]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkReachability.c
configd-204.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkReachability.c
1 /*
2 * Copyright (c) 2003-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * March 31, 2004 Allan Nathanson <ajn@apple.com>
28 * - use [SC] DNS configuration information
29 *
30 * January 19, 2003 Allan Nathanson <ajn@apple.com>
31 * - add advanced reachability APIs
32 */
33
34 #include <SystemConfiguration/SystemConfiguration.h>
35 #include <SystemConfiguration/SCValidation.h>
36 #include <SystemConfiguration/SCPrivate.h>
37
38 #include <CoreFoundation/CFRuntime.h>
39 #include <pthread.h>
40 #include <libkern/OSAtomic.h>
41
42 #include <notify.h>
43 #include <dnsinfo.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 #include <netdb.h>
47 #include <netdb_async.h>
48 #include <resolv.h>
49 #include <unistd.h>
50 #include <sys/ioctl.h>
51 #include <sys/socket.h>
52 #include <net/if.h>
53 #include <net/if_dl.h>
54 #define KERNEL_PRIVATE
55 #include <net/route.h>
56 #undef KERNEL_PRIVATE
57
58 #ifndef s6_addr16
59 #define s6_addr16 __u6_addr.__u6_addr16
60 #endif
61
62 #include <ppp/ppp_msg.h>
63
64
65
66
67 #define kSCNetworkFlagsFirstResolvePending (1<<31)
68
69
70 #define N_QUICK 32
71
72
73 typedef enum {
74 reachabilityTypeAddress,
75 reachabilityTypeAddressPair,
76 reachabilityTypeName
77 } addressType;
78
79
80 static CFStringRef __SCNetworkReachabilityCopyDescription (CFTypeRef cf);
81 static void __SCNetworkReachabilityDeallocate (CFTypeRef cf);
82
83
84 typedef struct {
85
86 /* base CFType information */
87 CFRuntimeBase cfBase;
88
89 /* lock */
90 pthread_mutex_t lock;
91
92 /* address type */
93 addressType type;
94
95 /* target host name */
96 const char *name;
97 CFArrayRef resolvedAddress; /* CFArray[CFData] */
98 int resolvedAddressError;
99
100 /* local & remote addresses */
101 struct sockaddr *localAddress;
102 struct sockaddr *remoteAddress;
103
104 /* current reachability flags */
105 SCNetworkConnectionFlags flags;
106 uint16_t if_index;
107
108 /* run loop source, callout, context, rl scheduling info */
109 CFRunLoopSourceRef rls;
110 SCNetworkReachabilityCallBack rlsFunction;
111 SCNetworkReachabilityContext rlsContext;
112 CFMutableArrayRef rlList;
113
114 /* [async] DNS query info */
115 Boolean haveDNS;
116 CFMachPortRef dnsPort;
117 CFRunLoopSourceRef dnsRLS;
118 struct timeval dnsQueryStart;
119
120 } SCNetworkReachabilityPrivate, *SCNetworkReachabilityPrivateRef;
121
122
123 static CFTypeID __kSCNetworkReachabilityTypeID = _kCFRuntimeNotATypeID;
124
125
126 static const CFRuntimeClass __SCNetworkReachabilityClass = {
127 0, // version
128 "SCNetworkReachability", // className
129 NULL, // init
130 NULL, // copy
131 __SCNetworkReachabilityDeallocate, // dealloc
132 NULL, // equal
133 NULL, // hash
134 NULL, // copyFormattingDesc
135 __SCNetworkReachabilityCopyDescription // copyDebugDesc
136 };
137
138
139 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
140 static int rtm_seq = 0;
141
142
143 /*
144 * host "something has changed" notifications
145 */
146
147 static pthread_mutex_t hn_lock = PTHREAD_MUTEX_INITIALIZER;
148 static SCDynamicStoreRef hn_store = NULL;
149 static CFRunLoopSourceRef hn_storeRLS = NULL;
150 static CFMutableArrayRef hn_rlList = NULL;
151 static CFMutableSetRef hn_targets = NULL;
152
153
154 /*
155 * DNS configuration
156 */
157
158 typedef struct {
159 dns_config_t *config;
160 int refs;
161 } dns_configuration_t;
162
163
164 static pthread_mutex_t dns_lock = PTHREAD_MUTEX_INITIALIZER;
165 static dns_configuration_t *dns_configuration = NULL;
166 static int dns_token;
167 static Boolean dns_token_valid = FALSE;
168
169
170 static __inline__ CFTypeRef
171 isA_SCNetworkReachability(CFTypeRef obj)
172 {
173 return (isA_CFType(obj, SCNetworkReachabilityGetTypeID()));
174 }
175
176
177 static void
178 __log_query_time(Boolean found, Boolean async, struct timeval *start)
179 {
180 struct timeval dnsQueryComplete;
181 struct timeval dnsQueryElapsed;
182
183 if (!_sc_debug) {
184 return;
185 }
186
187 if (start->tv_sec == 0) {
188 return;
189 }
190
191 (void) gettimeofday(&dnsQueryComplete, NULL);
192 timersub(&dnsQueryComplete, start, &dnsQueryElapsed);
193 SCLog(TRUE, LOG_DEBUG,
194 CFSTR("%ssync DNS complete%s (query time = %d.%3.3d)"),
195 async ? "a" : "",
196 found ? "" : ", host not found",
197 dnsQueryElapsed.tv_sec,
198 dnsQueryElapsed.tv_usec / 1000);
199
200 return;
201 }
202
203
204 static int
205 updatePPPStatus(SCDynamicStoreRef *storeP,
206 const struct sockaddr *sa,
207 const char *if_name,
208 SCNetworkConnectionFlags *flags)
209 {
210 CFDictionaryRef dict = NULL;
211 CFStringRef entity;
212 CFIndex i;
213 const void * keys_q[N_QUICK];
214 const void ** keys = keys_q;
215 CFIndex n;
216 CFStringRef ppp_if;
217 int sc_status = kSCStatusReachabilityUnknown;
218 SCDynamicStoreRef store = (storeP != NULL) ? *storeP : NULL;
219 const void * values_q[N_QUICK];
220 const void ** values = values_q;
221
222 switch (sa->sa_family) {
223 case AF_INET :
224 entity = kSCEntNetIPv4;
225 break;
226 case AF_INET6 :
227 entity = kSCEntNetIPv6;
228 break;
229 default :
230 goto done;
231 }
232
233 if (store == NULL) {
234 store = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkReachability"), NULL, NULL);
235 if (store == NULL) {
236 SCLog(_sc_verbose, LOG_INFO, CFSTR("updatePPPStatus SCDynamicStoreCreate() failed"));
237 goto done;
238 }
239 }
240
241 /*
242 * grab a snapshot of the PPP configuration from the dynamic store
243 */
244 {
245 CFStringRef pattern;
246 CFMutableArrayRef patterns;
247
248 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
249 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
250 kSCDynamicStoreDomainState,
251 kSCCompAnyRegex,
252 entity);
253 CFArrayAppendValue(patterns, pattern);
254 CFRelease(pattern);
255 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
256 kSCDynamicStoreDomainSetup,
257 kSCCompAnyRegex,
258 kSCEntNetPPP);
259 CFArrayAppendValue(patterns, pattern);
260 CFRelease(pattern);
261 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
262 kSCDynamicStoreDomainState,
263 kSCCompAnyRegex,
264 kSCEntNetPPP);
265 CFArrayAppendValue(patterns, pattern);
266 CFRelease(pattern);
267 dict = SCDynamicStoreCopyMultiple(store, NULL, patterns);
268 CFRelease(patterns);
269 }
270 if (dict == NULL) {
271 /* if we could not access the dynamic store */
272 goto done;
273 }
274
275 sc_status = kSCStatusOK;
276
277 /*
278 * look for the service which matches the provided interface
279 */
280 n = CFDictionaryGetCount(dict);
281 if (n <= 0) {
282 goto done;
283 }
284
285 ppp_if = CFStringCreateWithCStringNoCopy(NULL,
286 if_name,
287 kCFStringEncodingASCII,
288 kCFAllocatorNull);
289
290 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
291 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
292 values = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
293 }
294 CFDictionaryGetKeysAndValues(dict, keys, values);
295
296 for (i=0; i < n; i++) {
297 CFArrayRef components;
298 CFStringRef key;
299 CFNumberRef num;
300 CFDictionaryRef p_setup;
301 CFDictionaryRef p_state;
302 int32_t ppp_status;
303 CFStringRef service = NULL;
304 CFStringRef s_key = (CFStringRef) keys[i];
305 CFDictionaryRef s_dict = (CFDictionaryRef)values[i];
306 CFStringRef s_if;
307
308 if (!isA_CFString(s_key) || !isA_CFDictionary(s_dict)) {
309 continue;
310 }
311
312 if (!CFStringHasSuffix(s_key, entity)) {
313 continue; // if not an IPv4 or IPv6 entity
314 }
315
316 s_if = CFDictionaryGetValue(s_dict, kSCPropInterfaceName);
317 if (!isA_CFString(s_if)) {
318 continue; // if no interface
319 }
320
321 if (!CFEqual(ppp_if, s_if)) {
322 continue; // if not this interface
323 }
324
325 /*
326 * extract service ID, get PPP "state" entity (for status), and get
327 * the "setup" entity (for dial-on-traffic flag)
328 */
329 components = CFStringCreateArrayBySeparatingStrings(NULL, s_key, CFSTR("/"));
330 if (CFArrayGetCount(components) != 5) {
331 CFRelease(components);
332 continue;
333 }
334 service = CFArrayGetValueAtIndex(components, 3);
335 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
336 kSCDynamicStoreDomainState,
337 service,
338 kSCEntNetPPP);
339 p_state = CFDictionaryGetValue(dict, key);
340 CFRelease(key);
341 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
342 kSCDynamicStoreDomainSetup,
343 service,
344 kSCEntNetPPP);
345 p_setup = CFDictionaryGetValue(dict, key);
346 CFRelease(key);
347 CFRelease(components);
348
349 // get PPP status
350 if (!isA_CFDictionary(p_state)) {
351 continue;
352 }
353 num = CFDictionaryGetValue(p_state, kSCPropNetPPPStatus);
354 if (!isA_CFNumber(num)) {
355 continue;
356 }
357
358 if (!CFNumberGetValue(num, kCFNumberSInt32Type, &ppp_status)) {
359 continue;
360 }
361 switch (ppp_status) {
362 case PPP_RUNNING :
363 /* if we're really UP and RUNNING */
364 break;
365 case PPP_ONHOLD :
366 /* if we're effectively UP and RUNNING */
367 break;
368 case PPP_IDLE :
369 case PPP_STATERESERVED :
370 /* if we're not connected at all */
371 SCLog(_sc_debug, LOG_INFO, CFSTR(" PPP link idle, dial-on-traffic to connect"));
372 *flags |= kSCNetworkFlagsConnectionRequired;
373 break;
374 default :
375 /* if we're in the process of [dis]connecting */
376 SCLog(_sc_debug, LOG_INFO, CFSTR(" PPP link, connection in progress"));
377 *flags |= kSCNetworkFlagsConnectionRequired;
378 break;
379 }
380
381 // check PPP dial-on-traffic status
382 if (isA_CFDictionary(p_setup)) {
383 num = CFDictionaryGetValue(p_setup, kSCPropNetPPPDialOnDemand);
384 if (isA_CFNumber(num)) {
385 int32_t ppp_demand;
386
387 if (CFNumberGetValue(num, kCFNumberSInt32Type, &ppp_demand)) {
388 if (ppp_demand) {
389 *flags |= kSCNetworkFlagsConnectionAutomatic;
390 if (ppp_status == PPP_IDLE) {
391 *flags |= kSCNetworkFlagsInterventionRequired;
392 }
393 }
394 }
395 }
396 }
397
398 break;
399 }
400
401 CFRelease(ppp_if);
402 if (keys != keys_q) {
403 CFAllocatorDeallocate(NULL, keys);
404 CFAllocatorDeallocate(NULL, values);
405 }
406
407 done :
408
409 if (dict != NULL) CFRelease(dict);
410 if (storeP != NULL) *storeP = store;
411 return sc_status;
412 }
413
414
415 static int
416 updatePPPAvailable(SCDynamicStoreRef *storeP,
417 const struct sockaddr *sa,
418 SCNetworkConnectionFlags *flags)
419 {
420 CFDictionaryRef dict = NULL;
421 CFStringRef entity;
422 CFIndex i;
423 const void * keys_q[N_QUICK];
424 const void ** keys = keys_q;
425 CFIndex n;
426 int sc_status = kSCStatusReachabilityUnknown;
427 SCDynamicStoreRef store = (storeP != NULL) ? *storeP : NULL;
428 const void * values_q[N_QUICK];
429 const void ** values = values_q;
430
431 if (sa == NULL) {
432 entity = kSCEntNetIPv4;
433 } else {
434 switch (sa->sa_family) {
435 case AF_INET :
436 entity = kSCEntNetIPv4;
437 break;
438 case AF_INET6 :
439 entity = kSCEntNetIPv6;
440 break;
441 default :
442 goto done;
443 }
444 }
445
446 if (store == NULL) {
447 store = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkReachability"), NULL, NULL);
448 if (store == NULL) {
449 SCLog(_sc_debug, LOG_INFO, CFSTR(" status = unknown (could not access SCDynamicStore"));
450 goto done;
451 }
452 }
453
454 /*
455 * grab a snapshot of the PPP configuration from the dynamic store
456 */
457 {
458 CFStringRef pattern;
459 CFMutableArrayRef patterns;
460
461 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
462 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
463 kSCDynamicStoreDomainSetup,
464 kSCCompAnyRegex,
465 entity);
466 CFArrayAppendValue(patterns, pattern);
467 CFRelease(pattern);
468 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
469 kSCDynamicStoreDomainSetup,
470 kSCCompAnyRegex,
471 kSCEntNetPPP);
472 CFArrayAppendValue(patterns, pattern);
473 CFRelease(pattern);
474 dict = SCDynamicStoreCopyMultiple(store, NULL, patterns);
475 CFRelease(patterns);
476 }
477 if (dict == NULL) {
478 /* if we could not access the dynamic store */
479 goto done;
480 }
481
482 sc_status = kSCStatusOK;
483
484 /*
485 * look for an available service which will provide connectivity
486 * for the requested address family.
487 */
488 n = CFDictionaryGetCount(dict);
489 if (n <= 0) {
490 goto done;
491 }
492
493 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
494 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
495 values = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
496 }
497 CFDictionaryGetKeysAndValues(dict, keys, values);
498
499 for (i = 0; i < n; i++) {
500 CFArrayRef components;
501 Boolean found = FALSE;
502 CFStringRef p_key;
503 CFDictionaryRef p_dict;
504 CFStringRef service;
505 CFStringRef s_key = (CFStringRef) keys[i];
506 CFDictionaryRef s_dict = (CFDictionaryRef)values[i];
507
508 if (!isA_CFString(s_key) || !isA_CFDictionary(s_dict)) {
509 continue;
510 }
511
512 if (!CFStringHasSuffix(s_key, entity)) {
513 continue; // if not an IPv4 or IPv6 entity
514 }
515
516 // extract service ID
517 components = CFStringCreateArrayBySeparatingStrings(NULL, s_key, CFSTR("/"));
518 if (CFArrayGetCount(components) != 5) {
519 CFRelease(components);
520 continue;
521 }
522 service = CFArrayGetValueAtIndex(components, 3);
523
524 // check for PPP entity
525 p_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
526 kSCDynamicStoreDomainSetup,
527 service,
528 kSCEntNetPPP);
529 p_dict = CFDictionaryGetValue(dict, p_key);
530 CFRelease(p_key);
531
532 if (isA_CFDictionary(p_dict)) {
533 CFNumberRef num;
534
535 /*
536 * we have a PPP service for this address family
537 */
538 found = TRUE;
539
540 *flags |= kSCNetworkFlagsReachable;
541 *flags |= kSCNetworkFlagsTransientConnection;
542 *flags |= kSCNetworkFlagsConnectionRequired;
543
544 /*
545 * get PPP dial-on-traffic status
546 */
547 num = CFDictionaryGetValue(p_dict, kSCPropNetPPPDialOnDemand);
548 if (isA_CFNumber(num)) {
549 int32_t ppp_demand;
550
551 if (CFNumberGetValue(num, kCFNumberSInt32Type, &ppp_demand)) {
552 if (ppp_demand) {
553 *flags |= kSCNetworkFlagsConnectionAutomatic;
554 }
555 }
556 }
557
558 if (_sc_debug) {
559 SCLog(TRUE, LOG_INFO, CFSTR(" status = isReachable (after connect)"));
560 SCLog(TRUE, LOG_INFO, CFSTR(" service = %@"), service);
561 }
562
563 }
564
565 CFRelease(components);
566
567 if (found) {
568 break;
569 }
570 }
571
572 if (keys != keys_q) {
573 CFAllocatorDeallocate(NULL, keys);
574 CFAllocatorDeallocate(NULL, values);
575 }
576
577 done :
578
579 if (dict != NULL) CFRelease(dict);
580 if (storeP != NULL) *storeP = store;
581 return sc_status;
582 }
583
584
585 #define ROUNDUP(a, size) \
586 (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
587
588 #define NEXT_SA(ap) (ap) = (struct sockaddr *) \
589 ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\
590 sizeof(uint32_t)) :\
591 sizeof(uint32_t)))
592
593 static void
594 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
595 {
596 int i;
597
598 for (i = 0; i < RTAX_MAX; i++) {
599 if (addrs & (1 << i)) {
600 rti_info[i] = sa;
601 NEXT_SA(sa);
602 } else
603 rti_info[i] = NULL;
604 }
605 }
606
607
608 #define BUFLEN (sizeof(struct rt_msghdr) + 512) /* 8 * sizeof(struct sockaddr_in6) = 192 */
609
610 static Boolean
611 checkAddress(SCDynamicStoreRef *storeP,
612 const struct sockaddr *address,
613 SCNetworkConnectionFlags *flags,
614 uint16_t *if_index)
615 {
616 char buf[BUFLEN];
617 struct ifreq ifr;
618 char if_name[IFNAMSIZ + 1];
619 int isock;
620 int n;
621 pid_t pid = getpid();
622 int rsock;
623 struct sockaddr *rti_info[RTAX_MAX];
624 struct rt_msghdr *rtm;
625 struct sockaddr *sa;
626 int sc_status = kSCStatusReachabilityUnknown;
627 struct sockaddr_dl *sdl;
628 int32_t seq = OSAtomicIncrement32Barrier(&rtm_seq);
629 SCDynamicStoreRef store = (storeP != NULL) ? *storeP : NULL;
630 char *statusMessage = NULL;
631 #ifndef RTM_GET_SILENT
632 #warning Note: Using RTM_GET (and not RTM_GET_SILENT)
633 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
634 int sosize = 48 * 1024;
635 #endif
636
637 *flags = 0;
638 if (if_index != NULL) {
639 *if_index = 0;
640 }
641
642 if (address == NULL) {
643 /* special case: check only for available paths off the system */
644 goto checkAvailable;
645 }
646
647 switch (address->sa_family) {
648 case AF_INET :
649 case AF_INET6 :
650 if (_sc_debug) {
651 _SC_sockaddr_to_string(address, buf, sizeof(buf));
652 SCLog(TRUE, LOG_INFO, CFSTR("checkAddress(%s)"), buf);
653 }
654 break;
655 default :
656 /*
657 * if no code for this address family (yet)
658 */
659 SCLog(_sc_verbose, LOG_ERR,
660 CFSTR("checkAddress(): unexpected address family %d"),
661 address->sa_family);
662 sc_status = kSCStatusInvalidArgument;
663 goto done;
664 }
665
666 bzero(&buf, sizeof(buf));
667
668 rtm = (struct rt_msghdr *)&buf;
669 rtm->rtm_msglen = sizeof(struct rt_msghdr);
670 rtm->rtm_version = RTM_VERSION;
671 #ifdef RTM_GET_SILENT
672 rtm->rtm_type = RTM_GET_SILENT;
673 #else
674 rtm->rtm_type = RTM_GET;
675 #endif
676 rtm->rtm_flags = RTF_STATIC|RTF_UP|RTF_HOST|RTF_GATEWAY;
677 rtm->rtm_addrs = RTA_DST|RTA_IFP; /* Both destination and device */
678 rtm->rtm_pid = pid;
679 rtm->rtm_seq = seq;
680
681 switch (address->sa_family) {
682 case AF_INET6: {
683 struct sockaddr_in6 *sin6;
684
685 sin6 = (struct sockaddr_in6 *)address;
686 if ((IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
687 IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) &&
688 (sin6->sin6_scope_id != 0)) {
689 sin6->sin6_addr.s6_addr16[1] = htons(sin6->sin6_scope_id);
690 sin6->sin6_scope_id = 0;
691 }
692 break;
693 }
694 }
695
696 sa = (struct sockaddr *) (rtm + 1);
697 bcopy(address, sa, address->sa_len);
698 n = ROUNDUP(sa->sa_len, sizeof(uint32_t));
699 rtm->rtm_msglen += n;
700
701 sdl = (struct sockaddr_dl *) ((void *)sa + n);
702 sdl->sdl_family = AF_LINK;
703 sdl->sdl_len = sizeof (struct sockaddr_dl);
704 n = ROUNDUP(sdl->sdl_len, sizeof(uint32_t));
705 rtm->rtm_msglen += n;
706
707 #ifndef RTM_GET_SILENT
708 pthread_mutex_lock(&lock);
709 #endif
710 rsock = socket(PF_ROUTE, SOCK_RAW, 0);
711 if (rsock == -1) {
712 #ifndef RTM_GET_SILENT
713 pthread_mutex_unlock(&lock);
714 #endif
715 SCLog(TRUE, LOG_ERR, CFSTR("socket(PF_ROUTE) failed: %s"), strerror(errno));
716 sc_status = kSCStatusFailed;
717 goto done;
718 }
719
720 #ifndef RTM_GET_SILENT
721 if (setsockopt(rsock, SOL_SOCKET, SO_RCVBUF, &sosize, sizeof(sosize)) == -1) {
722 (void)close(rsock);
723 pthread_mutex_unlock(&lock);
724 SCLog(TRUE, LOG_ERR, CFSTR("setsockopt(SO_RCVBUF) failed: %s"), strerror(errno));
725 sc_status = kSCStatusFailed;
726 goto done;
727 }
728 #endif
729
730 if (write(rsock, &buf, rtm->rtm_msglen) == -1) {
731 int err = errno;
732
733 (void)close(rsock);
734 #ifndef RTM_GET_SILENT
735 pthread_mutex_unlock(&lock);
736 #endif
737 if (err != ESRCH) {
738 SCLog(TRUE, LOG_ERR, CFSTR("write() failed: %s"), strerror(err));
739 goto done;
740 }
741 goto checkAvailable;
742 }
743
744 /*
745 * Type, seq, pid identify our response.
746 * Routing sockets are broadcasters on input.
747 */
748 do {
749 int n;
750
751 n = read(rsock, (void *)&buf, sizeof(buf));
752 if (n == -1) {
753 int err = errno;
754
755 if (err != EINTR) {
756 (void)close(rsock);
757 SCLog(TRUE, LOG_ERR, CFSTR("read() failed: %s"), strerror(err));
758 #ifndef RTM_GET_SILENT
759 pthread_mutex_unlock(&lock);
760 #endif
761 goto done;
762 }
763 }
764 } while (rtm->rtm_type != RTM_GET ||
765 rtm->rtm_seq != seq ||
766 rtm->rtm_pid != pid);
767
768 (void)close(rsock);
769 #ifndef RTM_GET_SILENT
770 pthread_mutex_unlock(&lock);
771 #endif
772
773 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
774
775 #ifdef DEBUG
776 {
777 int i;
778 char buf[200];
779
780 SCLog(_sc_debug, LOG_DEBUG, CFSTR("rtm_flags = 0x%8.8x"), rtm->rtm_flags);
781
782 if ((rti_info[RTAX_NETMASK] != NULL) && (rti_info[RTAX_DST] != NULL)) {
783 rti_info[RTAX_NETMASK]->sa_family = rti_info[RTAX_DST]->sa_family;
784 }
785
786 for (i = 0; i < RTAX_MAX; i++) {
787 if (rti_info[i] != NULL) {
788 _SC_sockaddr_to_string(rti_info[i], buf, sizeof(buf));
789 SCLog(_sc_debug, LOG_DEBUG, CFSTR("%d: %s"), i, buf);
790 }
791 }
792 }
793 #endif /* DEBUG */
794
795 if ((rti_info[RTAX_IFP] == NULL) ||
796 (rti_info[RTAX_IFP]->sa_family != AF_LINK)) {
797 /* no interface info */
798 goto done;
799 }
800
801 sdl = (struct sockaddr_dl *) rti_info[RTAX_IFP];
802 if ((sdl->sdl_nlen == 0) || (sdl->sdl_nlen > IFNAMSIZ)) {
803 /* no interface name */
804 goto checkAvailable;
805 }
806
807 /* get the interface flags */
808
809 bzero(&ifr, sizeof(ifr));
810 bcopy(sdl->sdl_data, ifr.ifr_name, sdl->sdl_nlen);
811
812 isock = socket(AF_INET, SOCK_DGRAM, 0);
813 if (isock == -1) {
814 SCLog(TRUE, LOG_NOTICE, CFSTR("socket() failed: %s"), strerror(errno));
815 goto done;
816 }
817
818 if (ioctl(isock, SIOCGIFFLAGS, (char *)&ifr) == -1) {
819 SCLog(TRUE, LOG_NOTICE, CFSTR("ioctl() failed: %s"), strerror(errno));
820 (void)close(isock);
821 goto done;
822 }
823 (void)close(isock);
824
825 if (!(ifr.ifr_flags & IFF_UP)) {
826 goto checkAvailable;
827 }
828
829 statusMessage = "isReachable";
830 *flags |= kSCNetworkFlagsReachable;
831
832 if (rtm->rtm_flags & RTF_LOCAL) {
833 statusMessage = "isReachable (is a local address)";
834 *flags |= kSCNetworkFlagsIsLocalAddress;
835 } else if (ifr.ifr_flags & IFF_LOOPBACK) {
836 statusMessage = "isReachable (is loopback network)";
837 *flags |= kSCNetworkFlagsIsLocalAddress;
838 } else if (rti_info[RTAX_IFA]) {
839 void *addr1 = (void *)address;
840 void *addr2 = (void *)rti_info[RTAX_IFA];
841 size_t len = address->sa_len;
842
843 if ((address->sa_family != rti_info[RTAX_IFA]->sa_family) &&
844 (address->sa_len != rti_info[RTAX_IFA]->sa_len)) {
845 SCLog(TRUE, LOG_NOTICE,
846 CFSTR("address family/length mismatch: %d/%d != %d/%d"),
847 address->sa_family,
848 address->sa_len,
849 rti_info[RTAX_IFA]->sa_family,
850 rti_info[RTAX_IFA]->sa_len);
851 goto done;
852 }
853
854 switch (address->sa_family) {
855 case AF_INET :
856 addr1 = &((struct sockaddr_in *)address)->sin_addr;
857 addr2 = &((struct sockaddr_in *)rti_info[RTAX_IFA])->sin_addr;
858 len = sizeof(struct in_addr);
859
860 /*
861 * check if 0.0.0.0
862 */
863 if (((struct sockaddr_in *)address)->sin_addr.s_addr == 0) {
864 statusMessage = "isReachable (this host)";
865 *flags |= kSCNetworkFlagsIsLocalAddress;
866 }
867 break;
868 case AF_INET6 :
869 addr1 = &((struct sockaddr_in6 *)address)->sin6_addr;
870 addr2 = &((struct sockaddr_in6 *)rti_info[RTAX_IFA])->sin6_addr;
871 len = sizeof(struct in6_addr);
872 break;
873 default :
874 break;
875 }
876
877 if (memcmp(addr1, addr2, len) == 0) {
878 statusMessage = "isReachable (is interface address)";
879 *flags |= kSCNetworkFlagsIsLocalAddress;
880 }
881 }
882
883 if (!(rtm->rtm_flags & RTF_GATEWAY) &&
884 (rti_info[RTAX_GATEWAY] != NULL) &&
885 (rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) &&
886 !(ifr.ifr_flags & IFF_POINTOPOINT)) {
887 *flags |= kSCNetworkFlagsIsDirect;
888 }
889
890 bzero(&if_name, sizeof(if_name));
891 bcopy(sdl->sdl_data,
892 if_name,
893 (sdl->sdl_nlen <= IFNAMSIZ) ? sdl->sdl_nlen : IFNAMSIZ);
894
895 if (if_index != NULL) {
896 *if_index = sdl->sdl_index;
897 }
898
899 if (_sc_debug) {
900 SCLog(TRUE, LOG_INFO, CFSTR(" status = %s"), statusMessage);
901 SCLog(TRUE, LOG_INFO, CFSTR(" device = %s (%hu)"), if_name, sdl->sdl_index);
902 SCLog(TRUE, LOG_INFO, CFSTR(" ifr_flags = 0x%04hx"), ifr.ifr_flags);
903 SCLog(TRUE, LOG_INFO, CFSTR(" rtm_flags = 0x%08x"), rtm->rtm_flags);
904 }
905
906 sc_status = kSCStatusOK;
907
908 if (ifr.ifr_flags & IFF_POINTOPOINT) {
909 /*
910 * We have an interface which "claims" to be a valid path
911 * off of the system.
912 */
913 *flags |= kSCNetworkFlagsTransientConnection;
914
915 /*
916 * Check if this is a dial-on-demand PPP link that isn't
917 * connected yet.
918 */
919 sc_status = updatePPPStatus(&store, address, if_name, flags);
920 }
921
922 goto done;
923
924 checkAvailable :
925
926 sc_status = updatePPPAvailable(&store, address, flags);
927
928 done :
929
930 if (*flags == 0) {
931 SCLog(_sc_debug, LOG_INFO, CFSTR(" cannot be reached"));
932 }
933
934 if (storeP != NULL) *storeP = store;
935 if (sc_status != kSCStatusOK) {
936 _SCErrorSet(sc_status);
937 return FALSE;
938 }
939
940 return TRUE;
941 }
942
943
944 static CFStringRef
945 __SCNetworkReachabilityCopyDescription(CFTypeRef cf)
946 {
947 CFAllocatorRef allocator = CFGetAllocator(cf);
948 CFMutableStringRef result;
949 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)cf;
950
951 result = CFStringCreateMutable(allocator, 0);
952 CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkReachability %p [%p]> {"), cf, allocator);
953 switch (targetPrivate->type) {
954 case reachabilityTypeAddress :
955 case reachabilityTypeAddressPair : {
956 char buf[64];
957
958 if (targetPrivate->localAddress != NULL) {
959 _SC_sockaddr_to_string(targetPrivate->localAddress, buf, sizeof(buf));
960 CFStringAppendFormat(result, NULL, CFSTR("local address = %s"),
961 buf);
962 }
963
964 if (targetPrivate->remoteAddress != NULL) {
965 _SC_sockaddr_to_string(targetPrivate->remoteAddress, buf, sizeof(buf));
966 CFStringAppendFormat(result, NULL, CFSTR("%s%saddress = %s"),
967 targetPrivate->localAddress ? ", " : "",
968 (targetPrivate->type == reachabilityTypeAddressPair) ? "remote " : "",
969 buf);
970 }
971 break;
972 }
973 case reachabilityTypeName : {
974 CFStringAppendFormat(result, NULL, CFSTR("name = %s"), targetPrivate->name);
975 if ((targetPrivate->resolvedAddress != NULL) || (targetPrivate->resolvedAddressError != NETDB_SUCCESS)) {
976 if (targetPrivate->resolvedAddress != NULL) {
977 if (isA_CFArray(targetPrivate->resolvedAddress)) {
978 CFIndex i;
979 CFIndex n = CFArrayGetCount(targetPrivate->resolvedAddress);
980
981 CFStringAppendFormat(result, NULL, CFSTR(" ("));
982 for (i = 0; i < n; i++) {
983 CFDataRef address;
984 char buf[64];
985 struct sockaddr *sa;
986
987 address = CFArrayGetValueAtIndex(targetPrivate->resolvedAddress, i);
988 sa = (struct sockaddr *)CFDataGetBytePtr(address);
989 _SC_sockaddr_to_string(sa, buf, sizeof(buf));
990 CFStringAppendFormat(result, NULL, CFSTR("%s%s"),
991 i > 0 ? ", " : "",
992 buf);
993 }
994 CFStringAppendFormat(result, NULL, CFSTR(")"));
995 } else {
996 CFStringAppendFormat(result, NULL, CFSTR(" (no addresses)"));
997 }
998 } else {
999 CFStringAppendFormat(result, NULL, CFSTR(" (%s)"),
1000 gai_strerror(targetPrivate->resolvedAddressError));
1001 }
1002 } else if (targetPrivate->dnsPort != NULL) {
1003 CFStringAppendFormat(result, NULL, CFSTR(" (DNS query active)"));
1004 }
1005 break;
1006 }
1007 }
1008 if (targetPrivate->rls != NULL) {
1009 CFStringAppendFormat(result,
1010 NULL,
1011 CFSTR(", flags = %8.8x, if_index = %hu"),
1012 targetPrivate->flags,
1013 targetPrivate->if_index);
1014 }
1015 CFStringAppendFormat(result, NULL, CFSTR("}"));
1016
1017 return result;
1018 }
1019
1020
1021 static void
1022 __SCNetworkReachabilityDeallocate(CFTypeRef cf)
1023 {
1024 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)cf;
1025
1026 /* release resources */
1027
1028 pthread_mutex_destroy(&targetPrivate->lock);
1029
1030 if (targetPrivate->name != NULL)
1031 CFAllocatorDeallocate(NULL, (void *)targetPrivate->name);
1032
1033 if (targetPrivate->resolvedAddress != NULL)
1034 CFRelease(targetPrivate->resolvedAddress);
1035
1036 if (targetPrivate->localAddress != NULL)
1037 CFAllocatorDeallocate(NULL, (void *)targetPrivate->localAddress);
1038
1039 if (targetPrivate->remoteAddress != NULL)
1040 CFAllocatorDeallocate(NULL, (void *)targetPrivate->remoteAddress);
1041
1042 if (targetPrivate->rlsContext.release != NULL) {
1043 (*targetPrivate->rlsContext.release)(targetPrivate->rlsContext.info);
1044 }
1045
1046 return;
1047 }
1048
1049
1050 static void
1051 __SCNetworkReachabilityInitialize(void)
1052 {
1053 __kSCNetworkReachabilityTypeID = _CFRuntimeRegisterClass(&__SCNetworkReachabilityClass);
1054 return;
1055 }
1056
1057
1058 static SCNetworkReachabilityPrivateRef
1059 __SCNetworkReachabilityCreatePrivate(CFAllocatorRef allocator)
1060 {
1061 SCNetworkReachabilityPrivateRef targetPrivate;
1062 uint32_t size;
1063
1064 /* initialize runtime */
1065 pthread_once(&initialized, __SCNetworkReachabilityInitialize);
1066
1067 /* allocate target */
1068 size = sizeof(SCNetworkReachabilityPrivate) - sizeof(CFRuntimeBase);
1069 targetPrivate = (SCNetworkReachabilityPrivateRef)_CFRuntimeCreateInstance(allocator,
1070 __kSCNetworkReachabilityTypeID,
1071 size,
1072 NULL);
1073 if (targetPrivate == NULL) {
1074 return NULL;
1075 }
1076
1077 pthread_mutex_init(&targetPrivate->lock, NULL);
1078
1079 targetPrivate->name = NULL;
1080
1081 targetPrivate->resolvedAddress = NULL;
1082 targetPrivate->resolvedAddressError = NETDB_SUCCESS;
1083
1084 targetPrivate->localAddress = NULL;
1085 targetPrivate->remoteAddress = NULL;
1086
1087 targetPrivate->flags = 0;
1088 targetPrivate->if_index = 0;
1089
1090 targetPrivate->rls = NULL;
1091 targetPrivate->rlsFunction = NULL;
1092 targetPrivate->rlsContext.info = NULL;
1093 targetPrivate->rlsContext.retain = NULL;
1094 targetPrivate->rlsContext.release = NULL;
1095 targetPrivate->rlsContext.copyDescription = NULL;
1096 targetPrivate->rlList = NULL;
1097
1098 targetPrivate->haveDNS = FALSE;
1099 targetPrivate->dnsPort = NULL;
1100 targetPrivate->dnsRLS = NULL;
1101
1102 return targetPrivate;
1103 }
1104
1105
1106 SCNetworkReachabilityRef
1107 SCNetworkReachabilityCreateWithAddress(CFAllocatorRef allocator,
1108 const struct sockaddr *address)
1109 {
1110 SCNetworkReachabilityPrivateRef targetPrivate;
1111
1112 if ((address == NULL) ||
1113 (address->sa_len == 0) ||
1114 (address->sa_len > sizeof(struct sockaddr_storage))) {
1115 _SCErrorSet(kSCStatusInvalidArgument);
1116 return NULL;
1117 }
1118
1119 targetPrivate = __SCNetworkReachabilityCreatePrivate(allocator);
1120 if (targetPrivate == NULL) {
1121 return NULL;
1122 }
1123
1124 targetPrivate->type = reachabilityTypeAddress;
1125 targetPrivate->remoteAddress = CFAllocatorAllocate(NULL, address->sa_len, 0);
1126 bcopy(address, targetPrivate->remoteAddress, address->sa_len);
1127
1128 return (SCNetworkReachabilityRef)targetPrivate;
1129 }
1130
1131
1132 SCNetworkReachabilityRef
1133 SCNetworkReachabilityCreateWithAddressPair(CFAllocatorRef allocator,
1134 const struct sockaddr *localAddress,
1135 const struct sockaddr *remoteAddress)
1136 {
1137 SCNetworkReachabilityPrivateRef targetPrivate;
1138
1139 if ((localAddress == NULL) && (remoteAddress == NULL)) {
1140 _SCErrorSet(kSCStatusInvalidArgument);
1141 return NULL;
1142 }
1143
1144 if (localAddress != NULL) {
1145 if ((localAddress->sa_len == 0) ||
1146 (localAddress->sa_len > sizeof(struct sockaddr_storage))) {
1147 _SCErrorSet(kSCStatusInvalidArgument);
1148 return NULL;
1149 }
1150 }
1151
1152 if (remoteAddress != NULL) {
1153 if ((remoteAddress->sa_len == 0) ||
1154 (remoteAddress->sa_len > sizeof(struct sockaddr_storage))) {
1155 _SCErrorSet(kSCStatusInvalidArgument);
1156 return NULL;
1157 }
1158 }
1159
1160 targetPrivate = __SCNetworkReachabilityCreatePrivate(allocator);
1161 if (targetPrivate == NULL) {
1162 return NULL;
1163 }
1164
1165 targetPrivate->type = reachabilityTypeAddressPair;
1166
1167 if (localAddress != NULL) {
1168 targetPrivate->localAddress = CFAllocatorAllocate(NULL, localAddress->sa_len, 0);
1169 bcopy(localAddress, targetPrivate->localAddress, localAddress->sa_len);
1170 }
1171
1172 if (remoteAddress != NULL) {
1173 targetPrivate->remoteAddress = CFAllocatorAllocate(NULL, remoteAddress->sa_len, 0);
1174 bcopy(remoteAddress, targetPrivate->remoteAddress, remoteAddress->sa_len);
1175 }
1176
1177 return (SCNetworkReachabilityRef)targetPrivate;
1178 }
1179
1180
1181 SCNetworkReachabilityRef
1182 SCNetworkReachabilityCreateWithName(CFAllocatorRef allocator,
1183 const char *nodename)
1184 {
1185 int nodenameLen;
1186 struct sockaddr_in sin;
1187 struct sockaddr_in6 sin6;
1188 SCNetworkReachabilityPrivateRef targetPrivate;
1189
1190 if (nodename == NULL) {
1191 _SCErrorSet(kSCStatusInvalidArgument);
1192 return NULL;
1193 }
1194
1195 nodenameLen = strlen(nodename);
1196 if (nodenameLen == 0) {
1197 _SCErrorSet(kSCStatusInvalidArgument);
1198 return NULL;
1199 }
1200
1201 /* check if this "nodename" is really an IP[v6] address in disguise */
1202
1203 bzero(&sin, sizeof(sin));
1204 sin.sin_len = sizeof(sin);
1205 sin.sin_family = AF_INET;
1206 if (inet_aton(nodename, &sin.sin_addr) == 1) {
1207 /* if IPv4 address */
1208 return SCNetworkReachabilityCreateWithAddress(allocator, (struct sockaddr *)&sin);
1209 }
1210
1211 bzero(&sin6, sizeof(sin6));
1212 sin6.sin6_len = sizeof(sin6);
1213 sin6.sin6_family = AF_INET6;
1214 if (inet_pton(AF_INET6, nodename, &sin6.sin6_addr) == 1) {
1215 /* if IPv6 address */
1216 char *p;
1217
1218 p = strchr(nodename, '%');
1219 if (p != NULL) {
1220 sin6.sin6_scope_id = if_nametoindex(p + 1);
1221 }
1222
1223 return SCNetworkReachabilityCreateWithAddress(allocator, (struct sockaddr *)&sin6);
1224 }
1225
1226 targetPrivate = __SCNetworkReachabilityCreatePrivate(allocator);
1227 if (targetPrivate == NULL) {
1228 return NULL;
1229 }
1230
1231 targetPrivate->type = reachabilityTypeName;
1232
1233 targetPrivate->flags |= kSCNetworkFlagsFirstResolvePending;
1234
1235 targetPrivate->name = CFAllocatorAllocate(NULL, nodenameLen + 1, 0);
1236 strlcpy((char *)targetPrivate->name, nodename, nodenameLen + 1);
1237
1238 return (SCNetworkReachabilityRef)targetPrivate;
1239 }
1240
1241
1242 CFTypeID
1243 SCNetworkReachabilityGetTypeID(void)
1244 {
1245 pthread_once(&initialized, __SCNetworkReachabilityInitialize); /* initialize runtime */
1246 return __kSCNetworkReachabilityTypeID;
1247 }
1248
1249
1250 CFArrayRef
1251 SCNetworkReachabilityCopyResolvedAddress(SCNetworkReachabilityRef target,
1252 int *error_num)
1253 {
1254 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
1255
1256 if (!isA_SCNetworkReachability(target)) {
1257 _SCErrorSet(kSCStatusInvalidArgument);
1258 return NULL;
1259 }
1260
1261 if (targetPrivate->type != reachabilityTypeName) {
1262 _SCErrorSet(kSCStatusInvalidArgument);
1263 return NULL;
1264 }
1265
1266 if (error_num) {
1267 *error_num = targetPrivate->resolvedAddressError;
1268 }
1269
1270 if ((targetPrivate->resolvedAddress != NULL) || (targetPrivate->resolvedAddressError != NETDB_SUCCESS)) {
1271 if (targetPrivate->resolvedAddress != NULL) {
1272 return CFRetain(targetPrivate->resolvedAddress);
1273 } else {
1274 /* if status is known but no resolved addresses to return */
1275 _SCErrorSet(kSCStatusOK);
1276 return NULL;
1277 }
1278 }
1279
1280 _SCErrorSet(kSCStatusReachabilityUnknown);
1281 return NULL;
1282 }
1283
1284
1285 static void
1286 __SCNetworkReachabilitySetResolvedAddress(int32_t status,
1287 struct addrinfo *res,
1288 SCNetworkReachabilityRef target)
1289 {
1290 struct addrinfo *resP;
1291 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
1292
1293 if (targetPrivate->resolvedAddress != NULL) {
1294 CFRelease(targetPrivate->resolvedAddress);
1295 targetPrivate->resolvedAddress = NULL;
1296 }
1297
1298 if ((status == 0) && (res != NULL)) {
1299
1300 CFMutableArrayRef addresses;
1301
1302 addresses = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1303
1304 for (resP = res; resP; resP = resP->ai_next) {
1305 CFDataRef newAddress;
1306
1307 newAddress = CFDataCreate(NULL, (void *)resP->ai_addr, resP->ai_addr->sa_len);
1308 CFArrayAppendValue(addresses, newAddress);
1309 CFRelease(newAddress);
1310 }
1311
1312 /* save the resolved address[es] */
1313 targetPrivate->resolvedAddress = addresses;
1314 targetPrivate->resolvedAddressError = NETDB_SUCCESS;
1315 } else {
1316 SCLog(_sc_debug, LOG_INFO, CFSTR("getaddrinfo() failed: %s"), gai_strerror(status));
1317
1318 /* save the error associated with the attempt to resolve the name */
1319 targetPrivate->resolvedAddress = CFRetain(kCFNull);
1320 targetPrivate->resolvedAddressError = status;
1321 }
1322
1323 if (res != NULL) freeaddrinfo(res);
1324
1325 if (targetPrivate->rls != NULL) {
1326 SCLog(_sc_debug, LOG_INFO, CFSTR("DNS request completed"));
1327 CFRunLoopSourceSignal(targetPrivate->rls);
1328 _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
1329 }
1330
1331 return;
1332 }
1333
1334
1335 static void
1336 __SCNetworkReachabilityCallbackSetResolvedAddress(int32_t status, struct addrinfo *res, void *context)
1337 {
1338 SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)context;
1339 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
1340
1341 __log_query_time(((status == 0) && (res != NULL)), // if successful query
1342 TRUE, // async
1343 &targetPrivate->dnsQueryStart); // start time
1344
1345 __SCNetworkReachabilitySetResolvedAddress(status, res, target);
1346 return;
1347 }
1348
1349
1350 /*
1351 * rankReachability()
1352 * Not reachable == 0
1353 * Connection Required == 1
1354 * Reachable == 2
1355 */
1356 static int
1357 rankReachability(SCNetworkConnectionFlags flags)
1358 {
1359 int rank = 0;
1360
1361 if (flags & kSCNetworkFlagsReachable) rank = 2;
1362 if (flags & kSCNetworkFlagsConnectionRequired) rank = 1;
1363 return rank;
1364 }
1365
1366
1367 static void
1368 getaddrinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, void *info)
1369 {
1370 int32_t status;
1371 SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)info;
1372 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
1373
1374 pthread_mutex_lock(&targetPrivate->lock);
1375
1376 status = getaddrinfo_async_handle_reply(msg);
1377 if ((status == 0) &&
1378 (targetPrivate->resolvedAddress == NULL) && (targetPrivate->resolvedAddressError == NETDB_SUCCESS)) {
1379 // if request has been re-queued
1380 goto again;
1381 }
1382
1383 if (port == targetPrivate->dnsPort) {
1384 CFRunLoopSourceInvalidate(targetPrivate->dnsRLS);
1385 CFRelease(targetPrivate->dnsRLS);
1386 targetPrivate->dnsRLS = NULL;
1387 CFRelease(targetPrivate->dnsPort);
1388 targetPrivate->dnsPort = NULL;
1389 }
1390
1391 again :
1392
1393 pthread_mutex_unlock(&targetPrivate->lock);
1394
1395 return;
1396 }
1397
1398
1399 static Boolean
1400 check_resolver_reachability(SCDynamicStoreRef *storeP,
1401 dns_resolver_t *resolver,
1402 SCNetworkConnectionFlags *flags,
1403 Boolean *haveDNS)
1404 {
1405 int i;
1406 Boolean ok = TRUE;
1407
1408 *flags = kSCNetworkFlagsReachable;
1409 *haveDNS = FALSE;
1410
1411 for (i = 0; i < resolver->n_nameserver; i++) {
1412 struct sockaddr *address = resolver->nameserver[i];
1413 SCNetworkConnectionFlags ns_flags = 0;
1414
1415 *haveDNS = TRUE;
1416
1417 if (address->sa_family != AF_INET) {
1418 /*
1419 * we need to skip non-IPv4 DNS server
1420 * addresses (at least until [3510431] has
1421 * been resolved).
1422 */
1423 continue;
1424 }
1425
1426 ok = checkAddress(storeP, address, &ns_flags, NULL);
1427 if (!ok) {
1428 /* not today */
1429 goto done;
1430 }
1431
1432 if (rankReachability(ns_flags) < rankReachability(*flags)) {
1433 /* return the worst case result */
1434 *flags = ns_flags;
1435 }
1436 }
1437
1438 done :
1439
1440 return ok;
1441 }
1442
1443
1444 static Boolean
1445 check_matching_resolvers(SCDynamicStoreRef *storeP,
1446 dns_config_t *dns_config,
1447 const char *fqdn,
1448 SCNetworkConnectionFlags *flags,
1449 Boolean *haveDNS)
1450 {
1451 int i;
1452 Boolean matched = FALSE;
1453 const char *name = fqdn;
1454
1455 while (!matched && (name != NULL)) {
1456 int len;
1457
1458 /*
1459 * check if the provided name (or sub-component)
1460 * matches one of our resolver configurations.
1461 */
1462 len = strlen(name);
1463 for (i = 0; i < dns_config->n_resolver; i++) {
1464 char *domain;
1465 dns_resolver_t *resolver;
1466
1467 resolver = dns_config->resolver[i];
1468 domain = resolver->domain;
1469 if (domain != NULL && (len == strlen(domain))) {
1470 if (strcasecmp(name, domain) == 0) {
1471 Boolean ok;
1472
1473 /*
1474 * if name matches domain
1475 */
1476 matched = TRUE;
1477 ok = check_resolver_reachability(storeP, resolver, flags, haveDNS);
1478 if (!ok) {
1479 /* not today */
1480 return FALSE;
1481 }
1482 }
1483 }
1484 }
1485
1486 if (!matched) {
1487 /*
1488 * we have not found a matching resolver, try
1489 * a less qualified domain
1490 */
1491 name = strchr(name, '.');
1492 if ((name != NULL) && (*name != '\0')) {
1493 name++;
1494 } else {
1495 name = NULL;
1496 }
1497 }
1498 }
1499
1500 return matched;
1501 }
1502
1503
1504 static dns_configuration_t *
1505 dns_configuration_retain()
1506 {
1507 pthread_mutex_lock(&dns_lock);
1508
1509 if ((dns_configuration != NULL) && dns_token_valid) {
1510 int check = 0;
1511 uint32_t status;
1512
1513 /*
1514 * check if the global [DNS] configuration snapshot needs
1515 * to be updated
1516 */
1517 status = notify_check(dns_token, &check);
1518 if (status != NOTIFY_STATUS_OK) {
1519 SCLog(TRUE, LOG_INFO, CFSTR("notify_check() failed, status=%lu"), status);
1520 }
1521
1522 if ((status != NOTIFY_STATUS_OK) || (check != 0)) {
1523 /*
1524 * if the snapshot needs to be refreshed
1525 */
1526 if (dns_configuration->refs == 0) {
1527 dns_configuration_free(dns_configuration->config);
1528 CFAllocatorDeallocate(NULL, dns_configuration);
1529 }
1530 dns_configuration = NULL;
1531 }
1532 }
1533
1534 if (dns_configuration == NULL) {
1535 dns_config_t *new_config;
1536
1537 new_config = dns_configuration_copy();
1538 if (new_config != NULL) {
1539 dns_configuration = CFAllocatorAllocate(NULL, sizeof(dns_configuration_t), 0);
1540 dns_configuration->config = new_config;
1541 dns_configuration->refs = 0;
1542 }
1543 }
1544
1545 if (dns_configuration != NULL) {
1546 dns_configuration->refs++;
1547 }
1548
1549 pthread_mutex_unlock(&dns_lock);
1550 return dns_configuration;
1551 }
1552
1553
1554 static void
1555 dns_configuration_release(dns_configuration_t *config)
1556 {
1557 pthread_mutex_lock(&dns_lock);
1558
1559 config->refs--;
1560 if (config->refs == 0) {
1561 if ((dns_configuration != config)) {
1562 dns_configuration_free(config->config);
1563 CFAllocatorDeallocate(NULL, config);
1564 }
1565 }
1566
1567 pthread_mutex_unlock(&dns_lock);
1568 return;
1569 }
1570
1571
1572 static Boolean
1573 dns_configuration_watch()
1574 {
1575 int dns_check = 0;
1576 const char *dns_key;
1577 Boolean ok = FALSE;
1578 uint32_t status;
1579
1580 pthread_mutex_lock(&dns_lock);
1581
1582 dns_key = dns_configuration_notify_key();
1583 if (dns_key == NULL) {
1584 SCLog(TRUE, LOG_INFO, CFSTR("dns_configuration_notify_key() failed"));
1585 goto done;
1586 }
1587
1588 status = notify_register_check(dns_key, &dns_token);
1589 if (status == NOTIFY_STATUS_OK) {
1590 dns_token_valid = TRUE;
1591 } else {
1592 SCLog(TRUE, LOG_INFO, CFSTR("notify_register_check() failed, status=%lu"), status);
1593 goto done;
1594 }
1595
1596 status = notify_check(dns_token, &dns_check);
1597 if (status != NOTIFY_STATUS_OK) {
1598 SCLog(TRUE, LOG_INFO, CFSTR("notify_check() failed, status=%lu"), status);
1599 (void)notify_cancel(dns_token);
1600 dns_token_valid = FALSE;
1601 goto done;
1602 }
1603
1604 ok = TRUE;
1605
1606 done :
1607
1608 pthread_mutex_unlock(&dns_lock);
1609 return ok;
1610 }
1611
1612
1613 static void
1614 dns_configuration_unwatch()
1615 {
1616 pthread_mutex_lock(&dns_lock);
1617
1618 (void)notify_cancel(dns_token);
1619 dns_token_valid = FALSE;
1620
1621 if ((dns_configuration != NULL) && (dns_configuration->refs == 0)) {
1622 dns_configuration_free(dns_configuration->config);
1623 CFAllocatorDeallocate(NULL, dns_configuration);
1624 dns_configuration = NULL;
1625 }
1626
1627 pthread_mutex_unlock(&dns_lock);
1628 return;
1629 }
1630
1631
1632 Boolean
1633 _SC_checkResolverReachability(SCDynamicStoreRef *storeP,
1634 SCNetworkConnectionFlags *flags,
1635 Boolean *haveDNS,
1636 const char * nodename)
1637 {
1638 dns_resolver_t *default_resolver;
1639 dns_configuration_t *dns;
1640 Boolean found = FALSE;
1641 char *fqdn = (char *)nodename;
1642 int i;
1643 Boolean isFQDN = FALSE;
1644 uint32_t len;
1645 Boolean ok = TRUE;
1646
1647 /*
1648 * We first assume that all of the configured DNS servers
1649 * are available. Since we don't know which name server will
1650 * be consulted to resolve the specified nodename we need to
1651 * check the availability of ALL name servers. We can only
1652 * proceed if we know that our query can be answered.
1653 */
1654
1655 *flags = kSCNetworkFlagsReachable;
1656 *haveDNS = FALSE;
1657
1658 len = strlen(fqdn);
1659 if (len == 0) {
1660 // if no nodename, return not reachable
1661 *flags = 0;
1662 return ok;
1663 }
1664
1665 dns = dns_configuration_retain();
1666 if (dns == NULL) {
1667 // if error
1668 goto done;
1669 }
1670
1671 if (dns->config->n_resolver == 0) {
1672 // if no resolver configuration
1673 goto done;
1674 }
1675
1676 *flags = kSCNetworkFlagsReachable;
1677
1678 if (fqdn[len - 1] == '.') {
1679 isFQDN = TRUE;
1680
1681 // trim trailing '.''s
1682 while ((len > 0) && (fqdn[len-1] == '.')) {
1683 if (fqdn == nodename) {
1684 fqdn = strdup(nodename);
1685 }
1686 fqdn[--len] = '\0';
1687 }
1688 }
1689
1690 default_resolver = dns->config->resolver[0];
1691
1692 /*
1693 * try the provided name
1694 */
1695 found = check_matching_resolvers(storeP, dns->config, fqdn, flags, haveDNS);
1696 if (!found && !isFQDN && (dns->config->n_resolver > 1)) {
1697 /*
1698 * FQDN not specified, try w/search or default domain(s) too
1699 */
1700 if (default_resolver->n_search > 0) {
1701 for (i = 0; !found && (i < default_resolver->n_search); i++) {
1702 int ret;
1703 char *search_fqdn = NULL;
1704
1705 ret = asprintf(&search_fqdn, "%s.%s", fqdn, default_resolver->search[i]);
1706 if (ret == -1) {
1707 continue;
1708 }
1709
1710 // try the provided name with the search domain appended
1711 found = check_matching_resolvers(storeP, dns->config, search_fqdn, flags, haveDNS);
1712 free(search_fqdn);
1713 }
1714 } else if (default_resolver->domain != NULL) {
1715 char *dp;
1716 int domain_parts = 0;
1717
1718 // count domain parts
1719 for (dp = default_resolver->domain; *dp != '\0'; dp++) {
1720 if (*dp == '.') {
1721 domain_parts++;
1722 }
1723 }
1724
1725 // remove trailing dots
1726 for (dp--; (dp >= default_resolver->domain) && (*dp == '.'); dp--) {
1727 *dp = '\0';
1728 domain_parts--;
1729 }
1730
1731 if (dp >= default_resolver->domain) {
1732 // dots are separators, bump # of components
1733 domain_parts++;
1734 }
1735
1736 dp = default_resolver->domain;
1737 for (i = LOCALDOMAINPARTS; !found && (i <= domain_parts); i++) {
1738 int ret;
1739 char *search_fqdn = NULL;
1740
1741 ret = asprintf(&search_fqdn, "%s.%s", fqdn, dp);
1742 if (ret == -1) {
1743 continue;
1744 }
1745
1746 // try the provided name with the [default] domain appended
1747 found = check_matching_resolvers(storeP, dns->config, search_fqdn, flags, haveDNS);
1748 free(search_fqdn);
1749
1750 // move to the next component of the [default] domain
1751 dp = strchr(dp, '.') + 1;
1752 }
1753 }
1754 }
1755
1756 if (!found) {
1757 /*
1758 * check the reachability of the default resolver
1759 */
1760 ok = check_resolver_reachability(storeP, default_resolver, flags, haveDNS);
1761 }
1762
1763 if (fqdn != nodename) free(fqdn);
1764
1765 done :
1766
1767 if (dns != NULL) {
1768 dns_configuration_release(dns);
1769 }
1770
1771 return ok;
1772 }
1773
1774
1775 /*
1776 * _SC_checkResolverReachabilityByAddress()
1777 *
1778 * Given an IP address, determine whether a reverse DNS query can be issued
1779 * using the current network configuration.
1780 */
1781 Boolean
1782 _SC_checkResolverReachabilityByAddress(SCDynamicStoreRef *storeP,
1783 SCNetworkConnectionFlags *flags,
1784 Boolean *haveDNS,
1785 struct sockaddr *sa)
1786 {
1787 int i;
1788 Boolean ok = FALSE;
1789 char ptr_name[128];
1790
1791 /*
1792 * Ideally, we would have an API that given a local IP
1793 * address would return the DNS server(s) that would field
1794 * a given PTR query. Fortunately, we do have an SPI which
1795 * which will provide this information given a "name" so we
1796 * take the address, convert it into the inverse query name,
1797 * and find out which servers should be consulted.
1798 */
1799
1800 switch (sa->sa_family) {
1801 case AF_INET : {
1802 union {
1803 in_addr_t s_addr;
1804 unsigned char b[4];
1805 } rev;
1806 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1807
1808 /*
1809 * build "PTR" query name
1810 * NNN.NNN.NNN.NNN.in-addr.arpa.
1811 */
1812 rev.s_addr = sin->sin_addr.s_addr;
1813 (void) snprintf(ptr_name, sizeof(ptr_name), "%u.%u.%u.%u.in-addr.arpa.",
1814 rev.b[3],
1815 rev.b[2],
1816 rev.b[1],
1817 rev.b[0]);
1818
1819 break;
1820 }
1821
1822 case AF_INET6 : {
1823 int s = 0;
1824 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
1825 int x = sizeof(ptr_name);
1826 int n;
1827
1828 /*
1829 * build IPv6 "nibble" PTR query name (RFC 1886, RFC 3152)
1830 * N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.ip6.arpa.
1831 */
1832 for (i = sizeof(sin6->sin6_addr) - 1; i >= 0; i--) {
1833 n = snprintf(&ptr_name[s], x, "%x.%x.",
1834 ( sin6->sin6_addr.s6_addr[i] & 0xf),
1835 ((sin6->sin6_addr.s6_addr[i] >> 4) & 0xf));
1836 if ((n == -1) || (n >= x)) {
1837 goto done;
1838 }
1839
1840 s += n;
1841 x -= n;
1842 }
1843
1844 n = snprintf(&ptr_name[s], x, "ip6.arpa.");
1845 if ((n == -1) || (n >= x)) {
1846 goto done;
1847 }
1848
1849 break;
1850 }
1851
1852 default :
1853 goto done;
1854 }
1855
1856 ok = _SC_checkResolverReachability(storeP, flags, haveDNS, ptr_name);
1857
1858 done :
1859
1860 return ok;
1861 }
1862
1863
1864 static CFStringRef
1865 replyMPCopyDescription(const void *info)
1866 {
1867 SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)info;
1868 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
1869
1870 return CFStringCreateWithFormat(NULL,
1871 NULL,
1872 CFSTR("<getaddrinfo_async_start reply MP> {name = %s, target = %p}"),
1873 targetPrivate->name ? targetPrivate->name : "?",
1874 target);
1875 }
1876
1877
1878 static Boolean
1879 startAsyncDNSQuery(SCNetworkReachabilityRef target) {
1880 CFMachPortContext context = { 0
1881 , (void *)target
1882 , CFRetain
1883 , CFRelease
1884 , replyMPCopyDescription
1885 };
1886 int error;
1887 struct addrinfo hints;
1888 CFIndex i;
1889 CFIndex n;
1890 mach_port_t port;
1891 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
1892
1893 (void) gettimeofday(&targetPrivate->dnsQueryStart, NULL);
1894
1895 bzero(&hints, sizeof(hints));
1896 hints.ai_flags = AI_ADDRCONFIG;
1897 #ifdef AI_PARALLEL
1898 hints.ai_flags |= AI_PARALLEL;
1899 #endif /* AI_PARALLEL */
1900
1901 error = getaddrinfo_async_start(&port,
1902 targetPrivate->name,
1903 NULL,
1904 &hints,
1905 __SCNetworkReachabilityCallbackSetResolvedAddress,
1906 (void *)target);
1907 if (error != 0) {
1908 /* save the error associated with the attempt to resolve the name */
1909 __SCNetworkReachabilityCallbackSetResolvedAddress(error, NULL, (void *)target);
1910 return FALSE;
1911 }
1912
1913 targetPrivate->dnsPort = CFMachPortCreateWithPort(NULL,
1914 port,
1915 getaddrinfo_async_handleCFReply,
1916 &context,
1917 NULL);
1918 targetPrivate->dnsRLS = CFMachPortCreateRunLoopSource(NULL, targetPrivate->dnsPort, 0);
1919
1920 n = CFArrayGetCount(targetPrivate->rlList);
1921 for (i = 0; i < n; i += 3) {
1922 CFRunLoopRef rl = (CFRunLoopRef)CFArrayGetValueAtIndex(targetPrivate->rlList, i+1);
1923 CFStringRef rlMode = (CFStringRef) CFArrayGetValueAtIndex(targetPrivate->rlList, i+2);
1924
1925 CFRunLoopAddSource(rl, targetPrivate->dnsRLS, rlMode);
1926 }
1927
1928 return TRUE;
1929 }
1930
1931
1932 static Boolean
1933 __SCNetworkReachabilityGetFlags(SCDynamicStoreRef *storeP,
1934 SCNetworkReachabilityRef target,
1935 SCNetworkConnectionFlags *flags,
1936 uint16_t *if_index,
1937 Boolean async)
1938 {
1939 CFMutableArrayRef addresses = NULL;
1940 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
1941 SCNetworkConnectionFlags my_flags = 0;
1942 uint16_t my_index = 0;
1943 Boolean ok = TRUE;
1944
1945 *flags = 0;
1946 if (if_index != NULL) {
1947 *if_index = 0;
1948 }
1949
1950 if (!isA_SCNetworkReachability(target)) {
1951 _SCErrorSet(kSCStatusInvalidArgument);
1952 return FALSE;
1953 }
1954
1955 switch (targetPrivate->type) {
1956 case reachabilityTypeAddress :
1957 case reachabilityTypeAddressPair : {
1958 /*
1959 * Check "local" address
1960 */
1961 if (targetPrivate->localAddress != NULL) {
1962 /*
1963 * Check "local" address
1964 */
1965 ok = checkAddress(storeP, targetPrivate->localAddress, &my_flags, &my_index);
1966 if (!ok) {
1967 goto error; /* not today */
1968 }
1969
1970 if (!(my_flags & kSCNetworkFlagsIsLocalAddress)) {
1971 goto error; /* not reachable, non-"local" address */
1972 }
1973 }
1974
1975 /*
1976 * Check "remote" address
1977 */
1978 if (targetPrivate->remoteAddress != NULL) {
1979 /*
1980 * in cases where we have "local" and "remote" addresses
1981 * we need to re-initialize the to-be-returned flags.
1982 */
1983 my_flags = 0;
1984 my_index = 0;
1985
1986 /*
1987 * Check "remote" address
1988 */
1989 ok = checkAddress(storeP, targetPrivate->remoteAddress, &my_flags, &my_index);
1990 if (!ok) {
1991 goto error; /* not today */
1992 }
1993 }
1994
1995 break;
1996
1997 }
1998
1999 case reachabilityTypeName : {
2000 struct timeval dnsQueryStart;
2001 int error;
2002 struct addrinfo hints;
2003 SCNetworkConnectionFlags ns_flags;
2004 struct addrinfo *res;
2005
2006 addresses = (CFMutableArrayRef)SCNetworkReachabilityCopyResolvedAddress(target, &error);
2007 if ((addresses != NULL) || (error != NETDB_SUCCESS)) {
2008 /* if resolved or an error had been detected */
2009 goto checkResolvedAddress;
2010 }
2011
2012 /* check the reachability of the DNS servers */
2013 ok = _SC_checkResolverReachability(storeP,
2014 &ns_flags,
2015 &targetPrivate->haveDNS,
2016 targetPrivate->name);
2017 if (!ok) {
2018 /* if we could not get DNS server info */
2019 goto error;
2020 }
2021
2022 if (rankReachability(ns_flags) < 2) {
2023 /*
2024 * if DNS servers are not (or are no longer) reachable, set
2025 * flags based on the availability of configured (but not
2026 * active) services.
2027 */
2028
2029 SCLog(_sc_debug, LOG_INFO, CFSTR("DNS server(s) not available"));
2030
2031 if (!checkAddress(storeP, NULL, &my_flags, &my_index)) {
2032 goto error;
2033 }
2034
2035 if (async && (targetPrivate->rls != NULL)) {
2036 /*
2037 * return "host not found", set flags appropriately,
2038 * and schedule notification.
2039 */
2040 __SCNetworkReachabilityCallbackSetResolvedAddress(EAI_NONAME,
2041 NULL,
2042 (void *)target);
2043 my_flags |= (targetPrivate->flags & kSCNetworkFlagsFirstResolvePending);
2044
2045 SCLog(_sc_debug, LOG_INFO, CFSTR("no DNS servers are reachable"));
2046 CFRunLoopSourceSignal(targetPrivate->rls);
2047 _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
2048 }
2049 break;
2050 }
2051
2052 if (async) {
2053 /* for async requests we return the last known status */
2054 my_flags = targetPrivate->flags;
2055 my_index = targetPrivate->if_index;
2056
2057 if (targetPrivate->dnsPort != NULL) {
2058 /* if request already in progress */
2059 break;
2060 }
2061
2062 SCLog(_sc_debug, LOG_INFO, CFSTR("start DNS query for \"%s\""), targetPrivate->name);
2063
2064 /*
2065 * initiate an async DNS query
2066 */
2067 if (!startAsyncDNSQuery(target)) {
2068 /* if we could not initiate the request, process error */
2069 goto checkResolvedAddress;
2070 }
2071
2072 /* request initiated */
2073 break;
2074 }
2075
2076 SCLog(_sc_debug, LOG_INFO, CFSTR("check DNS for \"%s\""), targetPrivate->name);
2077
2078 /*
2079 * OK, all of the DNS name servers are available. Let's
2080 * resolve the nodename into an address.
2081 */
2082 if (_sc_debug) {
2083 (void) gettimeofday(&dnsQueryStart, NULL);
2084 }
2085
2086 bzero(&hints, sizeof(hints));
2087 hints.ai_flags = AI_ADDRCONFIG;
2088 #ifdef AI_PARALLEL
2089 hints.ai_flags |= AI_PARALLEL;
2090 #endif /* AI_PARALLEL */
2091
2092 error = getaddrinfo(targetPrivate->name, NULL, &hints, &res);
2093
2094 __log_query_time(((error == 0) && (res != NULL)),// if successful query
2095 FALSE, // sync
2096 &dnsQueryStart); // start time
2097
2098 __SCNetworkReachabilitySetResolvedAddress(error, res, target);
2099
2100 addresses = (CFMutableArrayRef)SCNetworkReachabilityCopyResolvedAddress(target, &error);
2101
2102 checkResolvedAddress :
2103
2104 /*
2105 * We first assume that the requested host is NOT available.
2106 * Then, check each address for accessibility and return the
2107 * best status available.
2108 */
2109 my_flags = 0;
2110 my_index = 0;
2111
2112 if (isA_CFArray(addresses)) {
2113 CFIndex i;
2114 CFIndex n = CFArrayGetCount(addresses);
2115
2116 for (i = 0; i < n; i++) {
2117 SCNetworkConnectionFlags ns_flags = 0;
2118 uint16_t ns_if_index = 0;
2119 struct sockaddr *sa;
2120
2121 sa = (struct sockaddr *)CFDataGetBytePtr(CFArrayGetValueAtIndex(addresses, i));
2122
2123 ok = checkAddress(storeP, sa, &ns_flags, &ns_if_index);
2124 if (!ok) {
2125 goto error; /* not today */
2126 }
2127
2128 if (rankReachability(ns_flags) > rankReachability(my_flags)) {
2129 /* return the best case result */
2130 my_flags = ns_flags;
2131 my_index = ns_if_index;
2132 if (rankReachability(my_flags) == 2) {
2133 /* we're in luck */
2134 break;
2135 }
2136 }
2137 }
2138 } else {
2139 if (((error == EAI_NONAME)
2140 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
2141 || (error == EAI_NODATA)
2142 #endif
2143 ) && !targetPrivate->haveDNS) {
2144 /*
2145 * No DNS servers are defined. Set flags based on
2146 * the availability of configured (but not active)
2147 * services.
2148 */
2149 ok = checkAddress(storeP, NULL, &my_flags, &my_index);
2150 if (!ok) {
2151 goto error; /* not today */
2152 }
2153
2154 if ((my_flags & kSCNetworkFlagsReachable) &&
2155 (my_flags & kSCNetworkFlagsConnectionRequired)) {
2156 /*
2157 * Since we might pick up a set of DNS servers when this connection
2158 * is established, don't reply with a "HOST NOT FOUND" error just yet.
2159 */
2160 break;
2161 }
2162
2163 /* Host not found, not reachable! */
2164 my_flags = 0;
2165 my_index = 0;
2166 }
2167 }
2168
2169 break;
2170 }
2171 }
2172
2173 *flags = my_flags;
2174 if (if_index != NULL) {
2175 *if_index = my_index;
2176 }
2177
2178 error :
2179
2180 if (addresses != NULL) CFRelease(addresses);
2181 return ok;
2182 }
2183
2184
2185 Boolean
2186 SCNetworkReachabilityGetFlags(SCNetworkReachabilityRef target,
2187 SCNetworkConnectionFlags *flags)
2188 {
2189 Boolean ok = TRUE;
2190 SCDynamicStoreRef store = NULL;
2191 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
2192
2193 if (!isA_SCNetworkReachability(target)) {
2194 _SCErrorSet(kSCStatusInvalidArgument);
2195 return FALSE;
2196 }
2197
2198 pthread_mutex_lock(&targetPrivate->lock);
2199
2200 if (targetPrivate->rlList != NULL) {
2201 // if being watched, return the last known (and what should be current) status
2202 *flags = targetPrivate->flags & ~kSCNetworkFlagsFirstResolvePending;
2203 goto done;
2204 }
2205
2206
2207 ok = __SCNetworkReachabilityGetFlags(&store, target, flags, NULL, FALSE);
2208 *flags &= ~kSCNetworkFlagsFirstResolvePending;
2209 if (store != NULL) CFRelease(store);
2210
2211 done :
2212
2213 pthread_mutex_unlock(&targetPrivate->lock);
2214 return ok;
2215 }
2216
2217
2218 static void
2219 __SCNetworkReachabilityReachabilitySetNotifications(SCDynamicStoreRef store)
2220 {
2221 CFStringRef key;
2222 CFMutableArrayRef keys;
2223 CFStringRef pattern;
2224 CFMutableArrayRef patterns;
2225
2226 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2227 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2228
2229 // Setup:/Network/Global/IPv4 (for the ServiceOrder)
2230 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2231 kSCDynamicStoreDomainSetup,
2232 kSCEntNetIPv4);
2233 CFArrayAppendValue(keys, key);
2234 CFRelease(key);
2235
2236 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2237 kSCDynamicStoreDomainState,
2238 kSCEntNetDNS);
2239 CFArrayAppendValue(keys, key);
2240 CFRelease(key);
2241
2242 // State:/Network/Global/IPv4 (default route)
2243 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2244 kSCDynamicStoreDomainState,
2245 kSCEntNetIPv4);
2246 CFArrayAppendValue(keys, key);
2247 CFRelease(key);
2248
2249 // Setup: per-service IPv4 info
2250 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
2251 kSCDynamicStoreDomainSetup,
2252 kSCCompAnyRegex,
2253 kSCEntNetIPv4);
2254 CFArrayAppendValue(patterns, pattern);
2255 CFRelease(pattern);
2256
2257 // Setup: per-service Interface info
2258 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
2259 kSCDynamicStoreDomainSetup,
2260 kSCCompAnyRegex,
2261 kSCEntNetInterface);
2262 CFArrayAppendValue(patterns, pattern);
2263 CFRelease(pattern);
2264
2265 // Setup: per-service PPP info (for kSCPropNetPPPDialOnDemand)
2266 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
2267 kSCDynamicStoreDomainSetup,
2268 kSCCompAnyRegex,
2269 kSCEntNetPPP);
2270 CFArrayAppendValue(patterns, pattern);
2271 CFRelease(pattern);
2272
2273 // State: per-interface IPv4 info
2274 pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
2275 kSCDynamicStoreDomainState,
2276 kSCCompAnyRegex,
2277 kSCEntNetIPv4);
2278 CFArrayAppendValue(patterns, pattern);
2279 CFRelease(pattern);
2280
2281 // State: per-interface IPv6 info
2282 pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
2283 kSCDynamicStoreDomainState,
2284 kSCCompAnyRegex,
2285 kSCEntNetIPv6);
2286 CFArrayAppendValue(patterns, pattern);
2287 CFRelease(pattern);
2288
2289 (void)SCDynamicStoreSetNotificationKeys(store, keys, patterns);
2290 CFRelease(keys);
2291 CFRelease(patterns);
2292
2293 return;
2294 }
2295
2296
2297 static void
2298 __SCNetworkReachabilityReachabilityHandleChanges(SCDynamicStoreRef store,
2299 CFArrayRef changedKeys,
2300 void *info)
2301 {
2302 Boolean dnsConfigChanged = FALSE;
2303 CFIndex i;
2304 CFStringRef key;
2305 CFIndex nTargets;
2306 const void * targets_q[N_QUICK];
2307 const void ** targets = targets_q;
2308
2309 pthread_mutex_lock(&hn_lock);
2310
2311 nTargets = CFSetGetCount(hn_targets);
2312 if (nTargets == 0) {
2313 /* if no addresses being monitored */
2314 goto done;
2315 }
2316
2317 if (CFArrayGetCount(changedKeys) == 0) {
2318 /* if no changes */
2319 goto done;
2320 }
2321
2322 SCLog(_sc_debug, LOG_INFO, CFSTR("process configuration change"));
2323
2324 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2325 kSCDynamicStoreDomainState,
2326 kSCEntNetDNS);
2327 if (CFArrayContainsValue(changedKeys,
2328 CFRangeMake(0, CFArrayGetCount(changedKeys)),
2329 key)) {
2330 dnsConfigChanged = TRUE; /* the DNS server(s) have changed */
2331 }
2332 CFRelease(key);
2333
2334 SCLog(_sc_debug && dnsConfigChanged, LOG_INFO, CFSTR(" DNS configuration changed"));
2335
2336 if (nTargets > (CFIndex)(sizeof(targets_q) / sizeof(CFTypeRef)))
2337 targets = CFAllocatorAllocate(NULL, nTargets * sizeof(CFTypeRef), 0);
2338 CFSetGetValues(hn_targets, targets);
2339 for (i = 0; i < nTargets; i++) {
2340 SCNetworkReachabilityRef target = targets[i];
2341 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
2342
2343 pthread_mutex_lock(&targetPrivate->lock);
2344
2345 if (targetPrivate->type == reachabilityTypeName) {
2346 Boolean dnsChanged = dnsConfigChanged;
2347
2348 if (!dnsChanged) {
2349 /*
2350 * if the DNS configuration didn't change we still need to
2351 * check that the DNS servers are accessible.
2352 */
2353 SCNetworkConnectionFlags ns_flags;
2354 Boolean ok;
2355
2356 /* check the reachability of the DNS servers */
2357 ok = _SC_checkResolverReachability(&store,
2358 &ns_flags,
2359 &targetPrivate->haveDNS,
2360 targetPrivate->name);
2361 if (!ok || (rankReachability(ns_flags) < 2)) {
2362 /* if DNS servers are not reachable */
2363 dnsChanged = TRUE;
2364 }
2365 }
2366
2367 if (dnsChanged) {
2368 if (targetPrivate->dnsPort != NULL) {
2369 /* cancel the outstanding DNS query */
2370 getaddrinfo_async_cancel(CFMachPortGetPort(targetPrivate->dnsPort));
2371 CFRunLoopSourceInvalidate(targetPrivate->dnsRLS);
2372 CFRelease(targetPrivate->dnsRLS);
2373 targetPrivate->dnsRLS = NULL;
2374 CFRelease(targetPrivate->dnsPort);
2375 targetPrivate->dnsPort = NULL;
2376 }
2377
2378 /* schedule request to resolve the name again */
2379 if (targetPrivate->resolvedAddress != NULL) {
2380 CFRelease(targetPrivate->resolvedAddress);
2381 targetPrivate->resolvedAddress = NULL;
2382 }
2383 targetPrivate->resolvedAddress = NULL;
2384 targetPrivate->resolvedAddressError = NETDB_SUCCESS;
2385 }
2386 }
2387
2388 CFRunLoopSourceSignal(targetPrivate->rls);
2389 _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
2390
2391 pthread_mutex_unlock(&targetPrivate->lock);
2392 }
2393 if (targets != targets_q) CFAllocatorDeallocate(NULL, targets);
2394
2395 done :
2396
2397 pthread_mutex_unlock(&hn_lock);
2398 return;
2399 }
2400
2401
2402 static void
2403 rlsPerform(void *info)
2404 {
2405 void *context_info;
2406 void (*context_release)(const void *);
2407 SCNetworkConnectionFlags flags;
2408 uint16_t if_index;
2409 Boolean ok;
2410 SCNetworkReachabilityCallBack rlsFunction;
2411 SCDynamicStoreRef store = NULL;
2412 SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)info;
2413 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
2414
2415 SCLog(_sc_debug, LOG_DEBUG, CFSTR("process reachability change"));
2416
2417
2418 pthread_mutex_lock(&targetPrivate->lock);
2419
2420 /* update reachability, notify if status changed */
2421 ok = __SCNetworkReachabilityGetFlags(&store, target, &flags, &if_index, TRUE);
2422 if (store != NULL) CFRelease(store);
2423 if (!ok) {
2424 /* if reachability status not available */
2425 flags = 0;
2426 if_index = 0;
2427 }
2428
2429 if ((targetPrivate->flags == flags) && (targetPrivate->if_index == if_index)) {
2430 /* if reachability flags and interface have not changed */
2431 pthread_mutex_unlock(&targetPrivate->lock);
2432 SCLog(_sc_debug, LOG_DEBUG,
2433 CFSTR("flags/interface match (now %8.8x/%hu)"),
2434 flags, if_index);
2435 return;
2436 } else {
2437 SCLog(_sc_debug, LOG_DEBUG,
2438 CFSTR("flags/interface have changed (was %8.8x/%hu, now %8.8x/%hu)"),
2439 targetPrivate->flags, targetPrivate->if_index,
2440 flags, if_index);
2441 }
2442
2443 /* update flags / interface */
2444 targetPrivate->flags = flags;
2445 targetPrivate->if_index = if_index;
2446
2447 /* callout */
2448 rlsFunction = targetPrivate->rlsFunction;
2449 if (targetPrivate->rlsContext.retain != NULL) {
2450 context_info = (void *)(*targetPrivate->rlsContext.retain)(targetPrivate->rlsContext.info);
2451 context_release = targetPrivate->rlsContext.release;
2452 } else {
2453 context_info = targetPrivate->rlsContext.info;
2454 context_release = NULL;
2455 }
2456
2457 pthread_mutex_unlock(&targetPrivate->lock);
2458
2459 if (rlsFunction != NULL) {
2460 (*rlsFunction)(target, flags, context_info);
2461 }
2462
2463 if (context_release != NULL) {
2464 (*context_release)(context_info);
2465 }
2466
2467 return;
2468 }
2469
2470
2471 Boolean
2472 SCNetworkReachabilitySetCallback(SCNetworkReachabilityRef target,
2473 SCNetworkReachabilityCallBack callout,
2474 SCNetworkReachabilityContext *context)
2475 {
2476 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
2477
2478 pthread_mutex_lock(&targetPrivate->lock);
2479
2480 if (targetPrivate->rlsContext.release != NULL) {
2481 /* let go of the current context */
2482 (*targetPrivate->rlsContext.release)(targetPrivate->rlsContext.info);
2483 }
2484
2485 targetPrivate->rlsFunction = callout;
2486 targetPrivate->rlsContext.info = NULL;
2487 targetPrivate->rlsContext.retain = NULL;
2488 targetPrivate->rlsContext.release = NULL;
2489 targetPrivate->rlsContext.copyDescription = NULL;
2490 if (context) {
2491 bcopy(context, &targetPrivate->rlsContext, sizeof(SCNetworkReachabilityContext));
2492 if (context->retain != NULL) {
2493 targetPrivate->rlsContext.info = (void *)(*context->retain)(context->info);
2494 }
2495 }
2496
2497 pthread_mutex_unlock(&targetPrivate->lock);
2498
2499 return TRUE;
2500 }
2501
2502
2503 static CFStringRef
2504 reachRLSCopyDescription(const void *info)
2505 {
2506 SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)info;
2507
2508 return CFStringCreateWithFormat(NULL,
2509 NULL,
2510 CFSTR("<SCNetworkReachability RLS> {target = %p}"),
2511 target);
2512 }
2513
2514
2515 Boolean
2516 SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef target,
2517 CFRunLoopRef runLoop,
2518 CFStringRef runLoopMode)
2519 {
2520 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
2521 Boolean init = FALSE;
2522 Boolean ok = FALSE;
2523
2524 if (!isA_SCNetworkReachability(target) || runLoop == NULL || runLoopMode == NULL) {
2525 _SCErrorSet(kSCStatusInvalidArgument);
2526 return FALSE;
2527 }
2528
2529 /* schedule the SCNetworkReachability run loop source */
2530
2531 pthread_mutex_lock(&hn_lock);
2532 pthread_mutex_lock(&targetPrivate->lock);
2533
2534 if (hn_store == NULL) {
2535 /*
2536 * if we are not monitoring any hosts, start watching
2537 */
2538 if (!dns_configuration_watch()) {
2539 // if error
2540 _SCErrorSet(kSCStatusFailed);
2541 goto done;
2542 }
2543
2544 hn_store = SCDynamicStoreCreate(NULL,
2545 CFSTR("SCNetworkReachability"),
2546 __SCNetworkReachabilityReachabilityHandleChanges,
2547 NULL);
2548 if (hn_store == NULL) {
2549 SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreCreate() failed"));
2550 goto done;
2551 }
2552
2553 __SCNetworkReachabilityReachabilitySetNotifications(hn_store);
2554
2555 hn_storeRLS = SCDynamicStoreCreateRunLoopSource(NULL, hn_store, 0);
2556 hn_rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2557 hn_targets = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2558 }
2559
2560 if (targetPrivate->rls == NULL) {
2561 CFRunLoopSourceContext context = { 0 // version
2562 , (void *)target // info
2563 , CFRetain // retain
2564 , CFRelease // release
2565 , reachRLSCopyDescription // copyDescription
2566 , CFEqual // equal
2567 , CFHash // hash
2568 , NULL // schedule
2569 , NULL // cancel
2570 , rlsPerform // perform
2571 };
2572
2573 targetPrivate->rls = CFRunLoopSourceCreate(NULL, 0, &context);
2574 targetPrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2575 init = TRUE;
2576 }
2577
2578 if (!_SC_isScheduled(NULL, runLoop, runLoopMode, targetPrivate->rlList)) {
2579 /*
2580 * if we do not already have host notifications scheduled with
2581 * this runLoop / runLoopMode
2582 */
2583 CFRunLoopAddSource(runLoop, targetPrivate->rls, runLoopMode);
2584
2585 if (targetPrivate->dnsRLS != NULL) {
2586 /* if we have an active async DNS query too */
2587 CFRunLoopAddSource(runLoop, targetPrivate->dnsRLS, runLoopMode);
2588 }
2589 }
2590
2591 _SC_schedule(target, runLoop, runLoopMode, targetPrivate->rlList);
2592
2593 /* schedule the SCNetworkReachability run loop source */
2594
2595 if (!_SC_isScheduled(NULL, runLoop, runLoopMode, hn_rlList)) {
2596 /*
2597 * if we do not already have SC notifications scheduled with
2598 * this runLoop / runLoopMode
2599 */
2600 CFRunLoopAddSource(runLoop, hn_storeRLS, runLoopMode);
2601 }
2602
2603 _SC_schedule(target, runLoop, runLoopMode, hn_rlList);
2604 CFSetAddValue(hn_targets, target);
2605
2606 if (init) {
2607 SCNetworkConnectionFlags flags;
2608 uint16_t if_index;
2609 SCDynamicStoreRef store = NULL;
2610
2611 /*
2612 * if we have yet to schedule SC notifications for this address
2613 * - initialize current reachability status
2614 */
2615 if (__SCNetworkReachabilityGetFlags(&store, target, &flags, &if_index, TRUE)) {
2616 /*
2617 * if reachability status available
2618 * - set flags
2619 * - schedule notification to report status via callback
2620 */
2621 targetPrivate->flags = flags;
2622 targetPrivate->if_index = if_index;
2623 CFRunLoopSourceSignal(targetPrivate->rls);
2624 _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
2625 } else {
2626 /* if reachability status not available, async lookup started */
2627 targetPrivate->flags = 0;
2628 targetPrivate->if_index = 0;
2629 }
2630 if (store != NULL) CFRelease(store);
2631 }
2632
2633 ok = TRUE;
2634
2635 done :
2636
2637 pthread_mutex_unlock(&targetPrivate->lock);
2638 pthread_mutex_unlock(&hn_lock);
2639 return ok;
2640 }
2641
2642
2643 Boolean
2644 SCNetworkReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef target,
2645 CFRunLoopRef runLoop,
2646 CFStringRef runLoopMode)
2647 {
2648 SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
2649 CFIndex n;
2650 Boolean ok = FALSE;
2651
2652 if (!isA_SCNetworkReachability(target) || runLoop == NULL || runLoopMode == NULL) {
2653 _SCErrorSet(kSCStatusInvalidArgument);
2654 return FALSE;
2655 }
2656
2657 pthread_mutex_lock(&hn_lock);
2658 pthread_mutex_lock(&targetPrivate->lock);
2659
2660 if (targetPrivate->rls == NULL) {
2661 /* if not currently scheduled */
2662 _SCErrorSet(kSCStatusInvalidArgument);
2663 goto done;
2664 }
2665
2666 if (!_SC_unschedule(NULL, runLoop, runLoopMode, targetPrivate->rlList, FALSE)) {
2667 /* if not currently scheduled */
2668 _SCErrorSet(kSCStatusInvalidArgument);
2669 goto done;
2670 }
2671
2672 n = CFArrayGetCount(targetPrivate->rlList);
2673 if (n == 0 || !_SC_isScheduled(NULL, runLoop, runLoopMode, targetPrivate->rlList)) {
2674 /*
2675 * if this host is no longer scheduled for this runLoop / runLoopMode
2676 */
2677 CFRunLoopRemoveSource(runLoop, targetPrivate->rls, runLoopMode);
2678
2679 if (targetPrivate->dnsRLS != NULL) {
2680 /* if we have an active async DNS query too */
2681 CFRunLoopRemoveSource(runLoop, targetPrivate->dnsRLS, runLoopMode);
2682 }
2683
2684 if (n == 0) {
2685 /*
2686 * if this host is no longer scheduled
2687 */
2688 CFRunLoopSourceInvalidate(targetPrivate->rls); /* cleanup SCNetworkReachability resources */
2689 CFRelease(targetPrivate->rls);
2690 targetPrivate->rls = NULL;
2691 CFRelease(targetPrivate->rlList);
2692 targetPrivate->rlList = NULL;
2693 CFSetRemoveValue(hn_targets, target); /* cleanup notification resources */
2694
2695 if (targetPrivate->dnsPort != NULL) {
2696 /* if we have an active async DNS query too */
2697 getaddrinfo_async_cancel(CFMachPortGetPort(targetPrivate->dnsPort));
2698 CFRunLoopSourceInvalidate(targetPrivate->dnsRLS);
2699 CFRelease(targetPrivate->dnsRLS);
2700 targetPrivate->dnsRLS = NULL;
2701 CFRelease(targetPrivate->dnsPort);
2702 targetPrivate->dnsPort = NULL;
2703 }
2704 }
2705 }
2706
2707 (void)_SC_unschedule(target, runLoop, runLoopMode, hn_rlList, FALSE);
2708
2709 n = CFArrayGetCount(hn_rlList);
2710 if (n == 0 || !_SC_isScheduled(NULL, runLoop, runLoopMode, hn_rlList)) {
2711 /*
2712 * if we no longer have any addresses scheduled for
2713 * this runLoop / runLoopMode
2714 */
2715 CFRunLoopRemoveSource(runLoop, hn_storeRLS, runLoopMode);
2716
2717 if (n == 0) {
2718 /*
2719 * if we are no longer monitoring any addresses
2720 */
2721 CFRelease(hn_targets);
2722 hn_targets = NULL;
2723 CFRelease(hn_rlList);
2724 hn_rlList = NULL;
2725 CFRunLoopSourceInvalidate(hn_storeRLS);
2726 CFRelease(hn_storeRLS);
2727 hn_storeRLS = NULL;
2728 CFRelease(hn_store);
2729 hn_store = NULL;
2730
2731 /*
2732 * until we start monitoring again, ensure that
2733 * any resources associated with tracking the
2734 * DNS configuration have been released.
2735 */
2736 dns_configuration_unwatch();
2737 }
2738 }
2739
2740 ok = TRUE;
2741
2742 done :
2743
2744 pthread_mutex_unlock(&targetPrivate->lock);
2745 pthread_mutex_unlock(&hn_lock);
2746 return ok;
2747 }