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_DNS_CONTROL_NAME "com.apple.system.dns"
55 #define DNS_CONTROL_FLAG_DEBUG 0x0000000000000001LL
56 #define DNS_CONTROL_FLAG_NO_MDNS 0x0000000000000002LL
58 #define NOTIFY_DIR_NAME "com.apple.system.dns.resolver.dir"
59 #define DNS_DELAY_NAME "com.apple.system.dns.delay"
61 #define DNS_DELAY_INTERVAL 4
63 #define DNS_PRIVATE_HANDLE_TYPE_SUPER 0
64 #define DNS_PRIVATE_HANDLE_TYPE_PLAIN 1
66 #define MDNS_MIN_TTL 2
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
;
73 extern uint32_t notify_monitor_file(int token
, const char *name
, int flags
);
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
);
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
);
87 _pdns_set_name(pdns_handle_t
*pdns
, const char *name
)
91 if (pdns
== NULL
) return;
92 if (name
== NULL
) return;
94 /* only set the name once */
95 if (pdns
->name
!= NULL
) return;
97 /* strip trailing dots */
99 while ((n
>= 0) && (name
[n
] == '.')) n
--;
104 pdns
->name
= calloc(n
+ 1, sizeof(char));
105 if (pdns
->name
== NULL
) return;
106 memcpy(pdns
->name
, name
, n
);
109 static pdns_handle_t
*
110 _pdns_build_start(char *name
)
114 pdns
= (pdns_handle_t
*)calloc(1, sizeof(pdns_handle_t
));
115 if (pdns
== NULL
) return NULL
;
117 pdns
->res
= res_build_start(NULL
);
118 if (pdns
->res
== NULL
)
124 _pdns_set_name(pdns
, name
);
125 pdns
->port
= NS_DEFAULTPORT
;
131 _pdns_build_finish(pdns_handle_t
*pdns
)
135 if (pdns
== NULL
) return -1;
137 n
= pdns
->res
->nscount
;
140 if (pdns
->total_timeout
== 0)
142 if (pdns
->send_timeout
== 0) pdns
->total_timeout
= RES_MAXRETRANS
;
143 else pdns
->total_timeout
= pdns
->send_timeout
* pdns
->res
->retry
* n
;
146 if (pdns
->total_timeout
== 0) pdns
->res
->retrans
= RES_MAXRETRANS
;
147 else pdns
->res
->retrans
= pdns
->total_timeout
;
149 pdns
->res
->options
|= RES_INIT
;
155 _pdns_build_sortlist(pdns_handle_t
*pdns
, struct in_addr addr
, struct in_addr mask
)
157 if (pdns
== NULL
) return -1;
158 return res_build_sortlist(pdns
->res
, addr
, mask
);
162 _pdns_free(pdns_handle_t
*pdns
)
166 if (pdns
== NULL
) return;
168 if ((pdns
->search_count
!= SEARCH_COUNT_INIT
) && (pdns
->search_count
> 0) && (pdns
->search_list
!= NULL
))
170 for (i
= 0; i
< pdns
->search_count
; i
++) free(pdns
->search_list
[i
]);
171 free(pdns
->search_list
);
174 if (pdns
->name
!= NULL
) free(pdns
->name
);
175 if (pdns
->res
!= NULL
) res_client_close(pdns
->res
);
181 _pdns_build(pdns_handle_t
*pdns
, char *key
, char *val
)
183 struct in6_addr addr6
;
187 if (pdns
== NULL
) return -1;
190 * Detect IPv6 server addresses.
192 if (((pdns
->flags
& DNS_FLAG_HAVE_IPV6_SERVER
) == 0) && (!strcmp(key
, "nameserver")))
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
;
200 * We handle some keys here.
201 * Other keys get passed on to res_build.
203 if (!strcmp(key
, "default"))
205 pdns
->flags
|= DNS_FLAG_DEFAULT_RESOLVER
;
209 if (!strcmp(key
, "port"))
211 pdns
->port
= atoi(val
);
215 if (!strcmp(key
, "search"))
217 dupval
= strdup(val
);
218 if (dupval
== NULL
) return -1;
220 if (pdns
->search_count
== SEARCH_COUNT_INIT
) pdns
->search_count
= 0;
221 if (pdns
->search_count
== 0)
223 pdns
->search_list
= (char **)calloc(1, sizeof(char *));
227 pdns
->search_list
= (char **)reallocf(pdns
->search_list
, (pdns
->search_count
+ 1) * sizeof(char *));
230 if (pdns
->search_list
== NULL
)
237 pdns
->search_list
[pdns
->search_count
] = dupval
;
238 pdns
->search_count
++;
242 if (!strcmp(key
, "total_timeout"))
244 pdns
->total_timeout
= atoi(val
);
248 if (!strcmp(key
, "timeout"))
250 pdns
->send_timeout
= atoi(val
);
254 if (!strcmp(key
, "search_order"))
256 pdns
->search_order
= atoi(val
);
260 if (!strcmp(key
, "pdns"))
262 pdns
->flags
|= DNS_FLAG_FORWARD_TO_MDNSRESPONDER
;
266 if (!strcmp(key
, "mdns"))
268 pdns
->flags
|= DNS_FLAG_FORWARD_TO_MDNSRESPONDER
;
272 /* pass on to res_build */
273 return res_build(pdns
->res
, pdns
->port
, &(pdns
->search_count
), key
, val
);
276 static pdns_handle_t
*
277 _pdns_convert_sc(dns_resolver_t
*r
)
283 pdns
= _pdns_build_start(r
->domain
);
284 if (r
->domain
== NULL
) _pdns_build(pdns
, "default", NULL
);
286 p
= getenv("RES_RETRY_TIMEOUT");
287 if (p
!= NULL
) pdns
->send_timeout
= atoi(p
);
289 p
= getenv("RES_RETRY");
290 if (p
!= NULL
) pdns
->res
->retry
= atoi(p
);
295 asprintf(&val
, "%hu", r
->port
);
302 _pdns_build(pdns
, "port", val
);
306 if (r
->n_nameserver
> MAXNS
) r
->n_nameserver
= MAXNS
;
307 for (i
= 0; i
< r
->n_nameserver
; i
++)
309 if (r
->nameserver
[i
]->sa_family
== AF_INET
)
311 val
= calloc(1, 256);
318 inet_ntop(AF_INET
, (char *)(r
->nameserver
[i
]) + INET_NTOP_AF_INET_OFFSET
, val
, 256);
319 _pdns_build(pdns
, "nameserver", val
);
322 else if (r
->nameserver
[i
]->sa_family
== AF_INET6
)
324 pdns
->flags
|= DNS_FLAG_HAVE_IPV6_SERVER
;
325 val
= calloc(1, 256);
332 inet_ntop(AF_INET6
, (char *)(r
->nameserver
[i
]) + INET_NTOP_AF_INET6_OFFSET
, val
, 256);
333 _pdns_build(pdns
, "nameserver", val
);
338 if (r
->n_search
> MAXDNSRCH
) r
->n_search
= MAXDNSRCH
;
339 for (i
= 0; i
< r
->n_search
; i
++)
342 asprintf(&val
, "%s", r
->search
[i
]);
349 _pdns_build(pdns
, "search", val
);
356 asprintf(&val
, "%d", r
->timeout
);
363 _pdns_build(pdns
, "total_timeout", val
);
368 asprintf(&val
, "%d", r
->search_order
);
375 _pdns_build(pdns
, "search_order", val
);
378 if (r
->n_sortaddr
> MAXRESOLVSORT
) r
->n_sortaddr
= MAXRESOLVSORT
;
379 for (i
= 0; i
< r
->n_sortaddr
; i
++)
381 _pdns_build_sortlist(pdns
, r
->sortaddr
[i
]->address
, r
->sortaddr
[i
]->mask
);
385 while (NULL
!= (x
= res_next_word(&p
)))
387 /* search for and process individual options */
388 if (!strncmp(x
, "ndots:", 6))
390 _pdns_build(pdns
, "ndots", x
+6);
393 else if (!strncmp(x
, "nibble:", 7))
395 _pdns_build(pdns
, "nibble", x
+7);
398 else if (!strncmp(x
, "nibble2:", 8))
400 _pdns_build(pdns
, "nibble2", x
+8);
403 else if (!strncmp(x
, "timeout:", 8))
405 _pdns_build(pdns
, "timeout", x
+8);
408 else if (!strncmp(x
, "attempts:", 9))
410 _pdns_build(pdns
, "attempts", x
+9);
413 else if (!strncmp(x
, "bitstring:", 10))
415 _pdns_build(pdns
, "bitstring", x
+10);
418 else if (!strncmp(x
, "v6revmode:", 10))
420 _pdns_build(pdns
, "v6revmode", x
+10);
423 else if (!strcmp(x
, "debug"))
425 _pdns_build(pdns
, "debug", NULL
);
428 else if (!strcmp(x
, "no_tld_query"))
430 _pdns_build(pdns
, "no_tld_query", NULL
);
433 else if (!strcmp(x
, "inet6"))
435 _pdns_build(pdns
, "inet6", NULL
);
438 else if (!strcmp(x
, "rotate"))
440 _pdns_build(pdns
, "rotate", NULL
);
443 else if (!strcmp(x
, "no-check-names"))
445 _pdns_build(pdns
, "no-check-names", NULL
);
449 else if (!strcmp(x
, "edns0"))
451 _pdns_build(pdns
, "edns0", NULL
);
454 else if (!strcmp(x
, "a6"))
456 _pdns_build(pdns
, "a6", NULL
);
459 else if (!strcmp(x
, "dname"))
461 _pdns_build(pdns
, "dname", NULL
);
464 else if (!strcmp(x
, "default"))
466 _pdns_build(pdns
, "default", NULL
);
469 else if (!strcmp(x
, "pdns"))
471 _pdns_build(pdns
, "pdns", NULL
);
474 else if (!strcmp(x
, "mdns"))
476 _pdns_build(pdns
, "mdns", NULL
);
480 _pdns_build_finish(pdns
);
484 static pdns_handle_t
*
485 _mdns_primary(dns_resolver_t
*r
)
491 pdns
= _pdns_build_start(r
->domain
);
492 if (r
->domain
== NULL
) _pdns_build(pdns
, "default", NULL
);
494 p
= getenv("RES_RETRY_TIMEOUT");
495 if (p
!= NULL
) pdns
->send_timeout
= atoi(p
);
497 p
= getenv("RES_RETRY");
498 if (p
!= NULL
) pdns
->res
->retry
= atoi(p
);
500 if (r
->n_search
> MAXDNSRCH
) r
->n_search
= MAXDNSRCH
;
501 for (i
= 0; i
< r
->n_search
; i
++)
504 asprintf(&val
, "%s", r
->search
[i
]);
511 _pdns_build(pdns
, "search", val
);
515 _pdns_build(pdns
, "mdns", NULL
);
517 _pdns_build_finish(pdns
);
522 * Open a named resolver client from the system config data.
524 static pdns_handle_t
*
525 _pdns_sc_open(const char *name
)
529 dns_config_t
*sc_dns
;
530 dns_resolver_t
*sc_res
;
532 sc_dns
= dns_configuration_copy();
533 if (sc_dns
== NULL
) return NULL
;
539 if (sc_dns
->n_resolver
!= 0) sc_res
= sc_dns
->resolver
[0];
543 for (i
= 0; (sc_res
== NULL
) && (i
< sc_dns
->n_resolver
); i
++)
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
];
553 dns_configuration_free(sc_dns
);
557 pdns
= (pdns_handle_t
*)calloc(1, sizeof(pdns_handle_t
));
560 dns_configuration_free(sc_dns
);
564 pdns
= _pdns_convert_sc(sc_res
);
566 dns_configuration_free(sc_dns
);
568 if (pdns
== NULL
) return NULL
;
570 if (pdns
->res
== 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
);
580 if (name
!= NULL
) pdns
->search_count
= SEARCH_COUNT_INIT
;
586 * Open a named resolver client from file.
588 static pdns_handle_t
*
589 _pdns_file_open(const char *name
)
592 char *path
, buf
[1024];
599 asprintf(&path
, "%s", _PATH_RESCONF
);
601 else if ((name
[0] == '.') || (name
[0] == '/'))
603 asprintf(&path
, "%s", name
);
607 asprintf(&path
, "%s/%s", DNS_RESOLVER_DIR
, name
);
610 if (path
== NULL
) return NULL
;
612 fp
= fopen(path
, "r");
614 if (fp
== NULL
) return NULL
;
616 pdns
= _pdns_build_start(NULL
);
623 p
= getenv("RES_RETRY_TIMEOUT");
624 if (p
!= NULL
) pdns
->send_timeout
= atoi(p
);
626 p
= getenv("RES_RETRY");
627 if (p
!= NULL
) pdns
->res
->retry
= atoi(p
);
629 while (fgets(buf
, sizeof(buf
), fp
) != NULL
)
632 if ((buf
[0] == ';') || (buf
[0] == '#')) continue;
634 x
= res_next_word(&p
);
635 if (x
== NULL
) continue;
636 if (!strcmp(x
, "sortlist"))
638 while (NULL
!= (x
= res_next_word(&p
)))
640 _pdns_build(pdns
, "sortlist", x
);
643 else if (!strcmp(x
, "timeout"))
645 x
= res_next_word(&p
);
646 if (x
!= NULL
) _pdns_build(pdns
, "total_timeout", x
);
648 else if (!strcmp(x
, "options"))
650 while (NULL
!= (x
= res_next_word(&p
)))
658 _pdns_build(pdns
, x
, y
);
663 y
= res_next_word(&p
);
664 _pdns_build(pdns
, x
, y
);
666 if ((!strcmp(x
, "domain")) && (pdns
->name
== NULL
)) _pdns_set_name(pdns
, y
);
672 if (pdns
->name
== NULL
) _pdns_set_name(pdns
, name
);
674 _pdns_build_finish(pdns
);
680 * If there was no search list, use domain name and parent domain components.
682 * N.B. This code deals with multiple trailing dots, but does not deal with
683 * multiple internal dots, e.g. "foo.....com".
686 _pdns_check_search_list(pdns_handle_t
*pdns
)
691 if (pdns
== NULL
) return;
692 if (pdns
->name
== NULL
) return;
693 if (pdns
->search_count
> 0) return;
697 for (p
= pdns
->name
; *p
!= '\0'; p
++)
702 /* Back up over any trailing dots and cut them out of the name */
703 for (p
--; (p
>= pdns
->name
) && (*p
== '.'); p
--)
709 /* This will be true if name was all dots */
710 if (p
< pdns
->name
) return;
712 /* dots are separators, so number of components is one larger */
715 _pdns_build(pdns
, "search", pdns
->name
);
717 /* Include parent domains with at least LOCALDOMAINPARTS components */
719 while (n
> LOCALDOMAINPARTS
)
721 /* Find next component */
722 while ((*p
!= '.') && (*p
!= '\0')) p
++;
723 if (*p
== '\0') break;
727 _pdns_build(pdns
, "search", p
);
731 __attribute__((__visibility__("hidden"))) void
732 _check_cache(sdns_handle_t
*sdns
)
734 int i
, n
, status
, refresh
, sc_dns_count
;
738 dns_config_t
*sc_dns
;
740 if (sdns
== NULL
) return;
744 if (sdns
->stattime
== 0) refresh
= 1;
748 if (sdns
->notify_sys_config_token
== -1) refresh
= 1;
752 status
= notify_check(sdns
->notify_sys_config_token
, &n
);
753 if ((status
!= NOTIFY_STATUS_OK
) || (n
== 1)) refresh
= 1;
759 if (sdns
->notify_dir_token
== -1) refresh
= 1;
763 status
= notify_check(sdns
->notify_dir_token
, &n
);
764 if ((status
!= NOTIFY_STATUS_OK
) || (n
== 1)) refresh
= 1;
768 if (refresh
== 0) return;
770 /* Free old clients */
771 sdns
->pdns_primary
= NULL
;
773 for (i
= 0; i
< sdns
->client_count
; i
++)
775 _pdns_free(sdns
->client
[i
]);
778 sdns
->client_count
= 0;
779 if (sdns
->client
!= NULL
) free(sdns
->client
);
782 /* Fetch clients from System Configuration */
783 sc_dns
= dns_configuration_copy();
785 /* Set up Primary resolver. It's the one we consult for a search list */
787 if ((sc_dns
!= NULL
) && (sc_dns
->n_resolver
> 0))
789 if (sdns
->flags
& DNS_FLAG_FORWARD_TO_MDNSRESPONDER
)
792 sdns
->pdns_primary
= _mdns_primary(sc_dns
->resolver
[0]);
796 sc_dns_count
= sc_dns
->n_resolver
;
797 sdns
->pdns_primary
= _pdns_convert_sc(sc_dns
->resolver
[0]);
800 _pdns_check_search_list(sdns
->pdns_primary
);
804 sdns
->pdns_primary
= _pdns_file_open(_PATH_RESCONF
);
807 if (sdns
->pdns_primary
!= NULL
)
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
;
813 sdns
->client
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
814 if (sdns
->client
== NULL
)
816 if (sc_dns
!= NULL
) dns_configuration_free(sc_dns
);
820 sdns
->client
[sdns
->client_count
] = sdns
->pdns_primary
;
821 sdns
->client_count
++;
824 /* Convert System Configuration resolvers */
825 for (i
= 1; i
< sc_dns_count
; i
++)
827 c
= _pdns_convert_sc(sc_dns
->resolver
[i
]);
828 if (c
== NULL
) continue;
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
;
833 if (sdns
->client_count
== 0)
835 sdns
->client
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
839 sdns
->client
= (pdns_handle_t
**)reallocf(sdns
->client
, (sdns
->client_count
+ 1) * sizeof(pdns_handle_t
*));
842 if (sdns
->client
== NULL
)
844 sdns
->client_count
= 0;
845 dns_configuration_free(sc_dns
);
849 sdns
->client
[sdns
->client_count
] = c
;
850 sdns
->client_count
++;
853 if (sc_dns
!= NULL
) dns_configuration_free(sc_dns
);
855 if (sdns
->flags
& DNS_FLAG_CHECK_RESOLVER_DIR
)
857 /* Read /etc/resolvers clients */
858 dp
= opendir(DNS_RESOLVER_DIR
);
861 sdns
->flags
&= ~DNS_FLAG_CHECK_RESOLVER_DIR
;
865 while (NULL
!= (d
= readdir(dp
)))
867 if (d
->d_name
[0] == '.') continue;
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
;
874 if (sdns
->client_count
== 0)
876 sdns
->client
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
880 sdns
->client
= (pdns_handle_t
**)reallocf(sdns
->client
, (sdns
->client_count
+ 1) * sizeof(pdns_handle_t
*));
883 if (sdns
->client
== NULL
)
885 sdns
->client_count
= 0;
889 sdns
->client
[sdns
->client_count
] = c
;
890 sdns
->client_count
++;
900 _pdns_get_default_handles(sdns_handle_t
*sdns
, pdns_handle_t
***pdns
)
904 if (sdns
== NULL
) return 0;
905 if (pdns
== NULL
) return 0;
909 for (i
= 0; i
< sdns
->client_count
; i
++)
911 if (sdns
->client
[i
]->flags
& DNS_FLAG_DEFAULT_RESOLVER
)
915 *pdns
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
919 *pdns
= (pdns_handle_t
**)reallocf((*pdns
), (count
+ 1) * sizeof(pdns_handle_t
*));
922 if (*pdns
== NULL
) return 0;
924 /* Insert sorted by search_order */
925 for (j
= 0; j
< count
; j
++)
927 if (sdns
->client
[i
]->search_order
< (*pdns
)[j
]->search_order
) break;
930 for (k
= count
; k
> j
; k
--) (*pdns
)[k
] = (*pdns
)[k
-1];
931 (*pdns
)[j
] = sdns
->client
[i
];
940 _pdns_get_handles_for_name(sdns_handle_t
*sdns
, const char *name
, pdns_handle_t
***pdns
)
945 if (sdns
== NULL
) return 0;
946 if (pdns
== NULL
) return 0;
948 if (name
== NULL
) return _pdns_get_default_handles(sdns
, pdns
);
949 else if (name
[0] == '\0') return _pdns_get_default_handles(sdns
, pdns
);
953 vname
= strdup(name
);
954 i
= strlen(vname
) - 1;
955 if ((i
>= 0) && (vname
[i
] == '.')) vname
[i
] = '\0';
960 for (i
= 0; i
< sdns
->client_count
; i
++)
962 if (sdns
->client
[i
]->name
== NULL
) continue;
964 if (!strcasecmp(sdns
->client
[i
]->name
, p
))
968 *pdns
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
972 *pdns
= (pdns_handle_t
**)reallocf((*pdns
), (count
+ 1) * sizeof(pdns_handle_t
*));
975 if (*pdns
== NULL
) return 0;
977 /* Insert sorted by search_order */
978 for (j
= 0; j
< count
; j
++)
980 if (sdns
->client
[i
]->search_order
< (*pdns
)[j
]->search_order
) break;
983 for (k
= count
; k
> j
; k
--) (*pdns
)[k
] = (*pdns
)[k
-1];
984 (*pdns
)[j
] = sdns
->client
[i
];
995 if (count
!= 0) return count
;
997 return _pdns_get_default_handles(sdns
, pdns
);
1001 _pdns_process_res_search_list(pdns_handle_t
*pdns
)
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
++);
1008 _pdns_search_list_domain(pdns_handle_t
*pdns
, uint32_t i
)
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
;
1016 s
= pdns
->search_list
[i
];
1017 if (s
== NULL
) return NULL
;
1022 _dns_open_notify(sdns_handle_t
*sdns
)
1026 if (sdns
== NULL
) return;
1028 if (sdns
->notify_delay_token
== -1)
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
);
1035 if (sdns
->notify_sys_config_token
== -1)
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;
1041 if (sdns
->notify_dir_token
== -1)
1043 status
= notify_register_check(NOTIFY_DIR_NAME
, &(sdns
->notify_dir_token
));
1044 if (status
== NOTIFY_STATUS_OK
)
1046 status
= notify_monitor_file(sdns
->notify_dir_token
, "/private/etc/resolver", 0);
1047 if (status
!= NOTIFY_STATUS_OK
)
1049 notify_cancel(sdns
->notify_dir_token
);
1050 sdns
->notify_dir_token
= -1;
1055 sdns
->notify_dir_token
= -1;
1061 _dns_close_notify(sdns_handle_t
*sdns
)
1063 if (sdns
== NULL
) return;
1065 if (sdns
->notify_delay_token
!= -1) notify_cancel(sdns
->notify_delay_token
);
1066 sdns
->notify_delay_token
= -1;
1068 if (sdns
->notify_sys_config_token
!= -1) notify_cancel(sdns
->notify_sys_config_token
);
1069 sdns
->notify_sys_config_token
= -1;
1071 if (sdns
->notify_dir_token
!= -1) notify_cancel(sdns
->notify_dir_token
);
1072 sdns
->notify_dir_token
= -1;
1076 dns_open(const char *name
)
1078 dns_private_handle_t
*dns
;
1080 int check
, status
, local_control
;
1083 dns
= (dns_private_handle_t
*)calloc(1, sizeof(dns_private_handle_t
));
1084 if (dns
== NULL
) return NULL
;
1086 /* set up control notification if necessary */
1087 if (dns_control_token
== -1)
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
);
1094 /* check for dns flags */
1095 if (dns_control_token
!= -1)
1097 pthread_mutex_lock(&dns_control_lock
);
1098 status
= notify_check(dns_control_token
, &check
);
1099 if ((status
== 0) && (check
== 1))
1101 /* notification was triggered */
1102 status
= notify_get_state(dns_control_token
, &control
);
1105 if (control
& DNS_CONTROL_FLAG_NO_MDNS
) dns_control_mdns
= 0;
1106 if (control
& DNS_CONTROL_FLAG_DEBUG
) dns_control_debug
= 1;
1110 pthread_mutex_unlock(&dns_control_lock
);
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;
1117 if ((name
== NULL
) && (local_control
== 0))
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
)
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
);
1133 memset(&sb
, 0, sizeof(struct stat
));
1134 dns_set_debug((dns_handle_t
)dns
, dns_control_debug
);
1136 return (dns_handle_t
)dns
;
1139 if (local_control
!= 0)
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
)
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
);
1155 memset(&sb
, 0, sizeof(struct stat
));
1156 dns_set_debug((dns_handle_t
)dns
, dns_control_debug
);
1158 return (dns_handle_t
)dns
;
1161 dns
->handle_type
= DNS_PRIVATE_HANDLE_TYPE_PLAIN
;
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
);
1167 if (dns
->pdns
== NULL
)
1173 dns_set_debug((dns_handle_t
)dns
, dns_control_debug
);
1174 return (dns_handle_t
)dns
;
1178 * Release a DNS client handle
1181 dns_free(dns_handle_t d
)
1183 dns_private_handle_t
*dns
;
1186 if (d
== NULL
) return;
1188 dns
= (dns_private_handle_t
*)d
;
1190 if (dns
->recvbuf
!= NULL
) free(dns
->recvbuf
);
1192 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1194 if (dns
->sdns
== NULL
) return;
1196 _dns_close_notify(dns
->sdns
);
1198 for (i
= 0; i
< dns
->sdns
->client_count
; i
++)
1200 _pdns_free(dns
->sdns
->client
[i
]);
1203 dns
->sdns
->client_count
= 0;
1204 if (dns
->sdns
->client
!= NULL
) free(dns
->sdns
->client
);
1210 _pdns_free(dns
->pdns
);
1217 _pdns_debug(pdns_handle_t
*pdns
, uint32_t flag
)
1219 if (pdns
== NULL
) return;
1223 pdns
->res
->options
&= ~RES_DEBUG
;
1227 pdns
->res
->options
|= RES_DEBUG
;
1232 _sdns_debug(sdns_handle_t
*sdns
, uint32_t flag
)
1236 if (sdns
== NULL
) return;
1240 sdns
->flags
&= ~ DNS_FLAG_DEBUG
;
1242 for (i
= 0; i
< sdns
->client_count
; i
++)
1244 sdns
->client
[i
]->res
->options
&= ~RES_DEBUG
;
1249 sdns
->flags
|= DNS_FLAG_DEBUG
;
1251 for (i
= 0; i
< sdns
->client_count
; i
++)
1253 sdns
->client
[i
]->res
->options
|= RES_DEBUG
;
1259 * Enable / Disable debugging
1262 dns_set_debug(dns_handle_t d
, uint32_t flag
)
1264 dns_private_handle_t
*dns
;
1266 if (d
== NULL
) return;
1268 dns
= (dns_private_handle_t
*)d
;
1270 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1272 _sdns_debug(dns
->sdns
, flag
);
1276 _pdns_debug(dns
->pdns
, flag
);
1281 * Returns the number of names in the search list
1284 dns_search_list_count(dns_handle_t d
)
1286 dns_private_handle_t
*dns
;
1287 pdns_handle_t
*pdns
;
1289 if (d
== NULL
) return 0;
1291 dns
= (dns_private_handle_t
*)d
;
1293 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1295 _check_cache(dns
->sdns
);
1296 pdns
= dns
->sdns
->pdns_primary
;
1303 if (pdns
->search_count
== SEARCH_COUNT_INIT
) _pdns_process_res_search_list(pdns
);
1304 return pdns
->search_count
;
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.
1313 dns_search_list_domain(dns_handle_t d
, uint32_t i
)
1315 dns_private_handle_t
*dns
;
1316 pdns_handle_t
*pdns
;
1318 if (d
== NULL
) return NULL
;
1320 dns
= (dns_private_handle_t
*)d
;
1322 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1324 _check_cache(dns
->sdns
);
1325 pdns
= dns
->sdns
->pdns_primary
;
1332 return _pdns_search_list_domain(pdns
, i
);
1336 _pdns_delay(sdns_handle_t
*sdns
)
1338 int status
, n
, snooze
;
1341 if (sdns
== NULL
) return 0;
1346 /* No delay if we are not receiving notifications */
1347 if (sdns
->notify_delay_token
== -1) return 0;
1349 if (sdns
->dns_delay
== 0)
1351 status
= notify_check(sdns
->notify_delay_token
, &n
);
1352 if ((status
== NOTIFY_STATUS_OK
) && (n
== 1))
1355 * First thread to hit this condition sleeps for DNS_DELAY_INTERVAL seconds
1357 sdns
->dns_delay
= time(NULL
) + DNS_DELAY_INTERVAL
;
1358 snooze
= DNS_DELAY_INTERVAL
;
1365 * Subsequent threads sleep for the remaining duration.
1366 * We add one to round up the interval since our granularity is coarse.
1368 snooze
= 1 + (sdns
->dns_delay
- tick
);
1369 if (snooze
< 0) snooze
= 0;
1372 if (snooze
== 0) return 0;
1376 /* When exiting, first thread in resets the delay condition */
1377 if (n
== 1) sdns
->dns_delay
= 0;
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
)
1387 if (name
== NULL
) return -1;
1388 if (pdns
== NULL
) return -1;
1390 if (pdns
->flags
& DNS_FLAG_FORWARD_TO_MDNSRESPONDER
)
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
;
1397 if (pdns
->res
== NULL
) return -1;
1398 if (pdns
->res
->nscount
== 0) return -1;
1400 if ((type
== ns_t_aaaa
) && ((pdns
->flags
& DNS_FLAG_HAVE_IPV6_SERVER
) == 0) && (pdns
->flags
& DNS_FLAG_OK_TO_SKIP_AAAA
)) return -1;
1405 return res_nquery_soa_min(pdns
->res
, name
, class, type
, (u_char
*)buf
, len
, from
, (int32_t *)fromlen
, min
);
1408 __attribute__((__visibility__("hidden"))) 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
)
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;
1419 if ((type
== ns_t_aaaa
) && ((pdns
->flags
& DNS_FLAG_HAVE_IPV6_SERVER
) == 0) && (pdns
->flags
& DNS_FLAG_OK_TO_SKIP_AAAA
)) return -1;
1425 * don't append my name if:
1427 * - input name is qualified (i.e. not single component)
1428 * - there is a search list
1429 * - there is a domain name
1432 if (pdns
->name
== NULL
) append
= 0;
1436 dot
= strrchr(name
, '.');
1437 if (dot
!= NULL
) append
= 0;
1442 if (pdns
->search_count
== SEARCH_COUNT_INIT
) _pdns_process_res_search_list(pdns
);
1443 if (pdns
->search_count
> 0) append
= 0;
1446 if ((append
== 1) && (pdns
->res
->defdname
!= NULL
) && (pdns
->res
->defdname
[0] != '\0')) append
= 0;
1454 status
= __res_nsearch_list_2(pdns
->res
, name
, class, type
, (u_char
*)buf
, len
, from
, fromlen
, pdns
->search_count
, pdns
->search_list
);
1461 asprintf(&qname
, "%s.%s.", name
, pdns
->name
);
1462 if (qname
== NULL
) return -1;
1465 status
= res_nsearch_2(pdns
->res
, qname
, class, type
, (u_char
*)buf
, len
, from
, fromlen
);
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
)
1476 pdns_handle_t
**pdns
;
1477 uint32_t pdns_count
;
1479 int m
, tmin
, minstate
;
1488 pdns_count
= _pdns_get_handles_for_name(sdns
, name
, &pdns
);
1490 if (pdns_count
== 0) return -1;
1493 asprintf(&qname
, "%s%s", name
, (fqdn
== 0) ? "." : "");
1494 if (qname
== NULL
) return -1;
1496 for (i
= 0; i
< pdns_count
; i
++)
1499 n
= _pdns_query(sdns
, pdns
[i
], qname
, class, type
, buf
, len
, from
, fromlen
, &tmin
);
1506 else if (minstate
== 0)
1508 if (m
== -1) m
= tmin
;
1509 else if (tmin
< m
) m
= tmin
;
1516 if (minstate
== 0) *min
= m
;
1523 __attribute__((__visibility__("hidden"))) 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
)
1526 pdns_handle_t
*primary
, **pdns
;
1527 int i
, n
, ndots
, status
;
1528 int m
, tmin
, minstate
;
1530 uint32_t pdns_count
;
1532 if (sdns
== NULL
) return -1;
1533 if (name
== NULL
) return -1;
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.
1546 /* m is the lowest of all minima. -1 is unset */
1549 /* ndots is the threshold for trying a qualified name "as is" */
1551 primary
= sdns
->pdns_primary
;
1552 if ((primary
!= NULL
) && (primary
->res
!= NULL
)) ndots
= primary
->res
->ndots
;
1554 /* count dots in input name, and keep track of the location of the last dot */
1558 for (i
= 0; name
[i
] != '\0'; i
++)
1563 dot
= (char *)(name
+ i
);
1567 /* the last dot is the last character, name is fully qualified */
1568 if ((fqdn
== 0) && (dot
!= NULL
) && (*(dot
+ 1) == '\0')) fqdn
= 1;
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".
1574 if ((n
>= ndots
) || (fqdn
== 1) || (type
== ns_t_ptr
))
1577 status
= _sdns_send(sdns
, name
, class, type
, fqdn
, buf
, len
, from
, fromlen
, &tmin
);
1578 if (status
> 0) return status
;
1580 if (tmin
< 0) minstate
= -1;
1584 /* end of the line for FQDNs or PTR queries */
1585 if ((fqdn
== 1) || (type
== ns_t_ptr
) || (recurse
== 0) || (primary
== NULL
))
1587 if (minstate
== 0) *min
= m
;
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
;
1596 /* Try qualifying with each name in the search list */
1597 for (i
= 0; i
< n
; i
++)
1600 asprintf(&qname
, "%s.%s", name
, primary
->search_list
[i
]);
1601 if (qname
== NULL
) return -1;
1604 status
= _sdns_search(sdns
, qname
, class, type
, fqdn
, 0, buf
, len
, from
, fromlen
, &tmin
);
1611 else if (minstate
== 0)
1613 if (m
== -1) m
= tmin
;
1614 else if (tmin
< m
) m
= tmin
;
1619 if (status
> 0) return status
;
1622 if (minstate
== 0) *min
= m
;
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.
1631 pdns_count
= _pdns_get_default_handles(sdns
, &pdns
);
1634 if (pdns_count
== 0)
1636 if (minstate
== 0) *min
= m
;
1640 for (i
= 0; i
< pdns_count
; i
++)
1643 if (pdns
[i
]->name
== NULL
) asprintf(&qname
, "%s", name
);
1644 else asprintf(&qname
, "%s.%s", name
, pdns
[i
]->name
);
1646 /* leave *min at -1 in case of a malloc failure */
1647 if (qname
== NULL
) return -1;
1650 status
= _pdns_query(sdns
, pdns
[i
], qname
, class, type
, buf
, len
, from
, fromlen
, &tmin
);
1657 else if (minstate
== 0)
1659 if (m
== -1) m
= tmin
;
1660 else if (tmin
< m
) m
= tmin
;
1665 if (status
> 0) break;
1670 if (minstate
== 0) *min
= m
;
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
)
1677 dns_private_handle_t
*dns
;
1680 if (d
== NULL
) return -1;
1681 if (name
== NULL
) return -1;
1682 dns
= (dns_private_handle_t
*)d
;
1687 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1689 _check_cache(dns
->sdns
);
1690 status
= _sdns_search(dns
->sdns
, name
, class, type
, 1, 1, buf
, len
, from
, fromlen
, &unused
);
1694 status
= _pdns_query(dns
->sdns
, dns
->pdns
, name
, class, type
, buf
, len
, from
, fromlen
, &unused
);
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
)
1704 dns_private_handle_t
*dns
;
1707 if (d
== NULL
) return -1;
1708 if (name
== NULL
) return -1;
1709 dns
= (dns_private_handle_t
*)d
;
1714 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1716 _check_cache(dns
->sdns
);
1717 status
= _sdns_search(dns
->sdns
, name
, class, type
, 0, 1, buf
, len
, from
, fromlen
, &unused
);
1721 status
= _pdns_search(dns
->sdns
, dns
->pdns
, name
, class, type
, buf
, len
, from
, fromlen
);
1732 dns_server_list_count(dns_handle_t d
)
1734 dns_private_handle_t
*dns
;
1737 if (d
== NULL
) return 0;
1738 dns
= (dns_private_handle_t
*)d
;
1740 if (dns
->handle_type
!= DNS_PRIVATE_HANDLE_TYPE_PLAIN
) return 0;
1742 if (dns
->pdns
== NULL
) return 0;
1745 if (r
== NULL
) return 0;
1751 dns_server_list_address(dns_handle_t d
, uint32_t i
)
1753 dns_private_handle_t
*dns
;
1755 struct sockaddr_storage
*s
;
1756 struct sockaddr
*sa
;
1758 if (d
== NULL
) return NULL
;
1759 dns
= (dns_private_handle_t
*)d
;
1761 if (dns
->handle_type
!= DNS_PRIVATE_HANDLE_TYPE_PLAIN
) return NULL
;
1763 if (dns
->pdns
== NULL
) return NULL
;
1766 if (r
== NULL
) return NULL
;
1768 if (i
>= r
->nscount
) return NULL
;
1769 sa
= get_nsaddr(r
, i
);
1770 if (sa
== NULL
) return NULL
;
1772 s
= (struct sockaddr_storage
*)calloc(1, sizeof(struct sockaddr_storage
));
1773 if (s
== NULL
) return NULL
;
1775 memcpy(s
, sa
, sizeof(struct sockaddr_storage
));
1776 return (struct sockaddr
*)s
;