]> git.saurik.com Git - apple/configd.git/blobdiff - SystemConfiguration.fproj/SCNetworkReachability.c
configd-137.2.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkReachability.c
index e5a1e51cfafddd9479fe47bbd03160257aa07800..f28d6f3cd7db6999dcd4d98313ef60b6a0e3a622 100644 (file)
@@ -1,10 +1,8 @@
 /*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003-2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
- * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -26,6 +24,9 @@
 /*
  * Modification History
  *
+ * March 31, 2004              Allan Nathanson <ajn@apple.com>
+ * - use [SC] DNS configuration information
+ *
  * January 19, 2003            Allan Nathanson <ajn@apple.com>
  * - add advanced reachability APIs
  */
 #include <CoreFoundation/CFRuntime.h>
 #include <pthread.h>
 
+#include <notify.h>
+#include <dnsinfo.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
-#include <arpa/nameser.h>
 #include <netdb.h>
 #include <netdb_async.h>
 #include <resolv.h>
@@ -56,7 +58,9 @@
 #define s6_addr16 __u6_addr.__u6_addr16
 #endif
 
-#include "ppp.h"
+#include <ppp/ppp_msg.h>
+
+
 
 
 #define kSCNetworkFlagsFirstResolvePending     (1<<31)
@@ -106,9 +110,11 @@ typedef struct {
        SCNetworkReachabilityContext    rlsContext;
        CFMutableArrayRef               rlList;
 
-       /* async DNS query info */
+       /* [async] DNS query info */
+       Boolean                         haveDNS;
        CFMachPortRef                   dnsPort;
        CFRunLoopSourceRef              dnsRLS;
+       struct timeval                  dnsQueryStart;
 
 } SCNetworkReachabilityPrivate, *SCNetworkReachabilityPrivateRef;
 
@@ -130,10 +136,12 @@ static const CFRuntimeClass __SCNetworkReachabilityClass = {
 
 
 static pthread_once_t          initialized     = PTHREAD_ONCE_INIT;
-static Boolean                 needDNS         = TRUE;
 
 
-/* host "something has changed" notifications */
+/*
+ * host "something has changed" notifications
+ */
+
 static pthread_mutex_t         hn_lock         = PTHREAD_MUTEX_INITIALIZER;
 static SCDynamicStoreRef       hn_store        = NULL;
 static CFRunLoopSourceRef      hn_storeRLS     = NULL;
@@ -141,161 +149,52 @@ static CFMutableArrayRef hn_rlList       = NULL;
 static CFMutableSetRef         hn_targets      = NULL;
 
 
-static __inline__ CFTypeRef
-isA_SCNetworkReachability(CFTypeRef obj)
-{
-       return (isA_CFType(obj, SCNetworkReachabilityGetTypeID()));
-}
+/*
+ * DNS configuration
+ */
 
+typedef struct {
+       dns_config_t    *config;
+       int             refs;
+} dns_configuration_t;
 
-static void
-sockaddr_to_string(const struct sockaddr *address, char *buf, size_t bufLen)
-{
-       bzero(buf, bufLen);
-       switch (address->sa_family) {
-               case AF_INET :
-                       (void)inet_ntop(((struct sockaddr_in *)address)->sin_family,
-                                       &((struct sockaddr_in *)address)->sin_addr,
-                                       buf,
-                                       bufLen);
-                       break;
-               case AF_INET6 : {
-                       (void)inet_ntop(((struct sockaddr_in6 *)address)->sin6_family,
-                                       &((struct sockaddr_in6 *)address)->sin6_addr,
-                                       buf,
-                                       bufLen);
-                       if (((struct sockaddr_in6 *)address)->sin6_scope_id != 0) {
-                               int     n;
-
-                               n = strlen(buf);
-                               if ((n+IF_NAMESIZE+1) <= (int)bufLen) {
-                                       buf[n++] = '%';
-                                       if_indextoname(((struct sockaddr_in6 *)address)->sin6_scope_id, &buf[n]);
-                               }
-                       }
-                       break;
-               }
-               case AF_LINK :
-                       if (((struct sockaddr_dl *)address)->sdl_len < bufLen) {
-                               bufLen = ((struct sockaddr_dl *)address)->sdl_len;
-                       } else {
-                               bufLen = bufLen - 1;
-                       }
 
-                       bcopy(((struct sockaddr_dl *)address)->sdl_data, buf, bufLen);
-                       break;
-               default :
-                       snprintf(buf, bufLen, "unexpected address family %d", address->sa_family);
-                       break;
-       }
+static pthread_mutex_t         dns_lock                = PTHREAD_MUTEX_INITIALIZER;
+static dns_configuration_t     *dns_configuration      = NULL;
+static int                     dns_token;
+static Boolean                 dns_token_valid         = FALSE;
 
-       return;
-}
 
-
-#ifndef        CHECK_IPV6_REACHABILITY
-static char *
-__netdb_error(int error)
+static __inline__ CFTypeRef
+isA_SCNetworkReachability(CFTypeRef obj)
 {
-       char    *msg;
-
-       switch(error) {
-               case NETDB_INTERNAL :
-                       msg = strerror(errno);
-                       break;
-               case HOST_NOT_FOUND :
-                       msg = "Host not found.";
-                       break;
-               case TRY_AGAIN :
-                       msg = "Try again.";
-                       break;
-               case NO_RECOVERY :
-                       msg = "No recovery.";
-                       break;
-               case NO_DATA :
-                       msg = "No data available.";
-                       break;
-               default :
-                       msg = "Unknown";
-                       break;
-       }
-
-       return msg;
+       return (isA_CFType(obj, SCNetworkReachabilityGetTypeID()));
 }
-#endif /* CHECK_IPV6_REACHABILITY */
 
 
 static void
-__signalRunLoop(CFTypeRef obj, CFRunLoopSourceRef rls, CFArrayRef rlList)
+__log_query_time(Boolean found, Boolean async, struct timeval *start)
 {
-       CFRunLoopRef    rl      = NULL;
-       CFRunLoopRef    rl1     = NULL;
-       CFIndex         i;
-       CFIndex         n       = CFArrayGetCount(rlList);
-
-       if (n == 0) {
-               return;
-       }
-
-       /* get first runLoop for this object */
-       for (i = 0; i < n; i += 3) {
-               if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
-                       continue;
-               }
+       struct timeval  dnsQueryComplete;
+       struct timeval  dnsQueryElapsed;
 
-               rl1 = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
-               break;
-       }
-
-       if (!rl1) {
-               /* if not scheduled */
+       if (!_sc_debug) {
                return;
        }
 
-       /* check if we have another runLoop for this object */
-       rl = rl1;
-       for (i = i+3; i < n; i += 3) {
-               CFRunLoopRef    rl2;
-
-               if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
-                       continue;
-               }
-
-               rl2 = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
-               if (!CFEqual(rl1, rl2)) {
-                       /* we've got more than one runLoop */
-                       rl = NULL;
-                       break;
-               }
-       }
-
-       if (rl) {
-               /* if we only have one runLoop */
-               CFRunLoopWakeUp(rl);
+       if (start->tv_sec == 0) {
                return;
        }
 
-       /* more than one different runLoop, so we must pick one */
-       for (i = 0; i < n; i+=3) {
-               CFStringRef     rlMode;
+       (void) gettimeofday(&dnsQueryComplete, NULL);
+       timersub(&dnsQueryComplete, start, &dnsQueryElapsed);
+       SCLog(TRUE, LOG_DEBUG,
+             CFSTR("%ssync DNS complete%s (query time = %d.%3.3d)"),
+             async ? "a" : "",
+             found ? "" : ", host not found",
+             dnsQueryElapsed.tv_sec,
+             dnsQueryElapsed.tv_usec / 1000);
 
-               if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
-                       continue;
-               }
-
-               rl     = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
-               rlMode = CFRunLoopCopyCurrentMode(rl);
-               if (rlMode && CFRunLoopIsWaiting(rl) && CFRunLoopContainsSource(rl, rls, rlMode)) {
-                       /* we've found a runLoop that's "ready" */
-                       CFRelease(rlMode);
-                       CFRunLoopWakeUp(rl);
-                       return;
-               }
-               if (rlMode) CFRelease(rlMode);
-       }
-
-       /* didn't choose one above, so choose first */
-       CFRunLoopWakeUp(rl1);
        return;
 }
 
@@ -314,7 +213,7 @@ updatePPPStatus(SCDynamicStoreRef           *storeP,
        CFIndex                 n;
        CFStringRef             ppp_if;
        int                     sc_status       = kSCStatusReachabilityUnknown;
-       SCDynamicStoreRef       store           = (storeP) ? *storeP : NULL;
+       SCDynamicStoreRef       store           = (storeP != NULL) ? *storeP : NULL;
        const void *            values_q[N_QUICK];
        const void **           values  = values_q;
 
@@ -329,10 +228,10 @@ updatePPPStatus(SCDynamicStoreRef         *storeP,
                        goto done;
        }
 
-       if (!store) {
+       if (store == NULL) {
                store = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkReachability"), NULL, NULL);
-               if (!store) {
-                       SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreCreate() failed"));
+               if (store == NULL) {
+                       SCLog(_sc_verbose, LOG_INFO, CFSTR("updatePPPStatus SCDynamicStoreCreate() failed"));
                        goto done;
                }
        }
@@ -366,7 +265,7 @@ updatePPPStatus(SCDynamicStoreRef           *storeP,
                dict = SCDynamicStoreCopyMultiple(store, NULL, patterns);
                CFRelease(patterns);
        }
-       if (!dict) {
+       if (dict == NULL) {
                /* if we could not access the dynamic store */
                goto done;
        }
@@ -504,16 +403,16 @@ updatePPPStatus(SCDynamicStoreRef         *storeP,
 
     done :
 
-       if (dict)       CFRelease(dict);
-       if (storeP)     *storeP = store;
+       if (dict != NULL)       CFRelease(dict);
+       if (storeP != NULL)     *storeP = store;
        return sc_status;
 }
 
 
 static int
 updatePPPAvailable(SCDynamicStoreRef           *storeP,
-                 const struct sockaddr         *sa,
-                 SCNetworkConnectionFlags      *flags)
+                  const struct sockaddr        *sa,
+                  SCNetworkConnectionFlags     *flags)
 {
        CFDictionaryRef         dict            = NULL;
        CFStringRef             entity;
@@ -522,25 +421,29 @@ updatePPPAvailable(SCDynamicStoreRef              *storeP,
        const void **           keys            = keys_q;
        CFIndex                 n;
        int                     sc_status       = kSCStatusReachabilityUnknown;
-       SCDynamicStoreRef       store           = (storeP) ? *storeP : NULL;
+       SCDynamicStoreRef       store           = (storeP != NULL) ? *storeP : NULL;
        const void *            values_q[N_QUICK];
        const void **           values  = values_q;
 
-       switch (sa->sa_family) {
-               case AF_INET :
-                       entity = kSCEntNetIPv4;
-                       break;
-               case AF_INET6 :
-                       entity = kSCEntNetIPv6;
-                       break;
-               default :
-                       goto done;
+       if (sa == NULL) {
+               entity = kSCEntNetIPv4;
+       } else {
+               switch (sa->sa_family) {
+                       case AF_INET :
+                               entity = kSCEntNetIPv4;
+                               break;
+                       case AF_INET6 :
+                               entity = kSCEntNetIPv6;
+                               break;
+                       default :
+                               goto done;
+               }
        }
 
-       if (!store) {
+       if (store == NULL) {
                store = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkReachability"), NULL, NULL);
-               if (!store) {
-                       SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreCreate() failed"));
+               if (store == NULL) {
+                       SCLog(_sc_debug, LOG_INFO, CFSTR("  status    = unknown (could not access SCDynamicStore"));
                        goto done;
                }
        }
@@ -568,7 +471,7 @@ updatePPPAvailable(SCDynamicStoreRef                *storeP,
                dict = SCDynamicStoreCopyMultiple(store, NULL, patterns);
                CFRelease(patterns);
        }
-       if (!dict) {
+       if (dict == NULL) {
                /* if we could not access the dynamic store */
                goto done;
        }
@@ -669,8 +572,8 @@ updatePPPAvailable(SCDynamicStoreRef                *storeP,
 
     done :
 
-       if (dict)       CFRelease(dict);
-       if (storeP)     *storeP = store;
+       if (dict != NULL)       CFRelease(dict);
+       if (storeP != NULL)     *storeP = store;
        return sc_status;
 }
 
@@ -719,7 +622,7 @@ checkAddress(SCDynamicStoreRef              *storeP,
        int                     sc_status       = kSCStatusReachabilityUnknown;
        struct sockaddr_dl      *sdl;
        int                     seq             = (int)pthread_self();
-       SCDynamicStoreRef       store           = (storeP) ? *storeP : NULL;
+       SCDynamicStoreRef       store           = (storeP != NULL) ? *storeP : NULL;
        char                    *statusMessage  = NULL;
 #ifndef        RTM_GET_SILENT
 #warning Note: Using RTM_GET (and not RTM_GET_SILENT)
@@ -727,16 +630,21 @@ checkAddress(SCDynamicStoreRef            *storeP,
        int                     sosize          = 48 * 1024;
 #endif
 
-       if (!address || !flags) {
-               sc_status = kSCStatusInvalidArgument;
-               goto done;
+       *flags = 0;
+       if (if_index != NULL) {
+               *if_index = 0;
+       }
+
+       if (address == NULL) {
+               /* special case: check only for available paths off the system */
+               goto checkAvailable;
        }
 
        switch (address->sa_family) {
                case AF_INET :
                case AF_INET6 :
                        if (_sc_debug) {
-                               sockaddr_to_string(address, buf, sizeof(buf));
+                               _SC_sockaddr_to_string(address, buf, sizeof(buf));
                                SCLog(TRUE, LOG_INFO, CFSTR("checkAddress(%s)"), buf);
                        }
                        break;
@@ -751,16 +659,6 @@ checkAddress(SCDynamicStoreRef             *storeP,
                        goto done;
        }
 
-       *flags = 0;
-       if (if_index) {
-               *if_index = 0;
-       }
-
-       if ((address->sa_family == AF_INET) && (((struct sockaddr_in *)address)->sin_addr.s_addr == 0)) {
-               /* special case: check for available paths off the system */
-               goto checkAvailable;
-       }
-
        bzero(&buf, sizeof(buf));
 
        rtm = (struct rt_msghdr *)&buf;
@@ -879,7 +777,7 @@ checkAddress(SCDynamicStoreRef              *storeP,
 
        for (i = 0; i < RTAX_MAX; i++) {
                if (rti_info[i] != NULL) {
-                       sockaddr_to_string(rti_info[i], buf, sizeof(buf));
+                       _SC_sockaddr_to_string(rti_info[i], buf, sizeof(buf));
                        SCLog(_sc_debug, LOG_DEBUG, CFSTR("%d: %s"), i, buf);
                }
        }
@@ -889,19 +787,19 @@ checkAddress(SCDynamicStoreRef            *storeP,
        if ((rti_info[RTAX_IFP] == NULL) ||
            (rti_info[RTAX_IFP]->sa_family != AF_LINK)) {
                /* no interface info */
-               goto done;      // ???
+               goto done;
        }
 
        sdl = (struct sockaddr_dl *) rti_info[RTAX_IFP];
        if ((sdl->sdl_nlen == 0) || (sdl->sdl_nlen > IFNAMSIZ)) {
                /* no interface name */
-               goto done;      // ???
+               goto checkAvailable;
        }
 
        /* get the interface flags */
 
        bzero(&ifr, sizeof(ifr));
-       bcopy(sdl->sdl_data, ifr.ifr_name, sdl->sdl_len);
+       bcopy(sdl->sdl_data, ifr.ifr_name, sdl->sdl_nlen);
 
        isock = socket(AF_INET, SOCK_DGRAM, 0);
        if (isock < 0) {
@@ -950,6 +848,14 @@ checkAddress(SCDynamicStoreRef             *storeP,
                                addr1 = &((struct sockaddr_in *)address)->sin_addr;
                                addr2 = &((struct sockaddr_in *)rti_info[RTAX_IFA])->sin_addr;
                                len = sizeof(struct in_addr);
+
+                               /*
+                                * check if 0.0.0.0
+                                */
+                               if (((struct sockaddr_in *)address)->sin_addr.s_addr == 0) {
+                                       statusMessage = "isReachable (this host)";
+                                       *flags |= kSCNetworkFlagsIsLocalAddress;
+                               }
                                break;
                        case AF_INET6 :
                                addr1 = &((struct sockaddr_in6 *)address)->sin6_addr;
@@ -966,16 +872,19 @@ checkAddress(SCDynamicStoreRef            *storeP,
                }
        }
 
-       if (rti_info[RTAX_GATEWAY] && (rti_info[RTAX_GATEWAY]->sa_family == AF_LINK)) {
+       if (!(rtm->rtm_flags & RTF_GATEWAY) &&
+           (rti_info[RTAX_GATEWAY] != NULL) &&
+           (rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) &&
+           !(ifr.ifr_flags & IFF_POINTOPOINT)) {
                *flags |= kSCNetworkFlagsIsDirect;
        }
 
        bzero(&if_name, sizeof(if_name));
        bcopy(sdl->sdl_data,
              if_name,
-             (sdl->sdl_len <= IFNAMSIZ) ? sdl->sdl_len : IFNAMSIZ);
+             (sdl->sdl_nlen <= IFNAMSIZ) ? sdl->sdl_nlen : IFNAMSIZ);
 
-       if (if_index) {
+       if (if_index != NULL) {
                *if_index = sdl->sdl_index;
        }
 
@@ -1014,7 +923,7 @@ checkAddress(SCDynamicStoreRef             *storeP,
                SCLog(_sc_debug, LOG_INFO, CFSTR("  cannot be reached"));
        }
 
-       if (storeP)             *storeP = store;
+       if (storeP != NULL)     *storeP = store;
        if (sc_status != kSCStatusOK) {
                _SCErrorSet(sc_status);
                return FALSE;
@@ -1024,47 +933,6 @@ checkAddress(SCDynamicStoreRef            *storeP,
 }
 
 
-static Boolean
-checkAddressZero(SCDynamicStoreRef             *storeP,
-                SCNetworkConnectionFlags       *flags,
-                uint16_t                       *if_index)
-{
-       Boolean                 ok;
-       struct sockaddr_in      sin;
-
-       bzero(&sin, sizeof(sin));
-       sin.sin_len         = sizeof(sin);
-       sin.sin_family      = AF_INET;
-       sin.sin_addr.s_addr = 0;
-
-       ok = checkAddress(storeP, (struct sockaddr *)&sin, flags, if_index);
-
-       return ok;
-}
-
-
-static Boolean
-isAddressZero(struct sockaddr *sa, SCNetworkConnectionFlags *flags)
-{
-       /*
-        * Check if 0.0.0.0
-        */
-       if (sa->sa_family == AF_INET) {
-               struct sockaddr_in      *sin = (struct sockaddr_in *)sa;
-
-               if (sin->sin_addr.s_addr == 0) {
-                       SCLog(_sc_debug, LOG_INFO, CFSTR("isAddressZero(0.0.0.0)"));
-                       SCLog(_sc_debug, LOG_INFO, CFSTR("  status     = isReachable (this host)"));
-                       *flags |= kSCNetworkFlagsReachable;
-                       *flags |= kSCNetworkFlagsIsLocalAddress;
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
-
-
 static CFStringRef
 __SCNetworkReachabilityCopyDescription(CFTypeRef cf)
 {
@@ -1079,14 +947,14 @@ __SCNetworkReachabilityCopyDescription(CFTypeRef cf)
                case reachabilityTypeAddressPair : {
                        char            buf[64];
 
-                       if (targetPrivate->localAddress) {
-                               sockaddr_to_string(targetPrivate->localAddress, buf, sizeof(buf));
+                       if (targetPrivate->localAddress != NULL) {
+                               _SC_sockaddr_to_string(targetPrivate->localAddress, buf, sizeof(buf));
                                CFStringAppendFormat(result, NULL, CFSTR("local address=%s"),
                                                     buf);
                        }
 
-                       if (targetPrivate->remoteAddress) {
-                               sockaddr_to_string(targetPrivate->remoteAddress, buf, sizeof(buf));
+                       if (targetPrivate->remoteAddress != NULL) {
+                               _SC_sockaddr_to_string(targetPrivate->remoteAddress, buf, sizeof(buf));
                                CFStringAppendFormat(result, NULL, CFSTR("%s%saddress=%s"),
                                                     targetPrivate->localAddress ? ", " : "",
                                                     (targetPrivate->type == reachabilityTypeAddressPair) ? "remote " : "",
@@ -1097,7 +965,7 @@ __SCNetworkReachabilityCopyDescription(CFTypeRef cf)
                case reachabilityTypeName : {
                        CFStringAppendFormat(result, NULL, CFSTR("name=%s"), targetPrivate->name);
                        if (targetPrivate->resolvedAddress || (targetPrivate->resolvedAddressError != NETDB_SUCCESS)) {
-                               if (targetPrivate->resolvedAddress) {
+                               if (targetPrivate->resolvedAddress != NULL) {
                                        if (isA_CFArray(targetPrivate->resolvedAddress)) {
                                                CFIndex i;
                                                CFIndex n       = CFArrayGetCount(targetPrivate->resolvedAddress);
@@ -1110,7 +978,7 @@ __SCNetworkReachabilityCopyDescription(CFTypeRef cf)
 
                                                        address = CFArrayGetValueAtIndex(targetPrivate->resolvedAddress, i);
                                                        sa      = (struct sockaddr *)CFDataGetBytePtr(address);
-                                                       sockaddr_to_string(sa, buf, sizeof(buf));
+                                                       _SC_sockaddr_to_string(sa, buf, sizeof(buf));
                                                        CFStringAppendFormat(result, NULL, CFSTR("%s%s"),
                                                                             i > 0 ? ", " : "",
                                                                             buf);
@@ -1120,13 +988,8 @@ __SCNetworkReachabilityCopyDescription(CFTypeRef cf)
                                                CFStringAppendFormat(result, NULL, CFSTR(" (no addresses)"));
                                        }
                                } else {
-#ifdef CHECK_IPV6_REACHABILITY
                                        CFStringAppendFormat(result, NULL, CFSTR(" (%s)"),
                                                             gai_strerror(targetPrivate->resolvedAddressError));
-#else  /* CHECK_IPV6_REACHABILITY */
-                                       CFStringAppendFormat(result, NULL, CFSTR(" (%s)"),
-                                                            __netdb_error(targetPrivate->resolvedAddressError));
-#endif /* CHECK_IPV6_REACHABILITY */
                                }
                        } else if (targetPrivate->dnsPort) {
                                CFStringAppendFormat(result, NULL, CFSTR(" (DNS query active)"));
@@ -1134,7 +997,7 @@ __SCNetworkReachabilityCopyDescription(CFTypeRef cf)
                        break;
                }
        }
-       if (targetPrivate->rls) {
+       if (targetPrivate->rls != NULL) {
                CFStringAppendFormat(result,
                                     NULL,
                                     CFSTR(", flags=%8.8x, if_index=%hu"),
@@ -1152,26 +1015,24 @@ __SCNetworkReachabilityDeallocate(CFTypeRef cf)
 {
        SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)cf;
 
-       SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCNetworkReachabilityDeallocate:"));
-
        /* release resources */
 
        pthread_mutex_destroy(&targetPrivate->lock);
 
-       if (targetPrivate->name)
+       if (targetPrivate->name != NULL)
                CFAllocatorDeallocate(NULL, (void *)targetPrivate->name);
 
-       if (targetPrivate->resolvedAddress)
+       if (targetPrivate->resolvedAddress != NULL)
                CFRelease(targetPrivate->resolvedAddress);
 
-       if (targetPrivate->localAddress)
+       if (targetPrivate->localAddress != NULL)
                CFAllocatorDeallocate(NULL, (void *)targetPrivate->localAddress);
 
-       if (targetPrivate->remoteAddress)
+       if (targetPrivate->remoteAddress != NULL)
                CFAllocatorDeallocate(NULL, (void *)targetPrivate->remoteAddress);
 
-       if (targetPrivate->rlsContext.release) {
-               targetPrivate->rlsContext.release(targetPrivate->rlsContext.info);
+       if (targetPrivate->rlsContext.release != NULL) {
+               (*targetPrivate->rlsContext.release)(targetPrivate->rlsContext.info);
        }
 
        return;
@@ -1195,15 +1056,13 @@ __SCNetworkReachabilityCreatePrivate(CFAllocatorRef     allocator)
        /* initialize runtime */
        pthread_once(&initialized, __SCNetworkReachabilityInitialize);
 
-       SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCNetworkReachabilityCreatePrivate:"));
-
        /* allocate target */
        size          = sizeof(SCNetworkReachabilityPrivate) - sizeof(CFRuntimeBase);
        targetPrivate = (SCNetworkReachabilityPrivateRef)_CFRuntimeCreateInstance(allocator,
                                                                                  __kSCNetworkReachabilityTypeID,
                                                                                  size,
                                                                                  NULL);
-       if (!targetPrivate) {
+       if (targetPrivate == NULL) {
                return NULL;
        }
 
@@ -1228,6 +1087,7 @@ __SCNetworkReachabilityCreatePrivate(CFAllocatorRef       allocator)
        targetPrivate->rlsContext.copyDescription       = NULL;
        targetPrivate->rlList                           = NULL;
 
+       targetPrivate->haveDNS                          = FALSE;
        targetPrivate->dnsPort                          = NULL;
        targetPrivate->dnsRLS                           = NULL;
 
@@ -1241,7 +1101,7 @@ SCNetworkReachabilityCreateWithAddress(CFAllocatorRef             allocator,
 {
        SCNetworkReachabilityPrivateRef targetPrivate;
 
-       if (!address ||
+       if ((address == NULL) ||
            (address->sa_len == 0) ||
            (address->sa_len > sizeof(struct sockaddr_storage))) {
                _SCErrorSet(kSCStatusInvalidArgument);
@@ -1249,7 +1109,7 @@ SCNetworkReachabilityCreateWithAddress(CFAllocatorRef             allocator,
        }
 
        targetPrivate = __SCNetworkReachabilityCreatePrivate(allocator);
-       if (!targetPrivate) {
+       if (targetPrivate == NULL) {
                return NULL;
        }
 
@@ -1273,7 +1133,7 @@ SCNetworkReachabilityCreateWithAddressPair(CFAllocatorRef         allocator,
                return NULL;
        }
 
-       if (localAddress) {
+       if (localAddress != NULL) {
                if ((localAddress->sa_len == 0) ||
                    (localAddress->sa_len > sizeof(struct sockaddr_storage))) {
                            _SCErrorSet(kSCStatusInvalidArgument);
@@ -1281,7 +1141,7 @@ SCNetworkReachabilityCreateWithAddressPair(CFAllocatorRef         allocator,
                }
        }
 
-       if (remoteAddress) {
+       if (remoteAddress != NULL) {
                if ((remoteAddress->sa_len == 0) ||
                    (remoteAddress->sa_len > sizeof(struct sockaddr_storage))) {
                            _SCErrorSet(kSCStatusInvalidArgument);
@@ -1290,18 +1150,18 @@ SCNetworkReachabilityCreateWithAddressPair(CFAllocatorRef               allocator,
        }
 
        targetPrivate = __SCNetworkReachabilityCreatePrivate(allocator);
-       if (!targetPrivate) {
+       if (targetPrivate == NULL) {
                return NULL;
        }
 
        targetPrivate->type = reachabilityTypeAddressPair;
 
-       if (localAddress) {
+       if (localAddress != NULL) {
                targetPrivate->localAddress = CFAllocatorAllocate(NULL, localAddress->sa_len, 0);
                bcopy(localAddress, targetPrivate->localAddress, localAddress->sa_len);
        }
 
-       if (remoteAddress) {
+       if (remoteAddress != NULL) {
                targetPrivate->remoteAddress = CFAllocatorAllocate(NULL, remoteAddress->sa_len, 0);
                bcopy(remoteAddress, targetPrivate->remoteAddress, remoteAddress->sa_len);
        }
@@ -1314,15 +1174,42 @@ SCNetworkReachabilityRef
 SCNetworkReachabilityCreateWithName(CFAllocatorRef     allocator,
                                    const char          *nodename)
 {
+       struct sockaddr_in              sin;
+       struct sockaddr_in6             sin6;
        SCNetworkReachabilityPrivateRef targetPrivate;
 
-       if (!nodename) {
+       if (nodename == NULL) {
                _SCErrorSet(kSCStatusInvalidArgument);
                return NULL;
        }
 
+       /* check if this "nodename" is really an IP[v6] address in disguise */
+
+       bzero(&sin, sizeof(sin));
+       sin.sin_len    = sizeof(sin);
+       sin.sin_family = AF_INET;
+       if (inet_aton(nodename, &sin.sin_addr) == 1) {
+               /* if IPv4 address */
+               return SCNetworkReachabilityCreateWithAddress(allocator, (struct sockaddr *)&sin);
+       }
+
+       bzero(&sin6, sizeof(sin6));
+       sin6.sin6_len    = sizeof(sin6);
+       sin6.sin6_family = AF_INET6;
+       if (inet_pton(AF_INET6, nodename, &sin6.sin6_addr) == 1) {
+               /* if IPv6 address */
+               char    *p;
+
+               p = strchr(nodename, '%');
+               if (p != NULL) {
+                       sin6.sin6_scope_id = if_nametoindex(p+1);
+               }
+
+               return SCNetworkReachabilityCreateWithAddress(allocator, (struct sockaddr *)&sin6);
+       }
+
        targetPrivate = __SCNetworkReachabilityCreatePrivate(allocator);
-       if (!targetPrivate) {
+       if (targetPrivate == NULL) {
                return NULL;
        }
 
@@ -1366,7 +1253,7 @@ SCNetworkReachabilityCopyResolvedAddress(SCNetworkReachabilityRef target,
        }
 
        if (targetPrivate->resolvedAddress || (targetPrivate->resolvedAddressError != NETDB_SUCCESS)) {
-               if (targetPrivate->resolvedAddress) {
+               if (targetPrivate->resolvedAddress != NULL) {
                        return CFRetain(targetPrivate->resolvedAddress);
                } else {
                        /* if status is known but no resolved addresses to return */
@@ -1381,37 +1268,20 @@ SCNetworkReachabilityCopyResolvedAddress(SCNetworkReachabilityRef       target,
 
 
 static void
-__SCNetworkReachabilitySetResolvedAddress(SCNetworkReachabilityRef     target,
-                                         CFArrayRef                    addresses,
-                                         int                           error_num)
+__SCNetworkReachabilitySetResolvedAddress(int32_t                      status,
+                                         struct addrinfo               *res,
+                                         SCNetworkReachabilityRef      target)
 {
-       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
-
-       if (targetPrivate->resolvedAddress) {
-               CFRelease(targetPrivate->resolvedAddress);
-       }
-       targetPrivate->resolvedAddress      = addresses ? CFRetain(addresses) : NULL;
-       targetPrivate->resolvedAddressError = error_num;
-       return;
-}
-
-
-#ifdef CHECK_IPV6_REACHABILITY
-static void
-__SCNetworkReachabilityCallbackSetResolvedAddress(int32_t status, struct addrinfo *res, void *context)
-{
-       Boolean                                 ok;
        struct addrinfo                         *resP;
-       SCNetworkReachabilityRef                target          = (SCNetworkReachabilityRef)context;
        SCNetworkReachabilityPrivateRef         targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
-       ok = (status == 0) && (res != NULL);
+       if (targetPrivate->resolvedAddress != NULL) {
+               CFRelease(targetPrivate->resolvedAddress);
+               targetPrivate->resolvedAddress = NULL;
+       }
 
-       SCLog(_sc_debug, LOG_DEBUG,
-             CFSTR("process async DNS complete%s"),
-             ok ? "" : ", host not found");
+       if ((status == 0) && (res != NULL)) {
 
-       if (ok) {
                CFMutableArrayRef       addresses;
 
                addresses = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
@@ -1425,94 +1295,41 @@ __SCNetworkReachabilityCallbackSetResolvedAddress(int32_t status, struct addrinf
                }
 
                /* save the resolved address[es] */
-               __SCNetworkReachabilitySetResolvedAddress(target, addresses, NETDB_SUCCESS);
-               CFRelease(addresses);
+               targetPrivate->resolvedAddress      = addresses;
+               targetPrivate->resolvedAddressError = NETDB_SUCCESS;
        } else {
                SCLog(_sc_debug, LOG_INFO, CFSTR("getaddrinfo() failed: %s"), gai_strerror(status));
 
                /* save the error associated with the attempt to resolve the name */
-               __SCNetworkReachabilitySetResolvedAddress(target, (CFArrayRef)kCFNull, status);
+               targetPrivate->resolvedAddress      = CFRetain(kCFNull);
+               targetPrivate->resolvedAddressError = status;
        }
 
        if (res)        freeaddrinfo(res);
 
-       if (targetPrivate->rls) {
+       if (targetPrivate->rls != NULL) {
                SCLog(_sc_debug, LOG_INFO, CFSTR("DNS request completed"));
                CFRunLoopSourceSignal(targetPrivate->rls);
-               __signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
+               _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
        }
 
        return;
 }
-#else  /* CHECK_IPV6_REACHABILITY */
-static void
-__SCNetworkReachabilityCallbackSetResolvedAddress(struct hostent *h, int error, void *context)
-{
-       SCNetworkReachabilityRef                target          = (SCNetworkReachabilityRef)context;
-       SCNetworkReachabilityPrivateRef         targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
-
-       SCLog(_sc_debug, LOG_DEBUG,
-             CFSTR("process async DNS complete%s"),
-             (h == NULL) ? ", host not found" : "");
 
-       if (h && h->h_length) {
-               CFMutableArrayRef       addresses;
-               union {
-                       struct sockaddr         sa;
-                       struct sockaddr_in      sin;
-                       struct sockaddr_in6     sin6;
-                       struct sockaddr_storage ss;
-               }       addr;
-               char    **ha            = h->h_addr_list;
 
-               addresses = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-
-               bzero(&addr, sizeof(addr));
-
-               while (*ha) {
-                       CFDataRef       newAddress;
-
-                       switch (h->h_length) {
-                               case sizeof(struct in_addr) :
-                                       addr.sin.sin_family = AF_INET;
-                                       addr.sin.sin_len    = sizeof(struct sockaddr_in);
-                                       bcopy(*ha, &addr.sin.sin_addr, h->h_length);
-                                       break;
-                               case sizeof(struct in6_addr) :
-                                       addr.sin6.sin6_family = AF_INET6;
-                                       addr.sin6.sin6_len    = sizeof(struct sockaddr_in6);
-                                       bcopy(*ha, &addr.sin6.sin6_addr, h->h_length);
-                                       break;
-                       }
-
-                       newAddress = CFDataCreate(NULL, (void *)&addr, addr.sa.sa_len);
-                       CFArrayAppendValue(addresses, newAddress);
-                       CFRelease(newAddress);
-
-                       ha++;
-               }
-
-               /* save the resolved address[es] */
-               __SCNetworkReachabilitySetResolvedAddress(target, addresses, NETDB_SUCCESS);
-               CFRelease(addresses);
-       } else {
-               SCLog(_sc_debug, LOG_INFO, CFSTR("getipnodebyname() failed: %s"), __netdb_error(error));
-
-               /* save the error associated with the attempt to resolve the name */
-               __SCNetworkReachabilitySetResolvedAddress(target, (CFArrayRef)kCFNull, error);
-       }
+static void
+__SCNetworkReachabilityCallbackSetResolvedAddress(int32_t status, struct addrinfo *res, void *context)
+{
+       SCNetworkReachabilityRef        target          = (SCNetworkReachabilityRef)context;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
-       if (h)  freehostent(h);
-
-       if (targetPrivate->rls) {
-               SCLog(_sc_debug, LOG_INFO, CFSTR("DNS request completed"));
-               CFRunLoopSourceSignal(targetPrivate->rls);
-               __signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
-       }
+       __log_query_time(((status == 0) && (res != NULL)),      // if successful query
+                        TRUE,                                  // async
+                        &targetPrivate->dnsQueryStart);        // start time
 
+       __SCNetworkReachabilitySetResolvedAddress(status, res, target);
        return;
 }
-#endif /* CHECK_IPV6_REACHABILITY */
 
 
 /*
@@ -1532,60 +1349,285 @@ rankReachability(SCNetworkConnectionFlags flags)
 }
 
 
-#ifdef CHECK_IPV6_REACHABILITY
 static void
 getaddrinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, void *info)
 {
+       int32_t                         status;
        SCNetworkReachabilityRef        target          = (SCNetworkReachabilityRef)info;
        SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
        pthread_mutex_lock(&targetPrivate->lock);
 
-       getaddrinfo_async_handle_reply(msg);
+       status = getaddrinfo_async_handle_reply(msg);
+       if ((status == 0) &&
+           (targetPrivate->resolvedAddress == NULL) && (targetPrivate->resolvedAddressError == NETDB_SUCCESS)) {
+               // if request has been re-queued
+               goto again;
+       }
 
        if (port == targetPrivate->dnsPort) {
+               CFRunLoopSourceInvalidate(targetPrivate->dnsRLS);
                CFRelease(targetPrivate->dnsRLS);
                targetPrivate->dnsRLS = NULL;
                CFRelease(targetPrivate->dnsPort);
                targetPrivate->dnsPort = NULL;
        }
 
+    again :
+
        pthread_mutex_unlock(&targetPrivate->lock);
 
        return;
 }
-#else  /* CHECK_IPV6_REACHABILITY */
-static void
-getipnodebyname_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, void *info)
+
+
+static Boolean
+check_resolver_reachability(SCDynamicStoreRef          *storeP,
+                           dns_resolver_t              *resolver,
+                           SCNetworkConnectionFlags    *flags,
+                           Boolean                     *haveDNS)
 {
-       SCNetworkReachabilityRef        target          = (SCNetworkReachabilityRef)info;
-       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+       int             i;
+       Boolean         ok      = TRUE;
 
-       pthread_mutex_lock(&targetPrivate->lock);
+       *flags   = kSCNetworkFlagsReachable;
+       *haveDNS = FALSE;
 
-       getipnodebyname_async_handleReply(msg);
+       for (i = 0; i < resolver->n_nameserver; i++) {
+               struct sockaddr                 *address        = resolver->nameserver[i];
+               SCNetworkConnectionFlags        ns_flags        = 0;
 
-       if (port == targetPrivate->dnsPort) {
-               CFRelease(targetPrivate->dnsRLS);
-               targetPrivate->dnsRLS = NULL;
-               CFRelease(targetPrivate->dnsPort);
-               targetPrivate->dnsPort = NULL;
+               *haveDNS = TRUE;
+
+               if (address->sa_family != AF_INET) {
+                       /*
+                        * we need to skip non-IPv4 DNS server
+                        * addresses (at least until [3510431] has
+                        * been resolved).
+                        */
+                       continue;
+               }
+
+               ok = checkAddress(storeP, address, &ns_flags, NULL);
+               if (!ok) {
+                       /* not today */
+                       goto done;
+               }
+
+               if (rankReachability(ns_flags) < rankReachability(*flags)) {
+                       /* return the worst case result */
+                       *flags = ns_flags;
+               }
        }
 
-       pthread_mutex_unlock(&targetPrivate->lock);
+    done :
+
+       return ok;
+}
+
+
+static Boolean
+check_matching_resolvers(SCDynamicStoreRef             *storeP,
+                        dns_config_t                   *dns_config,
+                        const char                     *fqdn,
+                        SCNetworkConnectionFlags       *flags,
+                        Boolean                        *haveDNS)
+{
+       int             i;
+       Boolean         matched = FALSE;
+       const char      *name   = fqdn;
+
+       while (!matched && (name != NULL)) {
+               int     len;
+
+               /*
+                * check if the provided name (or sub-component)
+                * matches one of our resolver configurations.
+                */
+               len = strlen(name);
+               for (i = 0; i < dns_config->n_resolver; i++) {
+                       char            *domain;
+                       dns_resolver_t  *resolver;
+
+                       resolver = dns_config->resolver[i];
+                       domain   = resolver->domain;
+                       if (domain != NULL && (len == strlen(domain))) {
+                               if (strcasecmp(name, domain) == 0) {
+                                       Boolean ok;
+
+                                       /*
+                                        * if name matches domain
+                                        */
+                                       matched = TRUE;
+                                       ok = check_resolver_reachability(storeP, resolver, flags, haveDNS);
+                                       if (!ok) {
+                                               /* not today */
+                                               return FALSE;
+                                       }
+                               }
+                       }
+               }
+
+               if (!matched) {
+                       /*
+                        * we have not found a matching resolver, try
+                        * a less qualified domain
+                        */
+                       name = strchr(name, '.');
+                       if ((name != NULL) && (*name != '\0')) {
+                               name++;
+                       } else {
+                               name = NULL;
+                       }
+               }
+       }
+
+       return matched;
+}
+
+
+static dns_configuration_t *
+dns_configuration_retain()
+{
+       pthread_mutex_lock(&dns_lock);
+
+       if ((dns_configuration != NULL) && dns_token_valid) {
+               int             check   = 0;
+               uint32_t        status;
+
+               /*
+                * check if the global [DNS] configuration snapshot needs
+                * to be updated
+                */
+               status = notify_check(dns_token, &check);
+               if (status != NOTIFY_STATUS_OK) {
+                       SCLog(TRUE, LOG_INFO, CFSTR("notify_check() failed, status=%lu"), status);
+               }
+
+               if ((status != NOTIFY_STATUS_OK) || (check != 0)) {
+                       /*
+                        * if the snapshot needs to be refreshed
+                        */
+                       if (dns_configuration->refs == 0) {
+                               dns_configuration_free(dns_configuration->config);
+                               CFAllocatorDeallocate(NULL, dns_configuration);
+                       }
+                       dns_configuration = NULL;
+               }
+       }
+
+       if (dns_configuration == NULL) {
+               dns_config_t    *new_config;
 
+               new_config = dns_configuration_copy();
+               if (new_config != NULL) {
+                       dns_configuration = CFAllocatorAllocate(NULL, sizeof(dns_configuration_t), 0);
+                       dns_configuration->config = new_config;
+                       dns_configuration->refs   = 0;
+               }
+       }
+
+       if (dns_configuration != NULL) {
+               dns_configuration->refs++;
+       }
+
+       pthread_mutex_unlock(&dns_lock);
+       return dns_configuration;
+}
+
+
+static void
+dns_configuration_release(dns_configuration_t *config)
+{
+       pthread_mutex_lock(&dns_lock);
+
+       config->refs--;
+       if (config->refs == 0) {
+               if ((dns_configuration != config)) {
+                       dns_configuration_free(config->config);
+                       CFAllocatorDeallocate(NULL, config);
+               }
+       }
+
+       pthread_mutex_unlock(&dns_lock);
        return;
 }
-#endif /* CHECK_IPV6_REACHABILITY */
 
 
 static Boolean
-checkResolverReachability(SCDynamicStoreRef            *storeP,
-                         SCNetworkConnectionFlags      *flags,
-                         Boolean                       *haveDNS)
+dns_configuration_watch()
 {
-       int     i;
-       Boolean ok      = TRUE;
+       int             dns_check       = 0;
+       const char      *dns_key;
+       Boolean         ok              = FALSE;
+       uint32_t        status;
+
+       pthread_mutex_lock(&dns_lock);
+
+       dns_key = dns_configuration_notify_key();
+       if (dns_key == NULL) {
+               SCLog(TRUE, LOG_INFO, CFSTR("dns_configuration_notify_key() failed"));
+               goto done;
+       }
+
+       status = notify_register_check(dns_key, &dns_token);
+       if (status == NOTIFY_STATUS_OK) {
+               dns_token_valid = TRUE;
+       } else {
+               SCLog(TRUE, LOG_INFO, CFSTR("notify_register_check() failed, status=%lu"), status);
+               goto done;
+       }
+
+       status = notify_check(dns_token, &dns_check);
+       if (status != NOTIFY_STATUS_OK) {
+               SCLog(TRUE, LOG_INFO, CFSTR("notify_check() failed, status=%lu"), status);
+               (void)notify_cancel(dns_token);
+               dns_token_valid = FALSE;
+               goto done;
+       }
+
+       ok = TRUE;
+
+    done :
+
+       pthread_mutex_unlock(&dns_lock);
+       return ok;
+}
+
+
+static void
+dns_configuration_unwatch()
+{
+       pthread_mutex_lock(&dns_lock);
+
+       (void)notify_cancel(dns_token);
+       dns_token_valid = FALSE;
+
+       if ((dns_configuration != NULL) && (dns_configuration->refs == 0)) {
+               dns_configuration_free(dns_configuration->config);
+               CFAllocatorDeallocate(NULL, dns_configuration);
+               dns_configuration = NULL;
+       }
+
+       pthread_mutex_unlock(&dns_lock);
+       return;
+}
+
+
+Boolean
+_SC_checkResolverReachability(SCDynamicStoreRef                *storeP,
+                             SCNetworkConnectionFlags  *flags,
+                             Boolean                   *haveDNS,
+                             const char *              nodename)
+{
+       dns_resolver_t          *default_resolver;
+       dns_configuration_t     *dns;
+       Boolean                 found                   = FALSE;
+       char                    *fqdn                   = (char *)nodename;
+       int                     i;
+       Boolean                 isFQDN                  = FALSE;
+       uint32_t                len;
+       Boolean                 ok                      = TRUE;
 
        /*
         * We first assume that all of the configured DNS servers
@@ -1598,41 +1640,105 @@ checkResolverReachability(SCDynamicStoreRef            *storeP,
        *flags   = kSCNetworkFlagsReachable;
        *haveDNS = FALSE;
 
-       if (needDNS) {
-               if (hn_store) {
-                       /* if we are actively watching at least one host */
-                       needDNS = FALSE;
-               }
-               res_init();
+       len = strlen(fqdn);
+       if (len == 0) {
+               // if no nodename, return not reachable
+               *flags = 0;
+               return ok;
        }
 
-       for (i = 0; i < _res.nscount; i++) {
-               SCNetworkConnectionFlags        ns_flags        = 0;
+       dns = dns_configuration_retain();
+       if (dns == NULL) {
+               // if error
+               goto done;
+       }
 
-               if (_res.nsaddr_list[i].sin_addr.s_addr == 0) {
-                       continue;
-               }
+       if (dns->config->n_resolver == 0) {
+               // if no resolver configuration
+               goto done;
+       }
 
-               *haveDNS = TRUE;
+       *flags = kSCNetworkFlagsReachable;
 
-               if (_res.nsaddr_list[i].sin_len == 0) {
-                       _res.nsaddr_list[i].sin_len = sizeof(_res.nsaddr_list[i]);
-               }
+       if (fqdn[len - 1] == '.') {
+               isFQDN = TRUE;
 
-               ok = checkAddress(storeP, (struct sockaddr *)&_res.nsaddr_list[i], &ns_flags, NULL);
-               if (!ok) {
-                       /* not today */
-                       break;
+               // trim trailing '.''s
+               while ((len > 0) && (fqdn[len-1] == '.')) {
+                       if (fqdn == nodename) {
+                               fqdn = strdup(nodename);
+                       }
+                       fqdn[--len] = '\0';
                }
-               if (rankReachability(ns_flags) < rankReachability(*flags)) {
-                       /* return the worst case result */
-                       *flags = ns_flags;
+       }
+
+       default_resolver = dns->config->resolver[0];
+
+       /*
+        * try the provided name
+        */
+       found = check_matching_resolvers(storeP, dns->config, fqdn, flags, haveDNS);
+       if (!found && !isFQDN && (dns->config->n_resolver > 1)) {
+               /*
+                * FQDN not specified, try w/search or default domain(s) too
+                */
+               if (default_resolver->n_search > 0) {
+                       for (i = 0; !found && (i < default_resolver->n_search); i++) {
+                               int     ret;
+                               char    *search_fqdn    = NULL;
+
+                               ret = asprintf(&search_fqdn, "%s.%s", fqdn, default_resolver->search[i]);
+                               if (ret == -1) {
+                                       continue;
+                               }
+
+                               // try the provided name with the search domain appended
+                               found = check_matching_resolvers(storeP, dns->config, search_fqdn, flags, haveDNS);
+                               free(search_fqdn);
+                       }
+               } else if (default_resolver->domain != NULL) {
+                       char    *dp;
+                       int     domain_parts    = 1;
+
+                       for (dp = default_resolver->domain; *dp != '\0'; dp++) {
+                               if (*dp == '.') {
+                                       domain_parts++;
+                               }
+                       }
+
+                       dp = default_resolver->domain;
+                       for (i = LOCALDOMAINPARTS; !found && (i <= domain_parts); i++) {
+                               int     ret;
+                               char    *search_fqdn    = NULL;
+
+                               ret = asprintf(&search_fqdn, "%s.%s", fqdn, dp);
+                               if (ret == -1) {
+                                       continue;
+                               }
+
+                               // try the provided name with the [default] domain appended
+                               found = check_matching_resolvers(storeP, dns->config, search_fqdn, flags, haveDNS);
+                               free(search_fqdn);
+
+                               // move to the next component of the [default] domain
+                               dp = strchr(dp, '.') + 1;
+                       }
                }
        }
 
-       if (!*haveDNS) {
-               /* if no DNS server addresses */
-               *flags = 0;
+       if (!found) {
+               /*
+                * check the reachability of the default resolver
+                */
+               ok = check_resolver_reachability(storeP, default_resolver, flags, haveDNS);
+       }
+
+       if (fqdn != nodename)   free(fqdn);
+
+    done :
+
+       if (dns != NULL) {
+               dns_configuration_release(dns);
        }
 
        return ok;
@@ -1643,17 +1749,19 @@ static Boolean
 startAsyncDNSQuery(SCNetworkReachabilityRef target) {
        CFMachPortContext               context         = { 0, (void *)target, CFRetain, CFRelease, CFCopyDescription };
        int                             error;
-#ifdef CHECK_IPV6_REACHABILITY
        struct addrinfo                 hints;
-#endif /* CHECK_IPV6_REACHABILITY */
        CFIndex                         i;
        CFIndex                         n;
        mach_port_t                     port;
        SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
-#ifdef CHECK_IPV6_REACHABILITY
+       (void) gettimeofday(&targetPrivate->dnsQueryStart, NULL);
+
        bzero(&hints, sizeof(hints));
        hints.ai_flags = AI_ADDRCONFIG;
+#ifdef AI_PARALLEL
+       hints.ai_flags |= AI_PARALLEL;
+#endif /* AI_PARALLEL */
 
        error = getaddrinfo_async_start(&port,
                                        targetPrivate->name,
@@ -1663,7 +1771,7 @@ startAsyncDNSQuery(SCNetworkReachabilityRef target) {
                                        (void *)target);
        if (error != 0) {
                /* save the error associated with the attempt to resolve the name */
-               __SCNetworkReachabilitySetResolvedAddress(target, (CFArrayRef)kCFNull, error);
+               __SCNetworkReachabilityCallbackSetResolvedAddress(error, NULL, (void *)target);
                return FALSE;
        }
 
@@ -1672,26 +1780,6 @@ startAsyncDNSQuery(SCNetworkReachabilityRef target) {
                                                          getaddrinfo_async_handleCFReply,
                                                          &context,
                                                          NULL);
-#else  /* CHECK_IPV6_REACHABILITY */
-       port = getipnodebyname_async_start(targetPrivate->name,
-                                          AF_INET,
-                                          0,
-                                          &error,
-                                          __SCNetworkReachabilityCallbackSetResolvedAddress,
-                                          (void *)target);
-       if (port == MACH_PORT_NULL) {
-               /* save the error associated with the attempt to resolve the name */
-               __SCNetworkReachabilitySetResolvedAddress(target, (CFArrayRef)kCFNull, error);
-               return FALSE;
-       }
-
-       targetPrivate->dnsPort = CFMachPortCreateWithPort(NULL,
-                                                         port,
-                                                         getipnodebyname_async_handleCFReply,
-                                                         &context,
-                                                         NULL);
-#endif /* CHECK_IPV6_REACHABILITY */
-
        targetPrivate->dnsRLS = CFMachPortCreateRunLoopSource(NULL, targetPrivate->dnsPort, 0);
 
        n = CFArrayGetCount(targetPrivate->rlList);
@@ -1720,7 +1808,7 @@ __SCNetworkReachabilityGetFlags(SCDynamicStoreRef         *storeP,
        Boolean                         ok              = TRUE;
 
        *flags = 0;
-       if (if_index) {
+       if (if_index != NULL) {
                *if_index = 0;
        }
 
@@ -1735,14 +1823,7 @@ __SCNetworkReachabilityGetFlags(SCDynamicStoreRef                *storeP,
                        /*
                         * Check "local" address
                         */
-                       if (targetPrivate->localAddress) {
-                               /*
-                                * Check if 0.0.0.0
-                                */
-                               if (isAddressZero(targetPrivate->localAddress, &my_flags)) {
-                                       goto checkRemote;
-                               }
-
+                       if (targetPrivate->localAddress != NULL) {
                                /*
                                 * Check "local" address
                                 */
@@ -1756,12 +1837,10 @@ __SCNetworkReachabilityGetFlags(SCDynamicStoreRef               *storeP,
                                }
                        }
 
-                   checkRemote :
-
                        /*
                         * Check "remote" address
                         */
-                       if (targetPrivate->remoteAddress) {
+                       if (targetPrivate->remoteAddress != NULL) {
                                /*
                                 * in cases where we have "local" and "remote" addresses
                                 * we need to re-initialize the to-be-returned flags.
@@ -1769,13 +1848,6 @@ __SCNetworkReachabilityGetFlags(SCDynamicStoreRef                *storeP,
                                my_flags = 0;
                                my_index = 0;
 
-                               /*
-                                * Check if 0.0.0.0
-                                */
-                               if (isAddressZero(targetPrivate->remoteAddress, &my_flags)) {
-                                       break;
-                               }
-
                                /*
                                 * Check "remote" address
                                 */
@@ -1790,27 +1862,23 @@ __SCNetworkReachabilityGetFlags(SCDynamicStoreRef               *storeP,
                }
 
                case reachabilityTypeName : {
+                       struct timeval                  dnsQueryStart;
                        int                             error;
-#ifndef        CHECK_IPV6_REACHABILITY
-                       struct hostent                  *h;
-#endif /* CHECK_IPV6_REACHABILITY */
-                       Boolean                         haveDNS         = FALSE;
-#ifdef CHECK_IPV6_REACHABILITY
                        struct addrinfo                 hints;
-#endif /* CHECK_IPV6_REACHABILITY */
                        SCNetworkConnectionFlags        ns_flags;
-#ifdef CHECK_IPV6_REACHABILITY
                        struct addrinfo                 *res;
-#endif /* CHECK_IPV6_REACHABILITY */
 
                        addresses = (CFMutableArrayRef)SCNetworkReachabilityCopyResolvedAddress(target, &error);
-                       if (addresses || (error != NETDB_SUCCESS)) {
+                       if ((addresses != NULL) || (error != NETDB_SUCCESS)) {
                                /* if resolved or an error had been detected */
                                goto checkResolvedAddress;
                        }
 
                        /* check the reachability of the DNS servers */
-                       ok = checkResolverReachability(storeP, &ns_flags, &haveDNS);\
+                       ok = _SC_checkResolverReachability(storeP,
+                                                          &ns_flags,
+                                                          &targetPrivate->haveDNS,
+                                                          targetPrivate->name);
                        if (!ok) {
                                /* if we could not get DNS server info */
                                goto error;
@@ -1822,30 +1890,23 @@ __SCNetworkReachabilityGetFlags(SCDynamicStoreRef               *storeP,
                                 * flags based on the availability of configured (but not
                                 * active) services.
                                 */
-                               if (!checkAddressZero(storeP, &my_flags, &my_index)) {
+                               if (!checkAddress(storeP, NULL, &my_flags, &my_index)) {
                                        goto error;
                                }
 
-                               if (async && targetPrivate->rls) {
+                               if (async && (targetPrivate->rls != NULL)) {
                                        /*
-                                        * return HOST_NOT_FOUND, set flags appropriately,
+                                        * return "host not found", set flags appropriately,
                                         * and schedule notification.
                                         */
-#ifdef CHECK_IPV6_REACHABILITY
                                        __SCNetworkReachabilityCallbackSetResolvedAddress(EAI_NODATA,
                                                                                          NULL,
                                                                                          (void *)target);
-#else  /* CHECK_IPV6_REACHABILITY */
-                                       __SCNetworkReachabilityCallbackSetResolvedAddress(NULL,
-                                                                                         HOST_NOT_FOUND,
-                                                                                         (void *)target);
-#endif /* CHECK_IPV6_REACHABILITY */
-
                                        my_flags |= (targetPrivate->flags & kSCNetworkFlagsFirstResolvePending);
 
                                        SCLog(_sc_debug, LOG_INFO, CFSTR("no DNS servers are reachable"));
                                        CFRunLoopSourceSignal(targetPrivate->rls);
-                                       __signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
+                                       _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
                                }
                                break;
                        }
@@ -1880,16 +1941,23 @@ __SCNetworkReachabilityGetFlags(SCDynamicStoreRef               *storeP,
                         * OK, all of the DNS name servers are available.  Let's
                         * resolve the nodename into an address.
                         */
-#ifdef CHECK_IPV6_REACHABILITY
+                       if (_sc_debug) {
+                               (void) gettimeofday(&dnsQueryStart, NULL);
+                       }
+
                        bzero(&hints, sizeof(hints));
                        hints.ai_flags = AI_ADDRCONFIG;
+#ifdef AI_PARALLEL
+                       hints.ai_flags |= AI_PARALLEL;
+#endif /* AI_PARALLEL */
 
                        error = getaddrinfo(targetPrivate->name, NULL, &hints, &res);
-                       __SCNetworkReachabilityCallbackSetResolvedAddress(error, res, (void *)target);
-#else  /* CHECK_IPV6_REACHABILITY */
-                       h = getipnodebyname(targetPrivate->name, AF_INET, 0, &error);
-                       __SCNetworkReachabilityCallbackSetResolvedAddress(h, error, (void *)target);
-#endif /* CHECK_IPV6_REACHABILITY */
+
+                       __log_query_time(((error == 0) && (res != NULL)),// if successful query
+                                        FALSE,                         // sync
+                                        &dnsQueryStart);               // start time
+
+                       __SCNetworkReachabilitySetResolvedAddress(error, res, target);
 
                        addresses = (CFMutableArrayRef)SCNetworkReachabilityCopyResolvedAddress(target, &error);
 
@@ -1913,6 +1981,7 @@ __SCNetworkReachabilityGetFlags(SCDynamicStoreRef         *storeP,
                                        struct sockaddr                 *sa;
 
                                        sa = (struct sockaddr *)CFDataGetBytePtr(CFArrayGetValueAtIndex(addresses, i));
+
                                        ok = checkAddress(storeP, sa, &ns_flags, &ns_if_index);
                                        if (!ok) {
                                                goto error;     /* not today */
@@ -1929,13 +1998,13 @@ __SCNetworkReachabilityGetFlags(SCDynamicStoreRef               *storeP,
                                        }
                                }
                        } else {
-                               if ((error == HOST_NOT_FOUND) && !haveDNS) {
+                               if ((error == EAI_NODATA) && !targetPrivate->haveDNS) {
                                        /*
                                         * No DNS servers are defined. Set flags based on
                                         * the availability of configured (but not active)
                                         * services.
                                         */
-                                       ok = checkAddressZero(storeP, &my_flags, &my_index);
+                                       ok = checkAddress(storeP, NULL, &my_flags, &my_index);
                                        if (!ok) {
                                                goto error;     /* not today */
                                        }
@@ -1960,13 +2029,13 @@ __SCNetworkReachabilityGetFlags(SCDynamicStoreRef               *storeP,
        }
 
        *flags = my_flags;
-       if (if_index) {
+       if (if_index != NULL) {
                *if_index = my_index;
        }
 
     error :
 
-       if (addresses)  CFRelease(addresses);
+       if (addresses != NULL)  CFRelease(addresses);
        return ok;
 }
 
@@ -1984,15 +2053,16 @@ SCNetworkReachabilityGetFlags(SCNetworkReachabilityRef  target,
                return FALSE;
        }
 
-       if (targetPrivate->rlList) {
-               /* if being watched, return current (OK, last known) status */
+       if (targetPrivate->rlList != NULL) {
+               // if being watched, return the last known (and what should be current) status
                *flags = targetPrivate->flags & ~kSCNetworkFlagsFirstResolvePending;
                return TRUE;
        }
 
+
        ok = __SCNetworkReachabilityGetFlags(&store, target, flags, NULL, FALSE);
        *flags &= ~kSCNetworkFlagsFirstResolvePending;
-       if (store)      CFRelease(store);
+       if (store != NULL)      CFRelease(store);
        return ok;
 }
 
@@ -2000,6 +2070,7 @@ SCNetworkReachabilityGetFlags(SCNetworkReachabilityRef    target,
 static void
 __SCNetworkReachabilityReachabilitySetNotifications(SCDynamicStoreRef  store)
 {
+       CFStringRef                     dns_key;
        CFStringRef                     key;
        CFMutableArrayRef               keys;
        CFStringRef                     pattern;
@@ -2008,34 +2079,29 @@ __SCNetworkReachabilityReachabilitySetNotifications(SCDynamicStoreRef   store)
        keys     = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
        patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
 
-       /*
-        * Setup:/Network/Global/IPv4 (for the ServiceOrder)
-        */
+       // Setup:/Network/Global/IPv4 (for the ServiceOrder)
        key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
                                                         kSCDynamicStoreDomainSetup,
                                                         kSCEntNetIPv4);
        CFArrayAppendValue(keys, key);
        CFRelease(key);
 
-       /*
-        * State:/Network/Global/DNS
-        */
-       key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
-                                                        kSCDynamicStoreDomainState,
-                                                        kSCEntNetDNS);
+       dns_key = CFStringCreateWithCString(NULL,
+                                           dns_configuration_notify_key(),
+                                           kCFStringEncodingASCII);
+       key = CFStringCreateWithFormat(NULL, NULL, CFSTR("Notify:%@"), dns_key);
+       CFRelease(dns_key);
        CFArrayAppendValue(keys, key);
        CFRelease(key);
 
-       /*
-        * State:/Network/Global/IPv4
-        */
+       // State:/Network/Global/IPv4 (default route)
        key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
                                                         kSCDynamicStoreDomainState,
                                                         kSCEntNetIPv4);
        CFArrayAppendValue(keys, key);
        CFRelease(key);
 
-       /* Setup: per-service IPv4 info */
+       // Setup: per-service IPv4 info
        pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
                                                              kSCDynamicStoreDomainSetup,
                                                              kSCCompAnyRegex,
@@ -2043,7 +2109,7 @@ __SCNetworkReachabilityReachabilitySetNotifications(SCDynamicStoreRef     store)
        CFArrayAppendValue(patterns, pattern);
        CFRelease(pattern);
 
-       /* Setup: per-service Interface info */
+       // Setup: per-service Interface info
        pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
                                                              kSCDynamicStoreDomainSetup,
                                                              kSCCompAnyRegex,
@@ -2051,7 +2117,7 @@ __SCNetworkReachabilityReachabilitySetNotifications(SCDynamicStoreRef     store)
        CFArrayAppendValue(patterns, pattern);
        CFRelease(pattern);
 
-       /* Setup: per-service PPP info */
+       // Setup: per-service PPP info (for kSCPropNetPPPDialOnDemand)
        pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
                                                              kSCDynamicStoreDomainSetup,
                                                              kSCCompAnyRegex,
@@ -2059,15 +2125,7 @@ __SCNetworkReachabilityReachabilitySetNotifications(SCDynamicStoreRef    store)
        CFArrayAppendValue(patterns, pattern);
        CFRelease(pattern);
 
-       /* State: per-service IPv4 info */
-       pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
-                                                             kSCDynamicStoreDomainState,
-                                                             kSCCompAnyRegex,
-                                                             kSCEntNetIPv4);
-       CFArrayAppendValue(patterns, pattern);
-       CFRelease(pattern);
-
-       /* State: per-interface IPv4 info */
+       // State: per-interface IPv4 info
        pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
                                                                kSCDynamicStoreDomainState,
                                                                kSCCompAnyRegex,
@@ -2075,7 +2133,7 @@ __SCNetworkReachabilityReachabilitySetNotifications(SCDynamicStoreRef     store)
        CFArrayAppendValue(patterns, pattern);
        CFRelease(pattern);
 
-       /* State: per-interface IPv6 info */
+       // State: per-interface IPv6 info
        pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
                                                                kSCDynamicStoreDomainState,
                                                                kSCCompAnyRegex,
@@ -2096,12 +2154,13 @@ __SCNetworkReachabilityReachabilityHandleChanges(SCDynamicStoreRef      store,
                                                 CFArrayRef             changedKeys,
                                                 void                   *info)
 {
-       Boolean         dnsChanged      = FALSE;
+       Boolean         dnsConfigChanged        = FALSE;
+       CFStringRef     dnsKey;
        CFIndex         i;
        CFStringRef     key;
        CFIndex         nTargets;
        const void *    targets_q[N_QUICK];
-       const void **   targets         = targets_q;
+       const void **   targets                 = targets_q;
 
        pthread_mutex_lock(&hn_lock);
 
@@ -2118,35 +2177,20 @@ __SCNetworkReachabilityReachabilityHandleChanges(SCDynamicStoreRef      store,
 
        SCLog(_sc_debug, LOG_INFO, CFSTR("process configuration change"));
 
-       key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
-                                                        kSCDynamicStoreDomainState,
-                                                        kSCEntNetDNS);
+       dnsKey = CFStringCreateWithCString(NULL,
+                                          dns_configuration_notify_key(),
+                                          kCFStringEncodingASCII);
+       key = CFStringCreateWithFormat(NULL, NULL, CFSTR("Notify:%@"), dnsKey);
+       CFRelease(dnsKey);
        if (CFArrayContainsValue(changedKeys,
                                 CFRangeMake(0, CFArrayGetCount(changedKeys)),
                                 key)) {
-               dnsChanged = TRUE;      /* the DNS server(s) have changed */
-               needDNS    = TRUE;      /* ... and we need to res_init() on the next query */
-       }
-       CFRelease(key);
+               dnsConfigChanged = TRUE;        /* the DNS server(s) have changed */
 
-       if (!dnsChanged) {
-               /*
-                * if the DNS configuration didn't change we still need to
-                * check that the DNS servers are accessible.
-                */
-               Boolean                         haveDNS         = FALSE;
-               SCNetworkConnectionFlags        ns_flags;
-               Boolean                         ok;
-
-               /* check the reachability of the DNS servers */
-               ok = checkResolverReachability(&store, &ns_flags, &haveDNS);\
-               if (!ok || (rankReachability(ns_flags) < 2)) {
-                       /* if DNS servers are not reachable */
-                       dnsChanged = TRUE;
-               }
        }
+       CFRelease(key);
 
-       SCLog(_sc_debug && dnsChanged, LOG_INFO, CFSTR("  DNS changed"));
+       SCLog(_sc_debug && dnsConfigChanged, LOG_INFO, CFSTR("  DNS configuration changed"));
 
        if (nTargets > (CFIndex)(sizeof(targets_q) / sizeof(CFTypeRef)))
                targets = CFAllocatorAllocate(NULL, nTargets * sizeof(CFTypeRef), 0);
@@ -2157,26 +2201,51 @@ __SCNetworkReachabilityReachabilityHandleChanges(SCDynamicStoreRef      store,
 
                pthread_mutex_lock(&targetPrivate->lock);
 
-               if (dnsChanged) {
-                       if (targetPrivate->dnsPort) {
-                               /* cancel the outstanding DNS query */
-#ifdef CHECK_IPV6_REACHABILITY
-                               lu_async_call_cancel(CFMachPortGetPort(targetPrivate->dnsPort));
-#else  /* CHECK_IPV6_REACHABILITY */
-                               getipnodebyname_async_cancel(CFMachPortGetPort(targetPrivate->dnsPort));
-#endif /* CHECK_IPV6_REACHABILITY */
-                               CFRelease(targetPrivate->dnsRLS);
-                               targetPrivate->dnsRLS = NULL;
-                               CFRelease(targetPrivate->dnsPort);
-                               targetPrivate->dnsPort = NULL;
+               if (targetPrivate->type == reachabilityTypeName) {
+                       Boolean         dnsChanged      = dnsConfigChanged;
+
+                       if (!dnsChanged) {
+                               /*
+                                * if the DNS configuration didn't change we still need to
+                                * check that the DNS servers are accessible.
+                                */
+                               SCNetworkConnectionFlags        ns_flags;
+                               Boolean                         ok;
+
+                               /* check the reachability of the DNS servers */
+                               ok = _SC_checkResolverReachability(&store,
+                                                                  &ns_flags,
+                                                                  &targetPrivate->haveDNS,
+                                                                  targetPrivate->name);
+                               if (!ok || (rankReachability(ns_flags) < 2)) {
+                                       /* if DNS servers are not reachable */
+                                       dnsChanged = TRUE;
+                               }
                        }
 
-                       /* schedule request to resolve the name again */
-                       __SCNetworkReachabilitySetResolvedAddress(target, NULL, NETDB_SUCCESS);
+                       if (dnsChanged) {
+                               if (targetPrivate->dnsPort) {
+                                       /* cancel the outstanding DNS query */
+                                       lu_async_call_cancel(CFMachPortGetPort(targetPrivate->dnsPort));
+                                       CFRunLoopSourceInvalidate(targetPrivate->dnsRLS);
+                                       CFRelease(targetPrivate->dnsRLS);
+                                       targetPrivate->dnsRLS = NULL;
+                                       CFRelease(targetPrivate->dnsPort);
+                                       targetPrivate->dnsPort = NULL;
+                               }
+
+                               /* schedule request to resolve the name again */
+                               if (targetPrivate->resolvedAddress != NULL) {
+                                       CFRelease(targetPrivate->resolvedAddress);
+                                       targetPrivate->resolvedAddress = NULL;
+                               }
+                               targetPrivate->resolvedAddress      = NULL;
+                               targetPrivate->resolvedAddressError = NETDB_SUCCESS;
+                       }
                }
 
                CFRunLoopSourceSignal(targetPrivate->rls);
-               __signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
+               _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
 
                pthread_mutex_unlock(&targetPrivate->lock);
        }
@@ -2189,78 +2258,6 @@ __SCNetworkReachabilityReachabilityHandleChanges(SCDynamicStoreRef       store,
 }
 
 
-static Boolean
-__isScheduled(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
-{
-       CFIndex i;
-       CFIndex n       = CFArrayGetCount(rlList);
-
-       for (i = 0; i < n; i += 3) {
-               if (obj         && !CFEqual(obj,         CFArrayGetValueAtIndex(rlList, i))) {
-                       continue;
-               }
-               if (runLoop     && !CFEqual(runLoop,     CFArrayGetValueAtIndex(rlList, i+1))) {
-                       continue;
-               }
-               if (runLoopMode && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
-                       continue;
-               }
-               return TRUE;
-       }
-
-       return FALSE;
-}
-
-
-static void
-__schedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
-{
-       CFArrayAppendValue(rlList, obj);
-       CFArrayAppendValue(rlList, runLoop);
-       CFArrayAppendValue(rlList, runLoopMode);
-
-       return;
-}
-
-
-static Boolean
-__unschedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList, Boolean all)
-{
-       CFIndex i       = 0;
-       Boolean found   = FALSE;
-       CFIndex n       = CFArrayGetCount(rlList);
-
-       while (i < n) {
-               if (obj         && !CFEqual(obj,         CFArrayGetValueAtIndex(rlList, i))) {
-                       i += 3;
-                       continue;
-               }
-               if (runLoop     && !CFEqual(runLoop,     CFArrayGetValueAtIndex(rlList, i+1))) {
-                       i += 3;
-                       continue;
-               }
-               if (runLoopMode && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
-                       i += 3;
-                       continue;
-               }
-
-               found = TRUE;
-
-               CFArrayRemoveValueAtIndex(rlList, i + 2);
-               CFArrayRemoveValueAtIndex(rlList, i + 1);
-               CFArrayRemoveValueAtIndex(rlList, i);
-
-               if (!all) {
-                       return found;
-               }
-
-               n -= 3;
-       }
-
-       return found;
-}
-
-
 static void
 rlsPerform(void *info)
 {
@@ -2276,11 +2273,12 @@ rlsPerform(void *info)
 
        SCLog(_sc_debug, LOG_DEBUG, CFSTR("process reachability change"));
 
+
        pthread_mutex_lock(&targetPrivate->lock);
 
        /* update reachability, notify if status changed */
        ok = __SCNetworkReachabilityGetFlags(&store, target, &flags, &if_index, TRUE);
-       if (store) CFRelease(store);
+       if (store != NULL) CFRelease(store);
        if (!ok) {
                /* if reachability status not available */
                flags    = 0;
@@ -2290,8 +2288,15 @@ rlsPerform(void *info)
        if ((targetPrivate->flags == flags) && (targetPrivate->if_index == if_index)) {
                /* if reachability flags and interface have not changed */
                pthread_mutex_unlock(&targetPrivate->lock);
-               SCLog(_sc_debug, LOG_DEBUG, CFSTR("flags/interface match"));
+               SCLog(_sc_debug, LOG_DEBUG,
+                     CFSTR("flags/interface match (now %8.8x/%hu)"),
+                     flags, if_index);
                return;
+       } else {
+               SCLog(_sc_debug, LOG_DEBUG,
+                     CFSTR("flags/interface have changed (was %8.8x/%hu, now %8.8x/%hu)"),
+                     targetPrivate->flags, targetPrivate->if_index,
+                     flags, if_index);
        }
 
        /* update flags / interface */
@@ -2300,8 +2305,8 @@ rlsPerform(void *info)
 
        /* callout */
        rlsFunction = targetPrivate->rlsFunction;
-       if (NULL != targetPrivate->rlsContext.retain) {
-               context_info    = (void *)targetPrivate->rlsContext.retain(targetPrivate->rlsContext.info);
+       if (targetPrivate->rlsContext.retain != NULL) {
+               context_info    = (void *)(*targetPrivate->rlsContext.retain)(targetPrivate->rlsContext.info);
                context_release = targetPrivate->rlsContext.release;
        } else {
                context_info    = targetPrivate->rlsContext.info;
@@ -2310,13 +2315,12 @@ rlsPerform(void *info)
 
        pthread_mutex_unlock(&targetPrivate->lock);
 
-       if (rlsFunction) {
-               SCLog(_sc_debug, LOG_DEBUG, CFSTR("flags/interface have changed"));
+       if (rlsFunction != NULL) {
                (*rlsFunction)(target, flags, context_info);
        }
 
-       if (context_release) {
-               context_release(context_info);
+       if (context_release != NULL) {
+               (*context_release)(context_info);
        }
 
        return;
@@ -2332,9 +2336,9 @@ SCNetworkReachabilitySetCallback(SCNetworkReachabilityRef target,
 
        pthread_mutex_lock(&targetPrivate->lock);
 
-       if (targetPrivate->rlsContext.release) {
+       if (targetPrivate->rlsContext.release != NULL) {
                /* let go of the current context */
-               targetPrivate->rlsContext.release(targetPrivate->rlsContext.info);
+               (*targetPrivate->rlsContext.release)(targetPrivate->rlsContext.info);
        }
 
        targetPrivate->rlsFunction                      = callout;
@@ -2344,8 +2348,8 @@ SCNetworkReachabilitySetCallback(SCNetworkReachabilityRef target,
        targetPrivate->rlsContext.copyDescription       = NULL;
        if (context) {
                bcopy(context, &targetPrivate->rlsContext, sizeof(SCNetworkReachabilityContext));
-               if (context->retain) {
-                       targetPrivate->rlsContext.info = (void *)context->retain(context->info);
+               if (context->retain != NULL) {
+                       targetPrivate->rlsContext.info = (void *)(*context->retain)(context->info);
                }
        }
 
@@ -2374,15 +2378,21 @@ SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef       target,
        pthread_mutex_lock(&hn_lock);
        pthread_mutex_lock(&targetPrivate->lock);
 
-       if (!hn_store) {
+       if (hn_store == NULL) {
                /*
-                * if we are not monitoring any hosts
+                * if we are not monitoring any hosts, start watching
                 */
+               if (!dns_configuration_watch()) {
+                       // if error
+                       _SCErrorSet(kSCStatusFailed);
+                       goto done;
+               }
+
                hn_store = SCDynamicStoreCreate(NULL,
                                                CFSTR("SCNetworkReachability"),
                                                __SCNetworkReachabilityReachabilityHandleChanges,
                                                NULL);
-               if (!hn_store) {
+               if (hn_store == NULL) {
                        SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreCreate() failed"));
                        goto done;
                }
@@ -2394,7 +2404,7 @@ SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef target,
                hn_targets  = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
        }
 
-       if (!targetPrivate->rls) {
+       if (targetPrivate->rls == NULL) {
                CFRunLoopSourceContext  context = { 0                   // version
                                                  , (void *)target      // info
                                                  , CFRetain            // retain
@@ -2412,24 +2422,24 @@ SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef       target,
                init = TRUE;
        }
 
-       if (!__isScheduled(NULL, runLoop, runLoopMode, targetPrivate->rlList)) {
+       if (!_SC_isScheduled(NULL, runLoop, runLoopMode, targetPrivate->rlList)) {
                /*
                 * if we do not already have host notifications scheduled with
                 * this runLoop / runLoopMode
                 */
                CFRunLoopAddSource(runLoop, targetPrivate->rls, runLoopMode);
 
-               if (targetPrivate->dnsRLS) {
+               if (targetPrivate->dnsRLS != NULL) {
                        /* if we have an active async DNS query too */
                        CFRunLoopAddSource(runLoop, targetPrivate->dnsRLS, runLoopMode);
                }
        }
 
-       __schedule(target, runLoop, runLoopMode, targetPrivate->rlList);
+       _SC_schedule(target, runLoop, runLoopMode, targetPrivate->rlList);
 
        /* schedule the SCNetworkReachability run loop source */
 
-       if (!__isScheduled(NULL, runLoop, runLoopMode, hn_rlList)) {
+       if (!_SC_isScheduled(NULL, runLoop, runLoopMode, hn_rlList)) {
                /*
                 * if we do not already have SC notifications scheduled with
                 * this runLoop / runLoopMode
@@ -2437,7 +2447,7 @@ SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef target,
                CFRunLoopAddSource(runLoop, hn_storeRLS, runLoopMode);
        }
 
-       __schedule(target, runLoop, runLoopMode, hn_rlList);
+       _SC_schedule(target, runLoop, runLoopMode, hn_rlList);
        CFSetAddValue(hn_targets, target);
 
        if (init) {
@@ -2458,13 +2468,13 @@ SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef       target,
                        targetPrivate->flags    = flags;
                        targetPrivate->if_index = if_index;
                        CFRunLoopSourceSignal(targetPrivate->rls);
-                       __signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
+                       _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
                } else {
                        /* if reachability status not available, async lookup started */
                        targetPrivate->flags    = 0;
                        targetPrivate->if_index = 0;
                }
-               if (store) CFRelease(store);
+               if (store != NULL) CFRelease(store);
        }
 
        ok = TRUE;
@@ -2494,24 +2504,24 @@ SCNetworkReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef     target,
        pthread_mutex_lock(&hn_lock);
        pthread_mutex_lock(&targetPrivate->lock);
 
-       if (!targetPrivate->rls) {
+       if (targetPrivate->rls == NULL) {
                /* if not currently scheduled */
                goto done;
        }
 
-       if (!__unschedule(NULL, runLoop, runLoopMode, targetPrivate->rlList, FALSE)) {
+       if (!_SC_unschedule(NULL, runLoop, runLoopMode, targetPrivate->rlList, FALSE)) {
                /* if not currently scheduled */
                goto done;
        }
 
        n = CFArrayGetCount(targetPrivate->rlList);
-       if (n == 0 || !__isScheduled(NULL, runLoop, runLoopMode, targetPrivate->rlList)) {
+       if (n == 0 || !_SC_isScheduled(NULL, runLoop, runLoopMode, targetPrivate->rlList)) {
                /*
                 * if this host is no longer scheduled for this runLoop / runLoopMode
                 */
                CFRunLoopRemoveSource(runLoop, targetPrivate->rls, runLoopMode);
 
-               if (targetPrivate->dnsRLS) {
+               if (targetPrivate->dnsRLS != NULL) {
                        /* if we have an active async DNS query too */
                        CFRunLoopRemoveSource(runLoop, targetPrivate->dnsRLS, runLoopMode);
                }
@@ -2520,19 +2530,17 @@ SCNetworkReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef     target,
                        /*
                         * if this host is no longer scheduled
                         */
-                       CFRelease(targetPrivate->rls);          /* cleanup SCNetworkReachability resources */
+                       CFRunLoopSourceInvalidate(targetPrivate->rls);  /* cleanup SCNetworkReachability resources */
+                       CFRelease(targetPrivate->rls);
                        targetPrivate->rls = NULL;
                        CFRelease(targetPrivate->rlList);
                        targetPrivate->rlList = NULL;
-                       CFSetRemoveValue(hn_targets, target);   /* cleanup notification resources */
+                       CFSetRemoveValue(hn_targets, target);           /* cleanup notification resources */
 
                        if (targetPrivate->dnsPort) {
                                /* if we have an active async DNS query too */
-#ifdef CHECK_IPV6_REACHABILITY
                                lu_async_call_cancel(CFMachPortGetPort(targetPrivate->dnsPort));
-#else  /* CHECK_IPV6_REACHABILITY */
-                               getipnodebyname_async_cancel(CFMachPortGetPort(targetPrivate->dnsPort));
-#endif /* CHECK_IPV6_REACHABILITY */
+                               CFRunLoopSourceInvalidate(targetPrivate->dnsRLS);
                                CFRelease(targetPrivate->dnsRLS);
                                targetPrivate->dnsRLS = NULL;
                                CFRelease(targetPrivate->dnsPort);
@@ -2541,10 +2549,10 @@ SCNetworkReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef     target,
                }
        }
 
-       (void)__unschedule(target, runLoop, runLoopMode, hn_rlList, FALSE);
+       (void)_SC_unschedule(target, runLoop, runLoopMode, hn_rlList, FALSE);
 
        n = CFArrayGetCount(hn_rlList);
-       if (n == 0 || !__isScheduled(NULL, runLoop, runLoopMode, hn_rlList)) {
+       if (n == 0 || !_SC_isScheduled(NULL, runLoop, runLoopMode, hn_rlList)) {
                /*
                 * if we no longer have any addresses scheduled for
                 * this runLoop / runLoopMode
@@ -2556,17 +2564,21 @@ SCNetworkReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef     target,
                         * if we are no longer monitoring any addresses
                         */
                        CFRelease(hn_targets);
+                       hn_targets = NULL;
                        CFRelease(hn_rlList);
+                       hn_rlList = NULL;
+                       CFRunLoopSourceInvalidate(hn_storeRLS);
                        CFRelease(hn_storeRLS);
+                       hn_storeRLS = NULL;
                        CFRelease(hn_store);
                        hn_store = NULL;
 
                        /*
                         * until we start monitoring again, ensure that
-                        * all subsequent reachability-by-name checks
-                        * call res_init()
+                        * any resources associated with tracking the
+                        * DNS configuration have been released.
                         */
-                       needDNS = TRUE;
+                       dns_configuration_unwatch();
                }
        }