2 * Copyright (c) 1999-2007 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
38 #include <netinet/in.h>
39 #include <arpa/nameser.h>
44 #include "dns_private.h"
45 #include "res_private.h"
47 #define INET_NTOP_AF_INET_OFFSET 4
48 #define INET_NTOP_AF_INET6_OFFSET 8
50 #define SEARCH_COUNT_INIT -1
52 #define DNS_RESOLVER_DIR "/etc/resolver"
54 #define NOTIFY_DIR_NAME "com.apple.system.dns.resolver.dir"
55 #define DNS_DELAY_NAME "com.apple.system.dns.delay"
57 #define DNS_DELAY_INTERVAL 4
59 #define DNS_PRIVATE_HANDLE_TYPE_SUPER 0
60 #define DNS_PRIVATE_HANDLE_TYPE_PLAIN 1
62 #define MDNS_MIN_TTL 2
64 extern uint32_t notify_monitor_file(int token
, const char *name
, int flags
);
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
);
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
);
78 _pdns_set_name(pdns_handle_t
*pdns
, const char *name
)
82 if (pdns
== NULL
) return;
83 if (name
== NULL
) return;
85 /* only set the name once */
86 if (pdns
->name
!= NULL
) return;
88 /* strip trailing dots */
90 while ((n
>= 0) && (name
[n
] == '.')) n
--;
95 pdns
->name
= calloc(n
+ 1, sizeof(char));
96 if (pdns
->name
== NULL
) return;
97 memcpy(pdns
->name
, name
, n
);
100 static pdns_handle_t
*
101 _pdns_build_start(char *name
)
105 pdns
= (pdns_handle_t
*)calloc(1, sizeof(pdns_handle_t
));
106 if (pdns
== NULL
) return NULL
;
108 pdns
->res
= res_build_start(NULL
);
109 if (pdns
->res
== NULL
)
115 _pdns_set_name(pdns
, name
);
116 pdns
->port
= NS_DEFAULTPORT
;
122 _pdns_build_finish(pdns_handle_t
*pdns
)
126 if (pdns
== NULL
) return -1;
128 n
= pdns
->res
->nscount
;
131 if (pdns
->total_timeout
== 0)
133 if (pdns
->send_timeout
== 0) pdns
->total_timeout
= RES_MAXRETRANS
;
134 else pdns
->total_timeout
= pdns
->send_timeout
* pdns
->res
->retry
* n
;
137 if (pdns
->total_timeout
== 0) pdns
->res
->retrans
= RES_MAXRETRANS
;
138 else pdns
->res
->retrans
= pdns
->total_timeout
;
140 pdns
->res
->options
|= RES_INIT
;
146 _pdns_build_sortlist(pdns_handle_t
*pdns
, struct in_addr addr
, struct in_addr mask
)
148 if (pdns
== NULL
) return -1;
149 return res_build_sortlist(pdns
->res
, addr
, mask
);
153 _pdns_free(pdns_handle_t
*pdns
)
157 if (pdns
== NULL
) return;
159 if ((pdns
->search_count
!= SEARCH_COUNT_INIT
) && (pdns
->search_count
> 0) && (pdns
->search_list
!= NULL
))
161 for (i
= 0; i
< pdns
->search_count
; i
++) free(pdns
->search_list
[i
]);
162 free(pdns
->search_list
);
165 if (pdns
->name
!= NULL
) free(pdns
->name
);
166 if (pdns
->res
!= NULL
) res_client_close(pdns
->res
);
172 _pdns_build(pdns_handle_t
*pdns
, char *key
, char *val
)
174 struct in6_addr addr6
;
178 if (pdns
== NULL
) return -1;
181 * Detect IPv6 server addresses.
183 if (((pdns
->flags
& DNS_FLAG_HAVE_IPV6_SERVER
) == 0) && (!strcmp(key
, "nameserver")))
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
;
191 * We handle some keys here.
192 * Other keys get passed on to res_build.
194 if (!strcmp(key
, "default"))
196 pdns
->flags
|= DNS_FLAG_DEFAULT_RESOLVER
;
200 if (!strcmp(key
, "port"))
202 pdns
->port
= atoi(val
);
206 if (!strcmp(key
, "search"))
208 dupval
= strdup(val
);
209 if (dupval
== NULL
) return -1;
211 if (pdns
->search_count
== SEARCH_COUNT_INIT
) pdns
->search_count
= 0;
212 if (pdns
->search_count
== 0)
214 pdns
->search_list
= (char **)calloc(1, sizeof(char *));
218 pdns
->search_list
= (char **)reallocf(pdns
->search_list
, (pdns
->search_count
+ 1) * sizeof(char *));
221 if (pdns
->search_list
== NULL
)
228 pdns
->search_list
[pdns
->search_count
] = dupval
;
229 pdns
->search_count
++;
233 if (!strcmp(key
, "total_timeout"))
235 pdns
->total_timeout
= atoi(val
);
239 if (!strcmp(key
, "timeout"))
241 pdns
->send_timeout
= atoi(val
);
245 if (!strcmp(key
, "search_order"))
247 pdns
->search_order
= atoi(val
);
251 if (!strcmp(key
, "pdns"))
253 pdns
->flags
|= DNS_FLAG_FORWARD_TO_MDNSRESPONDER
;
257 if (!strcmp(key
, "mdns"))
259 pdns
->flags
|= DNS_FLAG_FORWARD_TO_MDNSRESPONDER
;
263 /* pass on to res_build */
264 return res_build(pdns
->res
, pdns
->port
, &(pdns
->search_count
), key
, val
);
267 static pdns_handle_t
*
268 _pdns_convert_sc(dns_resolver_t
*r
)
274 pdns
= _pdns_build_start(r
->domain
);
275 if (r
->domain
== NULL
) _pdns_build(pdns
, "default", NULL
);
277 p
= getenv("RES_RETRY_TIMEOUT");
278 if (p
!= NULL
) pdns
->send_timeout
= atoi(p
);
280 p
= getenv("RES_RETRY");
281 if (p
!= NULL
) pdns
->res
->retry
= atoi(p
);
286 asprintf(&val
, "%hu", r
->port
);
293 _pdns_build(pdns
, "port", val
);
297 if (r
->n_nameserver
> MAXNS
) r
->n_nameserver
= MAXNS
;
298 for (i
= 0; i
< r
->n_nameserver
; i
++)
300 if (r
->nameserver
[i
]->sa_family
== AF_INET
)
302 val
= calloc(1, 256);
309 inet_ntop(AF_INET
, (char *)(r
->nameserver
[i
]) + INET_NTOP_AF_INET_OFFSET
, val
, 256);
310 _pdns_build(pdns
, "nameserver", val
);
313 else if (r
->nameserver
[i
]->sa_family
== AF_INET6
)
315 pdns
->flags
|= DNS_FLAG_HAVE_IPV6_SERVER
;
316 val
= calloc(1, 256);
323 inet_ntop(AF_INET6
, (char *)(r
->nameserver
[i
]) + INET_NTOP_AF_INET6_OFFSET
, val
, 256);
324 _pdns_build(pdns
, "nameserver", val
);
329 if (r
->n_search
> MAXDNSRCH
) r
->n_search
= MAXDNSRCH
;
330 for (i
= 0; i
< r
->n_search
; i
++)
333 asprintf(&val
, "%s", r
->search
[i
]);
340 _pdns_build(pdns
, "search", val
);
347 asprintf(&val
, "%d", r
->timeout
);
354 _pdns_build(pdns
, "total_timeout", val
);
359 asprintf(&val
, "%d", r
->search_order
);
366 _pdns_build(pdns
, "search_order", val
);
369 if (r
->n_sortaddr
> MAXRESOLVSORT
) r
->n_sortaddr
= MAXRESOLVSORT
;
370 for (i
= 0; i
< r
->n_sortaddr
; i
++)
372 _pdns_build_sortlist(pdns
, r
->sortaddr
[i
]->address
, r
->sortaddr
[i
]->mask
);
376 while (NULL
!= (x
= res_next_word(&p
)))
378 /* search for and process individual options */
379 if (!strncmp(x
, "ndots:", 6))
381 _pdns_build(pdns
, "ndots", x
+6);
384 else if (!strncmp(x
, "nibble:", 7))
386 _pdns_build(pdns
, "nibble", x
+7);
389 else if (!strncmp(x
, "nibble2:", 8))
391 _pdns_build(pdns
, "nibble2", x
+8);
394 else if (!strncmp(x
, "timeout:", 8))
396 _pdns_build(pdns
, "timeout", x
+8);
399 else if (!strncmp(x
, "attempts:", 9))
401 _pdns_build(pdns
, "attempts", x
+9);
404 else if (!strncmp(x
, "bitstring:", 10))
406 _pdns_build(pdns
, "bitstring", x
+10);
409 else if (!strncmp(x
, "v6revmode:", 10))
411 _pdns_build(pdns
, "v6revmode", x
+10);
414 else if (!strcmp(x
, "debug"))
416 _pdns_build(pdns
, "debug", NULL
);
419 else if (!strcmp(x
, "no_tld_query"))
421 _pdns_build(pdns
, "no_tld_query", NULL
);
424 else if (!strcmp(x
, "inet6"))
426 _pdns_build(pdns
, "inet6", NULL
);
429 else if (!strcmp(x
, "rotate"))
431 _pdns_build(pdns
, "rotate", NULL
);
434 else if (!strcmp(x
, "no-check-names"))
436 _pdns_build(pdns
, "no-check-names", NULL
);
440 else if (!strcmp(x
, "edns0"))
442 _pdns_build(pdns
, "edns0", NULL
);
445 else if (!strcmp(x
, "a6"))
447 _pdns_build(pdns
, "a6", NULL
);
450 else if (!strcmp(x
, "dname"))
452 _pdns_build(pdns
, "dname", NULL
);
455 else if (!strcmp(x
, "default"))
457 _pdns_build(pdns
, "default", NULL
);
460 else if (!strcmp(x
, "pdns"))
462 _pdns_build(pdns
, "pdns", NULL
);
465 else if (!strcmp(x
, "mdns"))
467 _pdns_build(pdns
, "mdns", NULL
);
471 _pdns_build_finish(pdns
);
476 * Open a named resolver client from the system config data.
478 static pdns_handle_t
*
479 _pdns_sc_open(const char *name
)
483 dns_config_t
*sc_dns
;
484 dns_resolver_t
*sc_res
;
486 sc_dns
= dns_configuration_copy();
487 if (sc_dns
== NULL
) return NULL
;
493 if (sc_dns
->n_resolver
!= 0) sc_res
= sc_dns
->resolver
[0];
497 for (i
= 0; (sc_res
== NULL
) && (i
< sc_dns
->n_resolver
); i
++)
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
];
507 dns_configuration_free(sc_dns
);
511 pdns
= (pdns_handle_t
*)calloc(1, sizeof(pdns_handle_t
));
514 dns_configuration_free(sc_dns
);
518 pdns
= _pdns_convert_sc(sc_res
);
520 dns_configuration_free(sc_dns
);
522 if (pdns
== NULL
) return NULL
;
524 if (pdns
->res
== 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
);
534 if (name
!= NULL
) pdns
->search_count
= SEARCH_COUNT_INIT
;
540 * Open a named resolver client from file.
542 static pdns_handle_t
*
543 _pdns_file_open(const char *name
)
546 char *path
, buf
[1024];
553 asprintf(&path
, "%s", _PATH_RESCONF
);
555 else if ((name
[0] == '.') || (name
[0] == '/'))
557 asprintf(&path
, "%s", name
);
561 asprintf(&path
, "%s/%s", DNS_RESOLVER_DIR
, name
);
564 if (path
== NULL
) return NULL
;
566 fp
= fopen(path
, "r");
568 if (fp
== NULL
) return NULL
;
570 pdns
= _pdns_build_start(NULL
);
577 p
= getenv("RES_RETRY_TIMEOUT");
578 if (p
!= NULL
) pdns
->send_timeout
= atoi(p
);
580 p
= getenv("RES_RETRY");
581 if (p
!= NULL
) pdns
->res
->retry
= atoi(p
);
583 while (fgets(buf
, sizeof(buf
), fp
) != NULL
)
586 if ((buf
[0] == ';') || (buf
[0] == '#')) continue;
588 x
= res_next_word(&p
);
589 if (x
== NULL
) continue;
590 if (!strcmp(x
, "sortlist"))
592 while (NULL
!= (x
= res_next_word(&p
)))
594 _pdns_build(pdns
, "sortlist", x
);
597 else if (!strcmp(x
, "timeout"))
599 x
= res_next_word(&p
);
600 if (x
!= NULL
) _pdns_build(pdns
, "total_timeout", x
);
602 else if (!strcmp(x
, "options"))
604 while (NULL
!= (x
= res_next_word(&p
)))
612 _pdns_build(pdns
, x
, y
);
617 y
= res_next_word(&p
);
618 _pdns_build(pdns
, x
, y
);
620 if ((!strcmp(x
, "domain")) && (pdns
->name
== NULL
)) _pdns_set_name(pdns
, y
);
626 if (pdns
->name
== NULL
) _pdns_set_name(pdns
, name
);
628 _pdns_build_finish(pdns
);
634 * If there was no search list, use domain name and parent domain components.
636 * N.B. This code deals with multiple trailing dots, but does not deal with
637 * multiple internal dots, e.g. "foo.....com".
640 _pdns_check_search_list(pdns_handle_t
*pdns
)
645 if (pdns
== NULL
) return;
646 if (pdns
->name
== NULL
) return;
647 if (pdns
->search_count
> 0) return;
651 for (p
= pdns
->name
; *p
!= '\0'; p
++)
656 /* Back up over any trailing dots and cut them out of the name */
657 for (p
--; (p
>= pdns
->name
) && (*p
== '.'); p
--)
663 /* This will be true if name was all dots */
664 if (p
< pdns
->name
) return;
666 /* dots are separators, so number of components is one larger */
669 _pdns_build(pdns
, "search", pdns
->name
);
671 /* Include parent domains with at least LOCALDOMAINPARTS components */
673 while (n
> LOCALDOMAINPARTS
)
675 /* Find next component */
676 while ((*p
!= '.') && (*p
!= '\0')) p
++;
677 if (*p
== '\0') break;
681 _pdns_build(pdns
, "search", p
);
685 __private_extern__
void
686 _check_cache(sdns_handle_t
*sdns
)
688 int i
, n
, status
, refresh
, sc_dns_count
;
692 dns_config_t
*sc_dns
;
694 if (sdns
== NULL
) return;
698 if (sdns
->stattime
== 0) refresh
= 1;
702 if (sdns
->notify_sys_config_token
== -1) refresh
= 1;
706 status
= notify_check(sdns
->notify_sys_config_token
, &n
);
707 if ((status
!= NOTIFY_STATUS_OK
) || (n
== 1)) refresh
= 1;
713 if (sdns
->notify_dir_token
== -1) refresh
= 1;
717 status
= notify_check(sdns
->notify_dir_token
, &n
);
718 if ((status
!= NOTIFY_STATUS_OK
) || (n
== 1)) refresh
= 1;
722 if (refresh
== 0) return;
724 /* Free old clients */
725 sdns
->pdns_primary
= NULL
;
727 for (i
= 0; i
< sdns
->client_count
; i
++)
729 _pdns_free(sdns
->client
[i
]);
732 sdns
->client_count
= 0;
733 if (sdns
->client
!= NULL
) free(sdns
->client
);
736 /* Fetch clients from System Configuration */
737 sc_dns
= dns_configuration_copy();
739 /* Set up Primary resolver. It's the one we consult for a search list */
741 if ((sc_dns
!= NULL
) && (sc_dns
->n_resolver
> 0))
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
);
749 sdns
->pdns_primary
= _pdns_file_open(_PATH_RESCONF
);
752 if (sdns
->pdns_primary
!= NULL
)
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
;
758 sdns
->client
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
759 if (sdns
->client
== NULL
)
761 if (sc_dns
!= NULL
) dns_configuration_free(sc_dns
);
765 sdns
->client
[sdns
->client_count
] = sdns
->pdns_primary
;
766 sdns
->client_count
++;
769 /* Convert System Configuration resolvers */
770 for (i
= 1; i
< sc_dns_count
; i
++)
772 c
= _pdns_convert_sc(sc_dns
->resolver
[i
]);
773 if (c
== NULL
) continue;
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
;
778 if (sdns
->client_count
== 0)
780 sdns
->client
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
784 sdns
->client
= (pdns_handle_t
**)reallocf(sdns
->client
, (sdns
->client_count
+ 1) * sizeof(pdns_handle_t
*));
787 if (sdns
->client
== NULL
)
789 sdns
->client_count
= 0;
790 dns_configuration_free(sc_dns
);
794 sdns
->client
[sdns
->client_count
] = c
;
795 sdns
->client_count
++;
798 if (sc_dns
!= NULL
) dns_configuration_free(sc_dns
);
800 if (sdns
->flags
& DNS_FLAG_CHECK_RESOLVER_DIR
)
802 /* Read /etc/resolvers clients */
803 dp
= opendir(DNS_RESOLVER_DIR
);
806 sdns
->flags
&= ~DNS_FLAG_CHECK_RESOLVER_DIR
;
810 while (NULL
!= (d
= readdir(dp
)))
812 if (d
->d_name
[0] == '.') continue;
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
;
819 if (sdns
->client_count
== 0)
821 sdns
->client
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
825 sdns
->client
= (pdns_handle_t
**)reallocf(sdns
->client
, (sdns
->client_count
+ 1) * sizeof(pdns_handle_t
*));
828 if (sdns
->client
== NULL
)
830 sdns
->client_count
= 0;
834 sdns
->client
[sdns
->client_count
] = c
;
835 sdns
->client_count
++;
845 _pdns_get_default_handles(sdns_handle_t
*sdns
, pdns_handle_t
***pdns
)
849 if (sdns
== NULL
) return 0;
850 if (pdns
== NULL
) return 0;
854 for (i
= 0; i
< sdns
->client_count
; i
++)
856 if (sdns
->client
[i
]->flags
& DNS_FLAG_DEFAULT_RESOLVER
)
860 *pdns
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
864 *pdns
= (pdns_handle_t
**)reallocf((*pdns
), (count
+ 1) * sizeof(pdns_handle_t
*));
867 if (*pdns
== NULL
) return 0;
869 /* Insert sorted by search_order */
870 for (j
= 0; j
< count
; j
++)
872 if (sdns
->client
[i
]->search_order
< (*pdns
)[j
]->search_order
) break;
875 for (k
= count
; k
> j
; k
--) (*pdns
)[k
] = (*pdns
)[k
-1];
876 (*pdns
)[j
] = sdns
->client
[i
];
885 _pdns_get_handles_for_name(sdns_handle_t
*sdns
, const char *name
, uint32_t nlabels
, pdns_handle_t
***pdns
)
890 if (sdns
== NULL
) return 0;
891 if (pdns
== NULL
) return 0;
893 if (name
== NULL
) return _pdns_get_default_handles(sdns
, pdns
);
894 else if (name
[0] == '\0') return _pdns_get_default_handles(sdns
, pdns
);
898 vname
= strdup(name
);
899 i
= strlen(vname
) - 1;
900 if ((i
>= 0) && (vname
[i
] == '.')) vname
[i
] = '\0';
905 for (i
= 0; i
< sdns
->client_count
; i
++)
907 if (sdns
->client
[i
]->name
== NULL
) continue;
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;
912 if (!strcasecmp(sdns
->client
[i
]->name
, p
))
916 *pdns
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
920 *pdns
= (pdns_handle_t
**)reallocf((*pdns
), (count
+ 1) * sizeof(pdns_handle_t
*));
923 if (*pdns
== NULL
) return 0;
925 /* Insert sorted by search_order */
926 for (j
= 0; j
< count
; j
++)
928 if (sdns
->client
[i
]->search_order
< (*pdns
)[j
]->search_order
) break;
931 for (k
= count
; k
> j
; k
--) (*pdns
)[k
] = (*pdns
)[k
-1];
932 (*pdns
)[j
] = sdns
->client
[i
];
943 if (count
!= 0) return count
;
945 return _pdns_get_default_handles(sdns
, pdns
);;
949 _pdns_process_res_search_list(pdns_handle_t
*pdns
)
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
++);
956 _pdns_search_list_domain(pdns_handle_t
*pdns
, uint32_t i
)
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
;
964 s
= pdns
->search_list
[i
];
965 if (s
== NULL
) return NULL
;
970 _dns_open_notify(sdns_handle_t
*sdns
)
974 if (sdns
== NULL
) return;
976 if (sdns
->notify_delay_token
== -1)
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
);
983 if (sdns
->notify_sys_config_token
== -1)
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;
989 if (sdns
->notify_dir_token
== -1)
991 status
= notify_register_check(NOTIFY_DIR_NAME
, &(sdns
->notify_dir_token
));
992 if (status
== NOTIFY_STATUS_OK
)
994 status
= notify_monitor_file(sdns
->notify_dir_token
, "/private/etc/resolver", 0);
995 if (status
!= NOTIFY_STATUS_OK
)
997 notify_cancel(sdns
->notify_dir_token
);
998 sdns
->notify_dir_token
= -1;
1003 sdns
->notify_dir_token
= -1;
1009 _dns_close_notify(sdns_handle_t
*sdns
)
1011 if (sdns
== NULL
) return;
1013 if (sdns
->notify_delay_token
!= -1) notify_cancel(sdns
->notify_delay_token
);
1014 sdns
->notify_delay_token
= -1;
1016 if (sdns
->notify_sys_config_token
!= -1) notify_cancel(sdns
->notify_sys_config_token
);
1017 sdns
->notify_sys_config_token
= -1;
1019 if (sdns
->notify_dir_token
!= -1) notify_cancel(sdns
->notify_dir_token
);
1020 sdns
->notify_dir_token
= -1;
1024 dns_open(const char *name
)
1026 dns_private_handle_t
*dns
;
1028 dns
= (dns_private_handle_t
*)calloc(1, sizeof(dns_private_handle_t
));
1029 if (dns
== NULL
) return NULL
;
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
)
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
);
1047 return (dns_handle_t
)dns
;
1050 dns
->handle_type
= DNS_PRIVATE_HANDLE_TYPE_PLAIN
;
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
);
1056 if (dns
->pdns
== NULL
)
1062 return (dns_handle_t
)dns
;
1066 * Release a DNS client handle
1069 dns_free(dns_handle_t d
)
1071 dns_private_handle_t
*dns
;
1074 if (d
== NULL
) return;
1076 dns
= (dns_private_handle_t
*)d
;
1078 if (dns
->recvbuf
!= NULL
) free(dns
->recvbuf
);
1080 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1082 if (dns
->sdns
== NULL
) return;
1084 _dns_close_notify(dns
->sdns
);
1086 for (i
= 0; i
< dns
->sdns
->client_count
; i
++)
1088 _pdns_free(dns
->sdns
->client
[i
]);
1091 dns
->sdns
->client_count
= 0;
1092 if (dns
->sdns
->client
!= NULL
) free(dns
->sdns
->client
);
1098 _pdns_free(dns
->pdns
);
1105 _pdns_debug(pdns_handle_t
*pdns
, uint32_t flag
)
1107 if (pdns
== NULL
) return;
1111 pdns
->res
->options
&= ~RES_DEBUG
;
1115 pdns
->res
->options
|= RES_DEBUG
;
1120 _sdns_debug(sdns_handle_t
*sdns
, uint32_t flag
)
1124 if (sdns
== NULL
) return;
1128 sdns
->flags
&= ~ DNS_FLAG_DEBUG
;
1130 for (i
= 0; i
< sdns
->client_count
; i
++)
1132 sdns
->client
[i
]->res
->options
&= ~RES_DEBUG
;
1137 sdns
->flags
|= DNS_FLAG_DEBUG
;
1139 for (i
= 0; i
< sdns
->client_count
; i
++)
1141 sdns
->client
[i
]->res
->options
|= RES_DEBUG
;
1147 * Enable / Disable debugging
1150 dns_set_debug(dns_handle_t d
, uint32_t flag
)
1152 dns_private_handle_t
*dns
;
1154 if (d
== NULL
) return;
1156 dns
= (dns_private_handle_t
*)d
;
1158 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1160 _sdns_debug(dns
->sdns
, flag
);
1164 _pdns_debug(dns
->pdns
, flag
);
1169 * Returns the number of names in the search list
1172 dns_search_list_count(dns_handle_t d
)
1174 dns_private_handle_t
*dns
;
1175 pdns_handle_t
*pdns
;
1177 if (d
== NULL
) return 0;
1179 dns
= (dns_private_handle_t
*)d
;
1181 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1183 _check_cache(dns
->sdns
);
1184 pdns
= dns
->sdns
->pdns_primary
;
1191 if (pdns
->search_count
== SEARCH_COUNT_INIT
) _pdns_process_res_search_list(pdns
);
1192 return pdns
->search_count
;
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.
1201 dns_search_list_domain(dns_handle_t d
, uint32_t i
)
1203 dns_private_handle_t
*dns
;
1204 pdns_handle_t
*pdns
;
1206 if (d
== NULL
) return NULL
;
1208 dns
= (dns_private_handle_t
*)d
;
1210 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1212 _check_cache(dns
->sdns
);
1213 pdns
= dns
->sdns
->pdns_primary
;
1220 return _pdns_search_list_domain(pdns
, i
);
1224 _pdns_delay(sdns_handle_t
*sdns
)
1226 int status
, n
, snooze
;
1229 if (sdns
== NULL
) return 0;
1234 /* No delay if we are not receiving notifications */
1235 if (sdns
->notify_delay_token
== -1) return 0;
1237 if (sdns
->dns_delay
== 0)
1239 status
= notify_check(sdns
->notify_delay_token
, &n
);
1240 if ((status
== NOTIFY_STATUS_OK
) && (n
== 1))
1243 * First thread to hit this condition sleeps for DNS_DELAY_INTERVAL seconds
1245 sdns
->dns_delay
= time(NULL
) + DNS_DELAY_INTERVAL
;
1246 snooze
= DNS_DELAY_INTERVAL
;
1253 * Subsequent threads sleep for the remaining duration.
1254 * We add one to round up the interval since our granularity is coarse.
1256 snooze
= 1 + (sdns
->dns_delay
- tick
);
1257 if (snooze
< 0) snooze
= 0;
1260 if (snooze
== 0) return 0;
1264 /* When exiting, first thread in resets the delay condition */
1265 if (n
== 1) sdns
->dns_delay
= 0;
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
)
1275 if (name
== NULL
) return -1;
1276 if (pdns
== NULL
) return -1;
1278 if (pdns
->flags
& DNS_FLAG_FORWARD_TO_MDNSRESPONDER
)
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
;
1285 if (pdns
->res
== NULL
) return -1;
1286 if (pdns
->res
->nscount
== 0) return -1;
1288 if ((type
== ns_t_aaaa
) && ((pdns
->flags
& DNS_FLAG_HAVE_IPV6_SERVER
) == 0) && (pdns
->flags
& DNS_FLAG_OK_TO_SKIP_AAAA
)) return -1;
1293 return res_nquery_soa_min(pdns
->res
, name
, class, type
, (u_char
*)buf
, len
, from
, (int32_t *)fromlen
, min
);
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
)
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;
1307 if ((type
== ns_t_aaaa
) && ((pdns
->flags
& DNS_FLAG_HAVE_IPV6_SERVER
) == 0) && (pdns
->flags
& DNS_FLAG_OK_TO_SKIP_AAAA
)) return -1;
1313 * don't append my name if:
1315 * - input name is qualified (i.e. not single component)
1316 * - there is a search list
1317 * - there is a domain name
1320 if (pdns
->name
== NULL
) append
= 0;
1324 dot
= strrchr(name
, '.');
1325 if (dot
!= NULL
) append
= 0;
1330 if (pdns
->search_count
== SEARCH_COUNT_INIT
) _pdns_process_res_search_list(pdns
);
1331 if (pdns
->search_count
> 0) append
= 0;
1334 if ((append
== 1) && (pdns
->res
->defdname
!= NULL
) && (pdns
->res
->defdname
[0] != '\0')) append
= 0;
1342 status
= __res_nsearch_list_2(pdns
->res
, name
, class, type
, (u_char
*)buf
, len
, from
, fromlen
, pdns
->search_count
, pdns
->search_list
);
1349 asprintf(&qname
, "%s.%s.", name
, pdns
->name
);
1350 if (qname
== NULL
) return -1;
1353 status
= res_nsearch_2(pdns
->res
, qname
, class, type
, (u_char
*)buf
, len
, from
, fromlen
);
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
)
1364 pdns_handle_t
**pdns
;
1365 uint32_t pdns_count
;
1367 int m
, tmin
, minstate
;
1376 pdns_count
= _pdns_get_handles_for_name(sdns
, name
, nlabels
, &pdns
);
1378 if (pdns_count
== 0) return -1;
1381 asprintf(&qname
, "%s%s", name
, (fqdn
== 0) ? "." : "");
1382 if (qname
== NULL
) return -1;
1384 for (i
= 0; i
< pdns_count
; i
++)
1387 n
= _pdns_query(sdns
, pdns
[i
], qname
, class, type
, buf
, len
, from
, fromlen
, &tmin
);
1394 else if (minstate
== 0)
1396 if (m
== -1) m
= tmin
;
1397 else if (tmin
< m
) m
= tmin
;
1404 if (minstate
== 0) *min
= m
;
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
)
1414 pdns_handle_t
*primary
, **pdns
;
1415 int i
, n
, ndots
, nlabels
, status
;
1416 int m
, tmin
, minstate
;
1418 uint32_t pdns_count
;
1420 if (sdns
== NULL
) return -1;
1421 if (name
== NULL
) return -1;
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.
1434 /* m is the lowest of all minima. -1 is unset */
1437 /* ndots is the threshold for trying a qualified name "as is" */
1439 primary
= sdns
->pdns_primary
;
1440 if ((primary
!= NULL
) && (primary
->res
!= NULL
)) ndots
= primary
->res
->ndots
;
1442 /* count dots in input name, and keep track of the location of the last dot */
1446 for (i
= 0; name
[i
] != '\0'; i
++)
1451 dot
= (char *)(name
+ i
);
1455 /* the last dot is the last character, name is fully qualified */
1456 if ((fqdn
== 0) && (dot
!= NULL
) && (*(dot
+ 1) == '\0')) fqdn
= 1;
1458 /* number of labels */
1459 nlabels
= n
+ 1 - fqdn
;
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".
1465 if ((n
>= ndots
) || (fqdn
== 1) || (type
== ns_t_ptr
))
1468 status
= _sdns_send(sdns
, name
, class, type
, fqdn
, buf
, len
, from
, fromlen
, nlabels
, &tmin
);
1469 if (status
> 0) return status
;
1471 if (tmin
< 0) minstate
= -1;
1475 /* end of the line for FQDNs or PTR queries */
1476 if ((fqdn
== 1) || (type
== ns_t_ptr
) || (recurse
== 0) || (primary
== NULL
))
1478 if (minstate
== 0) *min
= m
;
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
;
1487 /* Try qualifying with each name in the search list */
1488 for (i
= 0; i
< n
; i
++)
1491 asprintf(&qname
, "%s.%s", name
, primary
->search_list
[i
]);
1492 if (qname
== NULL
) return -1;
1495 status
= _sdns_search(sdns
, qname
, class, type
, fqdn
, 0, buf
, len
, from
, fromlen
, &tmin
);
1502 else if (minstate
== 0)
1504 if (m
== -1) m
= tmin
;
1505 else if (tmin
< m
) m
= tmin
;
1510 if (status
> 0) return status
;
1513 if (minstate
== 0) *min
= m
;
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.
1522 pdns_count
= _pdns_get_default_handles(sdns
, &pdns
);
1525 if (pdns_count
== 0)
1527 if (minstate
== 0) *min
= m
;
1531 for (i
= 0; i
< pdns_count
; i
++)
1534 if (pdns
[i
]->name
== NULL
) asprintf(&qname
, "%s", name
);
1535 else asprintf(&qname
, "%s.%s", name
, pdns
[i
]->name
);
1537 /* leave *min at -1 in case of a malloc failure */
1538 if (qname
== NULL
) return -1;
1541 status
= _pdns_query(sdns
, pdns
[i
], qname
, class, type
, buf
, len
, from
, fromlen
, &tmin
);
1548 else if (minstate
== 0)
1550 if (m
== -1) m
= tmin
;
1551 else if (tmin
< m
) m
= tmin
;
1556 if (status
> 0) break;
1561 if (minstate
== 0) *min
= m
;
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
)
1568 dns_private_handle_t
*dns
;
1571 if (d
== NULL
) return -1;
1572 if (name
== NULL
) return -1;
1573 dns
= (dns_private_handle_t
*)d
;
1578 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1580 _check_cache(dns
->sdns
);
1581 status
= _sdns_search(dns
->sdns
, name
, class, type
, 1, 1, buf
, len
, from
, fromlen
, &unused
);
1585 status
= _pdns_query(dns
->sdns
, dns
->pdns
, name
, class, type
, buf
, len
, from
, fromlen
, &unused
);
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
)
1595 dns_private_handle_t
*dns
;
1598 if (d
== NULL
) return -1;
1599 if (name
== NULL
) return -1;
1600 dns
= (dns_private_handle_t
*)d
;
1605 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1607 _check_cache(dns
->sdns
);
1608 status
= _sdns_search(dns
->sdns
, name
, class, type
, 0, 1, buf
, len
, from
, fromlen
, &unused
);
1612 status
= _pdns_search(dns
->sdns
, dns
->pdns
, name
, class, type
, buf
, len
, from
, fromlen
);
1623 dns_server_list_count(dns_handle_t d
)
1625 dns_private_handle_t
*dns
;
1628 if (d
== NULL
) return 0;
1629 dns
= (dns_private_handle_t
*)d
;
1631 if (dns
->handle_type
!= DNS_PRIVATE_HANDLE_TYPE_PLAIN
) return 0;
1633 if (dns
->pdns
== NULL
) return 0;
1636 if (r
== NULL
) return 0;
1642 dns_server_list_address(dns_handle_t d
, uint32_t i
)
1644 dns_private_handle_t
*dns
;
1646 struct sockaddr_storage
*s
;
1647 struct sockaddr
*sa
;
1649 if (d
== NULL
) return NULL
;
1650 dns
= (dns_private_handle_t
*)d
;
1652 if (dns
->handle_type
!= DNS_PRIVATE_HANDLE_TYPE_PLAIN
) return NULL
;
1654 if (dns
->pdns
== NULL
) return NULL
;
1657 if (r
== NULL
) return NULL
;
1659 if (i
>= r
->nscount
) return NULL
;
1660 sa
= get_nsaddr(r
, i
);
1661 if (sa
== NULL
) return NULL
;
1663 s
= (struct sockaddr_storage
*)calloc(1, sizeof(struct sockaddr_storage
));
1664 if (s
== NULL
) return NULL
;
1666 memcpy(s
, sa
, sizeof(struct sockaddr_storage
));
1667 return (struct sockaddr
*)s
;