2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
39 #include <netinet/in.h>
40 #include <arpa/nameser.h>
45 #include "dns_private.h"
46 #include "res_private.h"
48 #define INET_NTOP_AF_INET_OFFSET 4
49 #define INET_NTOP_AF_INET6_OFFSET 8
51 #define SEARCH_COUNT_INIT -1
53 #define DNS_RESOLVER_DIR "/etc/resolver"
55 #define NOTIFY_DIR_NAME "com.apple.system.dns.resolver.dir"
56 #define DNS_DELAY_NAME "com.apple.system.dns.delay"
58 #define DNS_DELAY_INTERVAL 4
60 #define DNS_PRIVATE_HANDLE_TYPE_SUPER 0
61 #define DNS_PRIVATE_HANDLE_TYPE_PLAIN 1
63 #define MDNS_MIN_TTL 2
65 extern uint32_t notify_monitor_file(int token
, const char *name
, int flags
);
67 extern void res_client_close(res_state res
);
68 extern res_state
res_state_new();
69 extern int res_nquery_soa_min(res_state statp
, const char *name
, int class, int type
, u_char
*answer
, int anslen
, struct sockaddr
*from
, int *fromlen
, int *min
);
70 extern int res_nsearch_2(res_state statp
, const char *name
, int class, int type
, u_char
*answer
, int anslen
, struct sockaddr
*from
, uint32_t *fromlen
);
71 extern int __res_nsearch_list_2(res_state statp
, const char *name
, int class, int type
, u_char
*answer
, int anslen
, struct sockaddr
*from
, uint32_t *fromlen
, int nsearch
, char **search
);
73 extern char *res_next_word(char **p
);
74 extern res_state
res_build_start(res_state res
);
75 extern int res_build(res_state res
, uint16_t port
, uint32_t *nsrch
, char *key
, char *val
);
76 extern int res_build_sortlist(res_state res
, struct in_addr addr
, struct in_addr mask
);
79 _pdns_set_name(pdns_handle_t
*pdns
, const char *name
)
83 if (pdns
== NULL
) return;
84 if (name
== NULL
) return;
86 /* only set the name once */
87 if (pdns
->name
!= NULL
) return;
89 /* strip trailing dots */
91 while ((n
>= 0) && (name
[n
] == '.')) n
--;
96 pdns
->name
= calloc(n
+ 1, sizeof(char));
97 if (pdns
->name
== NULL
) return;
98 memcpy(pdns
->name
, name
, n
);
101 static pdns_handle_t
*
102 _pdns_build_start(char *name
)
106 pdns
= (pdns_handle_t
*)calloc(1, sizeof(pdns_handle_t
));
107 if (pdns
== NULL
) return NULL
;
109 pdns
->res
= res_build_start(NULL
);
110 if (pdns
->res
== NULL
)
116 _pdns_set_name(pdns
, name
);
117 pdns
->port
= NS_DEFAULTPORT
;
123 _pdns_build_finish(pdns_handle_t
*pdns
)
127 if (pdns
== NULL
) return -1;
129 n
= pdns
->res
->nscount
;
132 if (pdns
->total_timeout
== 0)
134 if (pdns
->send_timeout
== 0) pdns
->total_timeout
= RES_MAXRETRANS
;
135 else pdns
->total_timeout
= pdns
->send_timeout
* pdns
->res
->retry
* n
;
138 if (pdns
->total_timeout
== 0) pdns
->res
->retrans
= RES_MAXRETRANS
;
139 else pdns
->res
->retrans
= pdns
->total_timeout
;
141 pdns
->res
->options
|= RES_INIT
;
147 _pdns_build_sortlist(pdns_handle_t
*pdns
, struct in_addr addr
, struct in_addr mask
)
149 if (pdns
== NULL
) return -1;
150 return res_build_sortlist(pdns
->res
, addr
, mask
);
154 _pdns_free(pdns_handle_t
*pdns
)
158 if (pdns
== NULL
) return;
160 if ((pdns
->search_count
!= SEARCH_COUNT_INIT
) && (pdns
->search_count
> 0) && (pdns
->search_list
!= NULL
))
162 for (i
= 0; i
< pdns
->search_count
; i
++) free(pdns
->search_list
[i
]);
163 free(pdns
->search_list
);
166 if (pdns
->name
!= NULL
) free(pdns
->name
);
167 if (pdns
->res
!= NULL
) res_client_close(pdns
->res
);
173 _pdns_build(pdns_handle_t
*pdns
, char *key
, char *val
)
175 struct in6_addr addr6
;
179 if (pdns
== NULL
) return -1;
182 * Detect IPv6 server addresses.
184 if (((pdns
->flags
& DNS_FLAG_HAVE_IPV6_SERVER
) == 0) && (!strcmp(key
, "nameserver")))
186 memset(&addr6
, 0, sizeof(struct in6_addr
));
187 status
= inet_pton(AF_INET6
, val
, &addr6
);
188 if (status
== 1) pdns
->flags
|= DNS_FLAG_HAVE_IPV6_SERVER
;
192 * We handle some keys here.
193 * Other keys get passed on to res_build.
195 if (!strcmp(key
, "default"))
197 pdns
->flags
|= DNS_FLAG_DEFAULT_RESOLVER
;
201 if (!strcmp(key
, "port"))
203 pdns
->port
= atoi(val
);
207 if (!strcmp(key
, "search"))
209 dupval
= strdup(val
);
210 if (dupval
== NULL
) return -1;
212 if (pdns
->search_count
== SEARCH_COUNT_INIT
) pdns
->search_count
= 0;
213 if (pdns
->search_count
== 0)
215 pdns
->search_list
= (char **)calloc(1, sizeof(char *));
219 pdns
->search_list
= (char **)reallocf(pdns
->search_list
, (pdns
->search_count
+ 1) * sizeof(char *));
222 if (pdns
->search_list
== NULL
)
229 pdns
->search_list
[pdns
->search_count
] = dupval
;
230 pdns
->search_count
++;
234 if (!strcmp(key
, "total_timeout"))
236 pdns
->total_timeout
= atoi(val
);
240 if (!strcmp(key
, "timeout"))
242 pdns
->send_timeout
= atoi(val
);
246 if (!strcmp(key
, "search_order"))
248 pdns
->search_order
= atoi(val
);
252 if (!strcmp(key
, "pdns"))
254 pdns
->flags
|= DNS_FLAG_FORWARD_TO_MDNSRESPONDER
;
258 if (!strcmp(key
, "mdns"))
260 pdns
->flags
|= DNS_FLAG_FORWARD_TO_MDNSRESPONDER
;
264 /* pass on to res_build */
265 return res_build(pdns
->res
, pdns
->port
, &(pdns
->search_count
), key
, val
);
268 static pdns_handle_t
*
269 _pdns_convert_sc(dns_resolver_t
*r
)
275 pdns
= _pdns_build_start(r
->domain
);
276 if (r
->domain
== NULL
) _pdns_build(pdns
, "default", NULL
);
278 p
= getenv("RES_RETRY_TIMEOUT");
279 if (p
!= NULL
) pdns
->send_timeout
= atoi(p
);
281 p
= getenv("RES_RETRY");
282 if (p
!= NULL
) pdns
->res
->retry
= atoi(p
);
287 asprintf(&val
, "%hu", r
->port
);
294 _pdns_build(pdns
, "port", val
);
298 if (r
->n_nameserver
> MAXNS
) r
->n_nameserver
= MAXNS
;
299 for (i
= 0; i
< r
->n_nameserver
; i
++)
301 if (r
->nameserver
[i
]->sa_family
== AF_INET
)
303 val
= calloc(1, 256);
310 inet_ntop(AF_INET
, (char *)(r
->nameserver
[i
]) + INET_NTOP_AF_INET_OFFSET
, val
, 256);
311 _pdns_build(pdns
, "nameserver", val
);
314 else if (r
->nameserver
[i
]->sa_family
== AF_INET6
)
316 pdns
->flags
|= DNS_FLAG_HAVE_IPV6_SERVER
;
317 val
= calloc(1, 256);
324 inet_ntop(AF_INET6
, (char *)(r
->nameserver
[i
]) + INET_NTOP_AF_INET6_OFFSET
, val
, 256);
325 _pdns_build(pdns
, "nameserver", val
);
330 if (r
->n_search
> MAXDNSRCH
) r
->n_search
= MAXDNSRCH
;
331 for (i
= 0; i
< r
->n_search
; i
++)
334 asprintf(&val
, "%s", r
->search
[i
]);
341 _pdns_build(pdns
, "search", val
);
348 asprintf(&val
, "%d", r
->timeout
);
355 _pdns_build(pdns
, "total_timeout", val
);
360 asprintf(&val
, "%d", r
->search_order
);
367 _pdns_build(pdns
, "search_order", val
);
370 if (r
->n_sortaddr
> MAXRESOLVSORT
) r
->n_sortaddr
= MAXRESOLVSORT
;
371 for (i
= 0; i
< r
->n_sortaddr
; i
++)
373 _pdns_build_sortlist(pdns
, r
->sortaddr
[i
]->address
, r
->sortaddr
[i
]->mask
);
377 while (NULL
!= (x
= res_next_word(&p
)))
379 /* search for and process individual options */
380 if (!strncmp(x
, "ndots:", 6))
382 _pdns_build(pdns
, "ndots", x
+6);
385 else if (!strncmp(x
, "nibble:", 7))
387 _pdns_build(pdns
, "nibble", x
+7);
390 else if (!strncmp(x
, "nibble2:", 8))
392 _pdns_build(pdns
, "nibble2", x
+8);
395 else if (!strncmp(x
, "timeout:", 8))
397 _pdns_build(pdns
, "timeout", x
+8);
400 else if (!strncmp(x
, "attempts:", 9))
402 _pdns_build(pdns
, "attempts", x
+9);
405 else if (!strncmp(x
, "bitstring:", 10))
407 _pdns_build(pdns
, "bitstring", x
+10);
410 else if (!strncmp(x
, "v6revmode:", 10))
412 _pdns_build(pdns
, "v6revmode", x
+10);
415 else if (!strcmp(x
, "debug"))
417 _pdns_build(pdns
, "debug", NULL
);
420 else if (!strcmp(x
, "no_tld_query"))
422 _pdns_build(pdns
, "no_tld_query", NULL
);
425 else if (!strcmp(x
, "inet6"))
427 _pdns_build(pdns
, "inet6", NULL
);
430 else if (!strcmp(x
, "rotate"))
432 _pdns_build(pdns
, "rotate", NULL
);
435 else if (!strcmp(x
, "no-check-names"))
437 _pdns_build(pdns
, "no-check-names", NULL
);
441 else if (!strcmp(x
, "edns0"))
443 _pdns_build(pdns
, "edns0", NULL
);
446 else if (!strcmp(x
, "a6"))
448 _pdns_build(pdns
, "a6", NULL
);
451 else if (!strcmp(x
, "dname"))
453 _pdns_build(pdns
, "dname", NULL
);
456 else if (!strcmp(x
, "default"))
458 _pdns_build(pdns
, "default", NULL
);
461 else if (!strcmp(x
, "pdns"))
463 _pdns_build(pdns
, "pdns", NULL
);
466 else if (!strcmp(x
, "mdns"))
468 _pdns_build(pdns
, "mdns", NULL
);
472 _pdns_build_finish(pdns
);
477 * Open a named resolver client from the system config data.
479 static pdns_handle_t
*
480 _pdns_sc_open(const char *name
)
484 dns_config_t
*sc_dns
;
485 dns_resolver_t
*sc_res
;
487 sc_dns
= dns_configuration_copy();
488 if (sc_dns
== NULL
) return NULL
;
494 if (sc_dns
->n_resolver
!= 0) sc_res
= sc_dns
->resolver
[0];
498 for (i
= 0; (sc_res
== NULL
) && (i
< sc_dns
->n_resolver
); i
++)
500 if (sc_dns
->resolver
[i
] == NULL
) continue;
501 if (sc_dns
->resolver
[i
]->domain
== NULL
) continue;
502 if (!strcasecmp(name
, sc_dns
->resolver
[i
]->domain
)) sc_res
= sc_dns
->resolver
[i
];
508 dns_configuration_free(sc_dns
);
512 pdns
= (pdns_handle_t
*)calloc(1, sizeof(pdns_handle_t
));
515 dns_configuration_free(sc_dns
);
519 pdns
= _pdns_convert_sc(sc_res
);
521 dns_configuration_free(sc_dns
);
523 if (pdns
== NULL
) return NULL
;
525 if (pdns
->res
== NULL
)
532 if (pdns
->res
->defdname
[0] != '\0') _pdns_set_name(pdns
, pdns
->res
->defdname
);
533 else if (name
!= NULL
) _pdns_set_name(pdns
, name
);
535 if (name
!= NULL
) pdns
->search_count
= SEARCH_COUNT_INIT
;
541 * Open a named resolver client from file.
543 static pdns_handle_t
*
544 _pdns_file_open(const char *name
)
547 char *path
, buf
[1024];
554 asprintf(&path
, "%s", _PATH_RESCONF
);
556 else if ((name
[0] == '.') || (name
[0] == '/'))
558 asprintf(&path
, "%s", name
);
562 asprintf(&path
, "%s/%s", DNS_RESOLVER_DIR
, name
);
565 if (path
== NULL
) return NULL
;
567 fp
= fopen(path
, "r");
569 if (fp
== NULL
) return NULL
;
571 pdns
= _pdns_build_start(NULL
);
578 p
= getenv("RES_RETRY_TIMEOUT");
579 if (p
!= NULL
) pdns
->send_timeout
= atoi(p
);
581 p
= getenv("RES_RETRY");
582 if (p
!= NULL
) pdns
->res
->retry
= atoi(p
);
584 while (fgets(buf
, sizeof(buf
), fp
) != NULL
)
587 if ((buf
[0] == ';') || (buf
[0] == '#')) continue;
589 x
= res_next_word(&p
);
590 if (x
== NULL
) continue;
591 if (!strcmp(x
, "sortlist"))
593 while (NULL
!= (x
= res_next_word(&p
)))
595 _pdns_build(pdns
, "sortlist", x
);
598 else if (!strcmp(x
, "timeout"))
600 x
= res_next_word(&p
);
601 if (x
!= NULL
) _pdns_build(pdns
, "total_timeout", x
);
603 else if (!strcmp(x
, "options"))
605 while (NULL
!= (x
= res_next_word(&p
)))
613 _pdns_build(pdns
, x
, y
);
618 y
= res_next_word(&p
);
619 _pdns_build(pdns
, x
, y
);
621 if ((!strcmp(x
, "domain")) && (pdns
->name
== NULL
)) _pdns_set_name(pdns
, y
);
627 if (pdns
->name
== NULL
) _pdns_set_name(pdns
, name
);
629 _pdns_build_finish(pdns
);
635 * If there was no search list, use domain name and parent domain components.
637 * N.B. This code deals with multiple trailing dots, but does not deal with
638 * multiple internal dots, e.g. "foo.....com".
641 _pdns_check_search_list(pdns_handle_t
*pdns
)
646 if (pdns
== NULL
) return;
647 if (pdns
->name
== NULL
) return;
648 if (pdns
->search_count
> 0) return;
652 for (p
= pdns
->name
; *p
!= '\0'; p
++)
657 /* Back up over any trailing dots and cut them out of the name */
658 for (p
--; (p
>= pdns
->name
) && (*p
== '.'); p
--)
664 /* This will be true if name was all dots */
665 if (p
< pdns
->name
) return;
667 /* dots are separators, so number of components is one larger */
670 _pdns_build(pdns
, "search", pdns
->name
);
672 /* Include parent domains with at least LOCALDOMAINPARTS components */
674 while (n
> LOCALDOMAINPARTS
)
676 /* Find next component */
677 while ((*p
!= '.') && (*p
!= '\0')) p
++;
678 if (*p
== '\0') break;
682 _pdns_build(pdns
, "search", p
);
686 __private_extern__
void
687 _check_cache(sdns_handle_t
*sdns
)
689 int i
, n
, status
, refresh
, sc_dns_count
;
693 dns_config_t
*sc_dns
;
695 if (sdns
== NULL
) return;
699 if (sdns
->stattime
== 0) refresh
= 1;
703 if (sdns
->notify_sys_config_token
== -1) refresh
= 1;
707 status
= notify_check(sdns
->notify_sys_config_token
, &n
);
708 if ((status
!= NOTIFY_STATUS_OK
) || (n
== 1)) refresh
= 1;
714 if (sdns
->notify_dir_token
== -1) refresh
= 1;
718 status
= notify_check(sdns
->notify_dir_token
, &n
);
719 if ((status
!= NOTIFY_STATUS_OK
) || (n
== 1)) refresh
= 1;
723 if (refresh
== 0) return;
725 /* Free old clients */
726 sdns
->pdns_primary
= NULL
;
728 for (i
= 0; i
< sdns
->client_count
; i
++)
730 _pdns_free(sdns
->client
[i
]);
733 sdns
->client_count
= 0;
734 if (sdns
->client
!= NULL
) free(sdns
->client
);
737 /* Fetch clients from System Configuration */
738 sc_dns
= dns_configuration_copy();
740 /* Set up Primary resolver. It's the one we consult for a search list */
742 if ((sc_dns
!= NULL
) && (sc_dns
->n_resolver
> 0))
744 sc_dns_count
= sc_dns
->n_resolver
;
745 sdns
->pdns_primary
= _pdns_convert_sc(sc_dns
->resolver
[0]);
746 _pdns_check_search_list(sdns
->pdns_primary
);
750 sdns
->pdns_primary
= _pdns_file_open(_PATH_RESCONF
);
753 if (sdns
->pdns_primary
!= NULL
)
755 if ((sdns
->flags
& DNS_FLAG_DEBUG
) && (sdns
->pdns_primary
->res
!= NULL
)) sdns
->pdns_primary
->res
->options
|= RES_DEBUG
;
756 if (sdns
->flags
& DNS_FLAG_OK_TO_SKIP_AAAA
) sdns
->pdns_primary
->flags
|= DNS_FLAG_OK_TO_SKIP_AAAA
;
757 sdns
->pdns_primary
->flags
|= DNS_FLAG_DEFAULT_RESOLVER
;
759 sdns
->client
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
760 if (sdns
->client
== NULL
)
762 if (sc_dns
!= NULL
) dns_configuration_free(sc_dns
);
766 sdns
->client
[sdns
->client_count
] = sdns
->pdns_primary
;
767 sdns
->client_count
++;
770 /* Convert System Configuration resolvers */
771 for (i
= 1; i
< sc_dns_count
; i
++)
773 c
= _pdns_convert_sc(sc_dns
->resolver
[i
]);
774 if (c
== NULL
) continue;
776 if (sdns
->flags
& DNS_FLAG_DEBUG
) c
->res
->options
|= RES_DEBUG
;
777 if (sdns
->flags
& DNS_FLAG_OK_TO_SKIP_AAAA
) c
->flags
|= DNS_FLAG_OK_TO_SKIP_AAAA
;
779 if (sdns
->client_count
== 0)
781 sdns
->client
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
785 sdns
->client
= (pdns_handle_t
**)reallocf(sdns
->client
, (sdns
->client_count
+ 1) * sizeof(pdns_handle_t
*));
788 if (sdns
->client
== NULL
)
790 sdns
->client_count
= 0;
791 dns_configuration_free(sc_dns
);
795 sdns
->client
[sdns
->client_count
] = c
;
796 sdns
->client_count
++;
799 if (sc_dns
!= NULL
) dns_configuration_free(sc_dns
);
801 if (sdns
->flags
& DNS_FLAG_CHECK_RESOLVER_DIR
)
803 /* Read /etc/resolvers clients */
804 dp
= opendir(DNS_RESOLVER_DIR
);
807 sdns
->flags
&= ~DNS_FLAG_CHECK_RESOLVER_DIR
;
811 while (NULL
!= (d
= readdir(dp
)))
813 if (d
->d_name
[0] == '.') continue;
815 c
= _pdns_file_open(d
->d_name
);
816 if (c
== NULL
) continue;
817 if (sdns
->flags
& DNS_FLAG_DEBUG
) c
->res
->options
|= RES_DEBUG
;
818 if (sdns
->flags
& DNS_FLAG_OK_TO_SKIP_AAAA
) c
->flags
|= DNS_FLAG_OK_TO_SKIP_AAAA
;
820 if (sdns
->client_count
== 0)
822 sdns
->client
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
826 sdns
->client
= (pdns_handle_t
**)reallocf(sdns
->client
, (sdns
->client_count
+ 1) * sizeof(pdns_handle_t
*));
829 if (sdns
->client
== NULL
)
831 sdns
->client_count
= 0;
835 sdns
->client
[sdns
->client_count
] = c
;
836 sdns
->client_count
++;
846 _pdns_get_default_handles(sdns_handle_t
*sdns
, pdns_handle_t
***pdns
)
850 if (sdns
== NULL
) return 0;
851 if (pdns
== NULL
) return 0;
855 for (i
= 0; i
< sdns
->client_count
; i
++)
857 if (sdns
->client
[i
]->flags
& DNS_FLAG_DEFAULT_RESOLVER
)
861 *pdns
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
865 *pdns
= (pdns_handle_t
**)reallocf((*pdns
), (count
+ 1) * sizeof(pdns_handle_t
*));
868 if (*pdns
== NULL
) return 0;
870 /* Insert sorted by search_order */
871 for (j
= 0; j
< count
; j
++)
873 if (sdns
->client
[i
]->search_order
< (*pdns
)[j
]->search_order
) break;
876 for (k
= count
; k
> j
; k
--) (*pdns
)[k
] = (*pdns
)[k
-1];
877 (*pdns
)[j
] = sdns
->client
[i
];
886 _pdns_get_handles_for_name(sdns_handle_t
*sdns
, const char *name
, pdns_handle_t
***pdns
)
891 if (sdns
== NULL
) return 0;
892 if (pdns
== NULL
) return 0;
894 if (name
== NULL
) return _pdns_get_default_handles(sdns
, pdns
);
895 else if (name
[0] == '\0') return _pdns_get_default_handles(sdns
, pdns
);
899 vname
= strdup(name
);
900 i
= strlen(vname
) - 1;
901 if ((i
>= 0) && (vname
[i
] == '.')) vname
[i
] = '\0';
906 for (i
= 0; i
< sdns
->client_count
; i
++)
908 if (sdns
->client
[i
]->name
== NULL
) continue;
910 if (!strcasecmp(sdns
->client
[i
]->name
, p
))
914 *pdns
= (pdns_handle_t
**)calloc(1, sizeof(pdns_handle_t
*));
918 *pdns
= (pdns_handle_t
**)reallocf((*pdns
), (count
+ 1) * sizeof(pdns_handle_t
*));
921 if (*pdns
== NULL
) return 0;
923 /* Insert sorted by search_order */
924 for (j
= 0; j
< count
; j
++)
926 if (sdns
->client
[i
]->search_order
< (*pdns
)[j
]->search_order
) break;
929 for (k
= count
; k
> j
; k
--) (*pdns
)[k
] = (*pdns
)[k
-1];
930 (*pdns
)[j
] = sdns
->client
[i
];
941 if (count
!= 0) return count
;
943 return _pdns_get_default_handles(sdns
, pdns
);;
947 _pdns_process_res_search_list(pdns_handle_t
*pdns
)
949 if (pdns
->search_count
!= SEARCH_COUNT_INIT
) return;
950 for (pdns
->search_count
= 0; (pdns
->res
->dnsrch
[pdns
->search_count
] != NULL
) && (pdns
->res
->dnsrch
[pdns
->search_count
][0] != '\0'); pdns
->search_count
++);
954 _pdns_search_list_domain(pdns_handle_t
*pdns
, uint32_t i
)
958 if (pdns
== NULL
) return NULL
;
959 if (pdns
->search_count
== SEARCH_COUNT_INIT
) _pdns_process_res_search_list(pdns
);
960 if (i
>= pdns
->search_count
) return NULL
;
962 s
= pdns
->search_list
[i
];
963 if (s
== NULL
) return NULL
;
968 _dns_open_notify(sdns_handle_t
*sdns
)
972 if (sdns
== NULL
) return;
974 if (sdns
->notify_delay_token
== -1)
976 status
= notify_register_check(DNS_DELAY_NAME
, &(sdns
->notify_delay_token
));
977 if (status
!= NOTIFY_STATUS_OK
) sdns
->notify_delay_token
= -1;
978 else status
= notify_check(sdns
->notify_delay_token
, &n
);
981 if (sdns
->notify_sys_config_token
== -1)
983 status
= notify_register_check(dns_configuration_notify_key(), &(sdns
->notify_sys_config_token
));
984 if (status
!= NOTIFY_STATUS_OK
) sdns
->notify_sys_config_token
= -1;
987 if (sdns
->notify_dir_token
== -1)
989 status
= notify_register_check(NOTIFY_DIR_NAME
, &(sdns
->notify_dir_token
));
990 if (status
== NOTIFY_STATUS_OK
)
992 status
= notify_monitor_file(sdns
->notify_dir_token
, "/private/etc/resolver", 0);
993 if (status
!= NOTIFY_STATUS_OK
)
995 notify_cancel(sdns
->notify_dir_token
);
996 sdns
->notify_dir_token
= -1;
1001 sdns
->notify_dir_token
= -1;
1007 _dns_close_notify(sdns_handle_t
*sdns
)
1009 if (sdns
== NULL
) return;
1011 if (sdns
->notify_delay_token
!= -1) notify_cancel(sdns
->notify_delay_token
);
1012 sdns
->notify_delay_token
= -1;
1014 if (sdns
->notify_sys_config_token
!= -1) notify_cancel(sdns
->notify_sys_config_token
);
1015 sdns
->notify_sys_config_token
= -1;
1017 if (sdns
->notify_dir_token
!= -1) notify_cancel(sdns
->notify_dir_token
);
1018 sdns
->notify_dir_token
= -1;
1022 dns_open(const char *name
)
1024 dns_private_handle_t
*dns
;
1026 dns
= (dns_private_handle_t
*)calloc(1, sizeof(dns_private_handle_t
));
1027 if (dns
== NULL
) return NULL
;
1031 dns
->handle_type
= DNS_PRIVATE_HANDLE_TYPE_SUPER
;
1032 dns
->sdns
= (sdns_handle_t
*)calloc(1, sizeof(sdns_handle_t
));
1033 if (dns
->sdns
== NULL
)
1039 dns
->sdns
->flags
|= DNS_FLAG_CHECK_RESOLVER_DIR
;
1040 dns
->sdns
->notify_sys_config_token
= -1;
1041 dns
->sdns
->notify_dir_token
= -1;
1042 dns
->sdns
->notify_delay_token
= -1;
1043 _dns_open_notify(dns
->sdns
);
1045 return (dns_handle_t
)dns
;
1048 dns
->handle_type
= DNS_PRIVATE_HANDLE_TYPE_PLAIN
;
1050 /* Look for name in System Configuration first */
1051 dns
->pdns
= _pdns_sc_open(name
);
1052 if (dns
->pdns
== NULL
) dns
->pdns
= _pdns_file_open(name
);
1054 if (dns
->pdns
== NULL
)
1060 return (dns_handle_t
)dns
;
1064 * Release a DNS client handle
1067 dns_free(dns_handle_t d
)
1069 dns_private_handle_t
*dns
;
1072 if (d
== NULL
) return;
1074 dns
= (dns_private_handle_t
*)d
;
1076 if (dns
->recvbuf
!= NULL
) free(dns
->recvbuf
);
1078 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1080 if (dns
->sdns
== NULL
) return;
1082 _dns_close_notify(dns
->sdns
);
1084 for (i
= 0; i
< dns
->sdns
->client_count
; i
++)
1086 _pdns_free(dns
->sdns
->client
[i
]);
1089 dns
->sdns
->client_count
= 0;
1090 if (dns
->sdns
->client
!= NULL
) free(dns
->sdns
->client
);
1096 _pdns_free(dns
->pdns
);
1103 _pdns_debug(pdns_handle_t
*pdns
, uint32_t flag
)
1105 if (pdns
== NULL
) return;
1109 pdns
->res
->options
&= ~RES_DEBUG
;
1113 pdns
->res
->options
|= RES_DEBUG
;
1118 _sdns_debug(sdns_handle_t
*sdns
, uint32_t flag
)
1122 if (sdns
== NULL
) return;
1126 sdns
->flags
&= ~ DNS_FLAG_DEBUG
;
1128 for (i
= 0; i
< sdns
->client_count
; i
++)
1130 sdns
->client
[i
]->res
->options
&= ~RES_DEBUG
;
1135 sdns
->flags
|= DNS_FLAG_DEBUG
;
1137 for (i
= 0; i
< sdns
->client_count
; i
++)
1139 sdns
->client
[i
]->res
->options
|= RES_DEBUG
;
1145 * Enable / Disable debugging
1148 dns_set_debug(dns_handle_t d
, uint32_t flag
)
1150 dns_private_handle_t
*dns
;
1152 if (d
== NULL
) return;
1154 dns
= (dns_private_handle_t
*)d
;
1156 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1158 _sdns_debug(dns
->sdns
, flag
);
1162 _pdns_debug(dns
->pdns
, flag
);
1167 * Returns the number of names in the search list
1170 dns_search_list_count(dns_handle_t d
)
1172 dns_private_handle_t
*dns
;
1173 pdns_handle_t
*pdns
;
1175 if (d
== NULL
) return 0;
1177 dns
= (dns_private_handle_t
*)d
;
1179 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1181 _check_cache(dns
->sdns
);
1182 pdns
= dns
->sdns
->pdns_primary
;
1189 if (pdns
->search_count
== SEARCH_COUNT_INIT
) _pdns_process_res_search_list(pdns
);
1190 return pdns
->search_count
;
1194 * Returns the domain name at index i in the search list.
1195 * Returns NULL if there are no names in the search list.
1196 * Caller must free the returned name.
1199 dns_search_list_domain(dns_handle_t d
, uint32_t i
)
1201 dns_private_handle_t
*dns
;
1202 pdns_handle_t
*pdns
;
1204 if (d
== NULL
) return NULL
;
1206 dns
= (dns_private_handle_t
*)d
;
1208 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1210 _check_cache(dns
->sdns
);
1211 pdns
= dns
->sdns
->pdns_primary
;
1218 return _pdns_search_list_domain(pdns
, i
);
1222 _pdns_delay(sdns_handle_t
*sdns
)
1224 int status
, n
, snooze
;
1227 if (sdns
== NULL
) return 0;
1232 /* No delay if we are not receiving notifications */
1233 if (sdns
->notify_delay_token
== -1) return 0;
1235 if (sdns
->dns_delay
== 0)
1237 status
= notify_check(sdns
->notify_delay_token
, &n
);
1238 if ((status
== NOTIFY_STATUS_OK
) && (n
== 1))
1241 * First thread to hit this condition sleeps for DNS_DELAY_INTERVAL seconds
1243 sdns
->dns_delay
= time(NULL
) + DNS_DELAY_INTERVAL
;
1244 snooze
= DNS_DELAY_INTERVAL
;
1251 * Subsequent threads sleep for the remaining duration.
1252 * We add one to round up the interval since our garnularity is coarse.
1254 snooze
= 1 + (sdns
->dns_delay
- tick
);
1255 if (snooze
< 0) snooze
= 0;
1258 if (snooze
== 0) return 0;
1262 /* When exiting, first thread in resets the delay condition */
1263 if (n
== 1) sdns
->dns_delay
= 0;
1269 _pdns_query(sdns_handle_t
*sdns
, pdns_handle_t
*pdns
, const char *name
, uint32_t class, uint32_t type
, char *buf
, uint32_t len
, struct sockaddr
*from
, uint32_t *fromlen
, int *min
)
1273 if (name
== NULL
) return -1;
1274 if (pdns
== NULL
) return -1;
1276 if (pdns
->flags
& DNS_FLAG_FORWARD_TO_MDNSRESPONDER
)
1278 n
= res_query_mDNSResponder(pdns
->res
, name
, class, type
, (u_char
*)buf
, len
, from
, fromlen
);
1279 if ((n
< 0) && (min
!= NULL
)) *min
= MDNS_MIN_TTL
;
1283 if (pdns
->res
== NULL
) return -1;
1284 if (pdns
->res
->nscount
== 0) return -1;
1286 if ((type
== ns_t_aaaa
) && ((pdns
->flags
& DNS_FLAG_HAVE_IPV6_SERVER
) == 0) && (pdns
->flags
& DNS_FLAG_OK_TO_SKIP_AAAA
)) return -1;
1291 return res_nquery_soa_min(pdns
->res
, name
, class, type
, (u_char
*)buf
, len
, from
, (int32_t *)fromlen
, min
);
1294 __private_extern__
int
1295 _pdns_search(sdns_handle_t
*sdns
, pdns_handle_t
*pdns
, const char *name
, uint32_t class, uint32_t type
, char *buf
, uint32_t len
, struct sockaddr
*from
, uint32_t *fromlen
)
1300 if (name
== NULL
) return -1;
1301 if (pdns
== NULL
) return -1;
1302 if (pdns
->res
== NULL
) return -1;
1303 if (pdns
->res
->nscount
== 0) return -1;
1305 if ((type
== ns_t_aaaa
) && ((pdns
->flags
& DNS_FLAG_HAVE_IPV6_SERVER
) == 0) && (pdns
->flags
& DNS_FLAG_OK_TO_SKIP_AAAA
)) return -1;
1311 * don't append my name if:
1313 * - input name is qualified (i.e. not single component)
1314 * - there is a search list
1315 * - there is a domain name
1318 if (pdns
->name
== NULL
) append
= 0;
1322 dot
= strrchr(name
, '.');
1323 if (dot
!= NULL
) append
= 0;
1328 if (pdns
->search_count
== SEARCH_COUNT_INIT
) _pdns_process_res_search_list(pdns
);
1329 if (pdns
->search_count
> 0) append
= 0;
1332 if ((append
== 1) && (pdns
->res
->defdname
!= NULL
) && (pdns
->res
->defdname
[0] != '\0')) append
= 0;
1340 status
= __res_nsearch_list_2(pdns
->res
, name
, class, type
, (u_char
*)buf
, len
, from
, fromlen
, pdns
->search_count
, pdns
->search_list
);
1347 asprintf(&qname
, "%s.%s.", name
, pdns
->name
);
1348 if (qname
== NULL
) return -1;
1351 status
= res_nsearch_2(pdns
->res
, qname
, class, type
, (u_char
*)buf
, len
, from
, fromlen
);
1359 _sdns_send(sdns_handle_t
*sdns
, const char *name
, uint32_t class, uint32_t type
, uint32_t fqdn
, char *buf
, uint32_t len
, struct sockaddr
*from
, uint32_t *fromlen
, int *min
)
1362 pdns_handle_t
**pdns
;
1363 uint32_t pdns_count
;
1370 pdns_count
= _pdns_get_handles_for_name(sdns
, name
, &pdns
);
1372 if (pdns_count
== 0) return -1;
1375 asprintf(&qname
, "%s%s", name
, (fqdn
== 0) ? "." : "");
1376 if (qname
== NULL
) return -1;
1378 for (i
= 0; i
< pdns_count
; i
++)
1381 n
= _pdns_query(sdns
, pdns
[i
], qname
, class, type
, buf
, len
, from
, fromlen
, &m
);
1384 if (*min
== -1) *min
= m
;
1385 else if ((m
>= 0) && (m
< *min
)) *min
= m
;
1396 __private_extern__
int
1397 _sdns_search(sdns_handle_t
*sdns
, const char *name
, uint32_t class, uint32_t type
, uint32_t fqdn
, uint32_t recurse
, char *buf
, uint32_t len
, struct sockaddr
*from
, uint32_t *fromlen
, int *min
)
1399 pdns_handle_t
*primary
, **pdns
;
1400 int i
, n
, ndots
, status
, m
;
1402 uint32_t pdns_count
;
1404 if (sdns
== NULL
) return -1;
1405 if (name
== NULL
) return -1;
1407 /* ndots is the threshold for trying a qualified name "as is" */
1409 primary
= sdns
->pdns_primary
;
1410 if ((primary
!= NULL
) && (primary
->res
!= NULL
)) ndots
= primary
->res
->ndots
;
1412 /* count dots in input name, and keep track of the location of the last dot */
1416 for (i
= 0; name
[i
] != '\0'; i
++)
1421 dot
= (char *)(name
+ i
);
1425 /* the last dot is the last character, name is fully qualified */
1426 if ((fqdn
== 0) && (dot
!= NULL
) && (*(dot
+ 1) == '\0')) fqdn
= 1;
1429 * If n >= ndots, or it's a FQDN, or if it's a PTR query,
1430 * we try a query with the name "as is".
1432 if ((n
>= ndots
) || (fqdn
== 1) || (type
== ns_t_ptr
))
1434 status
= _sdns_send(sdns
, name
, class, type
, fqdn
, buf
, len
, from
, fromlen
, min
);
1435 if (status
> 0) return status
;
1438 /* end of the line for FQDNs or PTR queries */
1439 if (fqdn
== 1) return -1;
1440 if (type
== ns_t_ptr
) return -1;
1442 if (recurse
== 0) return -1;
1443 if (primary
== NULL
) return -1;
1445 /* Try appending names from the search list */
1446 if (primary
->search_count
== SEARCH_COUNT_INIT
) _pdns_process_res_search_list(primary
);
1447 n
= primary
->search_count
;
1450 /* Try qualifying with each name in the search list */
1451 for (i
= 0; i
< n
; i
++)
1454 asprintf(&qname
, "%s.%s", name
, primary
->search_list
[i
]);
1455 if (qname
== NULL
) return -1;
1458 status
= _sdns_search(sdns
, qname
, class, type
, fqdn
, 0, buf
, len
, from
, fromlen
, &m
);
1460 if (*min
== -1) *min
= m
;
1461 else if ((m
>= 0) && (m
< *min
)) *min
= m
;
1465 if (status
> 0) return status
;
1472 * We get here if the name is not fully qualified (no trailing dot), and there is no search list.
1473 * Try each default client, qualifying with that client's name.
1476 pdns_count
= _pdns_get_default_handles(sdns
, &pdns
);
1479 if (pdns_count
== 0) return -1;
1481 for (i
= 0; i
< pdns_count
; i
++)
1484 if (pdns
[i
]->name
== NULL
) asprintf(&qname
, "%s", name
);
1485 else asprintf(&qname
, "%s.%s", name
, pdns
[i
]->name
);
1486 if (qname
== NULL
) return -1;
1489 status
= _pdns_query(sdns
, pdns
[i
], qname
, class, type
, buf
, len
, from
, fromlen
, min
);
1491 if (*min
== -1) *min
= m
;
1492 else if ((m
>= 0) && (m
< *min
)) *min
= m
;
1496 if (status
> 0) break;
1504 dns_query(dns_handle_t d
, const char *name
, uint32_t class, uint32_t type
, char *buf
, uint32_t len
, struct sockaddr
*from
, uint32_t *fromlen
)
1506 dns_private_handle_t
*dns
;
1509 if (d
== NULL
) return -1;
1510 if (name
== NULL
) return -1;
1511 dns
= (dns_private_handle_t
*)d
;
1516 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1518 _check_cache(dns
->sdns
);
1519 status
= _sdns_search(dns
->sdns
, name
, class, type
, 1, 1, buf
, len
, from
, fromlen
, &unused
);
1523 status
= _pdns_query(dns
->sdns
, dns
->pdns
, name
, class, type
, buf
, len
, from
, fromlen
, &unused
);
1531 dns_search(dns_handle_t d
, const char *name
, uint32_t class, uint32_t type
, char *buf
, uint32_t len
, struct sockaddr
*from
, uint32_t *fromlen
)
1533 dns_private_handle_t
*dns
;
1536 if (d
== NULL
) return -1;
1537 if (name
== NULL
) return -1;
1538 dns
= (dns_private_handle_t
*)d
;
1543 if (dns
->handle_type
== DNS_PRIVATE_HANDLE_TYPE_SUPER
)
1545 _check_cache(dns
->sdns
);
1546 status
= _sdns_search(dns
->sdns
, name
, class, type
, 0, 1, buf
, len
, from
, fromlen
, &unused
);
1550 status
= _pdns_search(dns
->sdns
, dns
->pdns
, name
, class, type
, buf
, len
, from
, fromlen
);
1561 dns_server_list_count(dns_handle_t d
)
1563 dns_private_handle_t
*dns
;
1566 if (d
== NULL
) return 0;
1567 dns
= (dns_private_handle_t
*)d
;
1569 if (dns
->handle_type
!= DNS_PRIVATE_HANDLE_TYPE_PLAIN
) return 0;
1571 if (dns
->pdns
== NULL
) return 0;
1574 if (r
== NULL
) return 0;
1580 dns_server_list_address(dns_handle_t d
, uint32_t i
)
1582 dns_private_handle_t
*dns
;
1584 struct sockaddr_storage
*s
;
1585 struct sockaddr
*sa
;
1587 if (d
== NULL
) return NULL
;
1588 dns
= (dns_private_handle_t
*)d
;
1590 if (dns
->handle_type
!= DNS_PRIVATE_HANDLE_TYPE_PLAIN
) return NULL
;
1592 if (dns
->pdns
== NULL
) return NULL
;
1595 if (r
== NULL
) return NULL
;
1597 if (i
>= r
->nscount
) return NULL
;
1598 sa
= get_nsaddr(r
, i
);
1599 if (sa
== NULL
) return NULL
;
1601 s
= (struct sockaddr_storage
*)calloc(1, sizeof(struct sockaddr_storage
));
1602 if (s
== NULL
) return NULL
;
1604 memcpy(s
, sa
, sizeof(struct sockaddr_storage
));
1605 return (struct sockaddr
*)s
;