[PATCH 09/10] mDNSResponder: Update to v878.270.2

Sebastian Huber sebastian.huber at embedded-brains.de
Fri Jun 19 11:02:23 UTC 2020


The sources can be obtained via:

https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-878.270.2.tar.gz

Update #4010.
---
 mDNSResponder/Makefile                        |   2 +-
 mDNSResponder/mDNSCore/DNSCommon.c            |  15 +-
 mDNSResponder/mDNSCore/DNSCommon.h            |   2 +
 mDNSResponder/mDNSCore/dnssec.c               |   2 +-
 mDNSResponder/mDNSCore/mDNS.c                 |  51 ++++---
 mDNSResponder/mDNSCore/mDNSDebug.h            |   1 +
 mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h      |  22 +--
 mDNSResponder/mDNSCore/uDNS.c                 | 136 +++++++++---------
 mDNSResponder/mDNSMacOSX/DNS64.c              |  26 ++--
 mDNSResponder/mDNSMacOSX/DNS64.h              |   4 +-
 mDNSResponder/mDNSMacOSX/daemon.c             |   6 +-
 mDNSResponder/mDNSMacOSX/mDNSMacOSX.c         | 109 ++++++++++----
 mDNSResponder/mDNSMacOSX/mDNSMacOSX.h         |   7 +-
 .../mDNSResponder.xcodeproj/project.pbxproj   |   8 ++
 mDNSResponder/mDNSPosix/mDNSPosix.c           |   1 +
 mDNSResponder/mDNSShared/dns_sd.h             |   2 +-
 mDNSResponder/mDNSShared/dnsextd.c            |   2 +-
 mDNSResponder/mDNSShared/uds_daemon.c         |   2 +-
 mDNSResponder/unittests/uds_daemon_ut.c       |   2 +-
 19 files changed, 245 insertions(+), 155 deletions(-)

diff --git a/mDNSResponder/Makefile b/mDNSResponder/Makefile
index b647c70a..68ba6b64 100644
--- a/mDNSResponder/Makefile
+++ b/mDNSResponder/Makefile
@@ -17,7 +17,7 @@
 
 include $(MAKEFILEPATH)/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-878.260.1"
+MVERS = "mDNSResponder-878.270.2"
 
 VER =
 ifneq ($(strip $(GCC_VERSION)),)
diff --git a/mDNSResponder/mDNSCore/DNSCommon.c b/mDNSResponder/mDNSCore/DNSCommon.c
index f3150762..15a92200 100644
--- a/mDNSResponder/mDNSCore/DNSCommon.c
+++ b/mDNSResponder/mDNSCore/DNSCommon.c
@@ -1790,8 +1790,8 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr
     // Resource record received via unicast, the resolver group ID should match ?
     if (!rr->InterfaceID)
     {
-        mDNSu16 idr = (rr->rDNSServer ? rr->rDNSServer->resGroupID : 0);
-        mDNSu16 idq = (q->qDNSServer ? q->qDNSServer->resGroupID : 0);
+        const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0;
+        const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0;
         if (idr != idq) return(mDNSfalse);
         if (!DNSSECRecordAnswersQuestion(rr, q, &checkType)) return mDNSfalse;
     }
@@ -1924,8 +1924,8 @@ mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr,
     // both the DNSServers are assumed to be NULL in that case
     if (!rr->InterfaceID)
     {
-        mDNSu16 idr = (rr->rDNSServer ? rr->rDNSServer->resGroupID : 0);
-        mDNSu16 idq = (q->qDNSServer ? q->qDNSServer->resGroupID : 0);
+        const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0;
+        const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0;
         if (idr != idq) return(mDNSfalse);
     }
 
@@ -4551,3 +4551,10 @@ mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt,
 
     return(length);
 }
+
+mDNSexport mDNSu32 mDNS_GetNextResolverGroupID(void)
+{
+    static mDNSu32 lastID = 0;
+    if (++lastID == 0) lastID = 1; // Valid resolver group IDs are non-zero.
+    return(lastID);
+}
diff --git a/mDNSResponder/mDNSCore/DNSCommon.h b/mDNSResponder/mDNSCore/DNSCommon.h
index 48dfe102..4291577e 100644
--- a/mDNSResponder/mDNSCore/DNSCommon.h
+++ b/mDNSResponder/mDNSCore/DNSCommon.h
@@ -98,6 +98,8 @@ extern mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf
 
 extern mDNSu32 mDNSRandom(mDNSu32 max);     // Returns pseudo-random result from zero to max inclusive
 
+extern mDNSu32 mDNS_GetNextResolverGroupID(void);
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
diff --git a/mDNSResponder/mDNSCore/dnssec.c b/mDNSResponder/mDNSCore/dnssec.c
index 9525655f..3010d6f2 100644
--- a/mDNSResponder/mDNSCore/dnssec.c
+++ b/mDNSResponder/mDNSCore/dnssec.c
@@ -3084,7 +3084,7 @@ mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *
     if (!dv)
     {
         first = mDNStrue;
-        if (!q->qDNSServer || q->qDNSServer->cellIntf)
+        if (!q->qDNSServer || q->qDNSServer->isCell)
         {
             LogDNSSEC("VerifySignature: Disabled");
             return;
diff --git a/mDNSResponder/mDNSCore/mDNS.c b/mDNSResponder/mDNSCore/mDNS.c
index bf1bce2f..4e70ef83 100755
--- a/mDNSResponder/mDNSCore/mDNS.c
+++ b/mDNSResponder/mDNSCore/mDNS.c
@@ -4170,7 +4170,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
         mDNSBool            isForCellular;
 
         queryName = q->metrics.originalQName ? q->metrics.originalQName : &q->qname;
-        isForCellular = (q->qDNSServer && q->qDNSServer->cellIntf);
+        isForCellular = (q->qDNSServer && q->qDNSServer->isCell);
         if (!q->metrics.answered)
         {
             if (q->metrics.querySendCount > 0)
@@ -4269,7 +4269,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
 #if USE_DNS64
             if (DNS64ShouldAnswerQuestion(q, &rr->resrec))
             {
-                DNS64AnswerQuestion(m, q, &rr->resrec, AddRecord);
+                DNS64AnswerCurrentQuestion(m, &rr->resrec, AddRecord);
             }
             else
 #endif
@@ -7410,8 +7410,8 @@ mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const Res
     {
         if (!pktrr->InterfaceID)
         {
-            mDNSu16 id1 = (pktrr->rDNSServer ? pktrr->rDNSServer->resGroupID : 0);
-            mDNSu16 id2 = (rr->resrec.rDNSServer ? rr->resrec.rDNSServer->resGroupID : 0);
+            const mDNSu32 id1 = (pktrr->rDNSServer ? pktrr->rDNSServer->resGroupID : 0);
+            const mDNSu32 id2 = (rr->resrec.rDNSServer ? rr->resrec.rDNSServer->resGroupID : 0);
             match = (id1 == id2);
         }
         else match = (pktrr->InterfaceID == rr->resrec.InterfaceID);
@@ -8737,8 +8737,8 @@ mDNSlocal CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage
         // Resource record received via unicast, the resGroupID should match ?
         if (!InterfaceID)
         {
-            mDNSu16 id1 = (rr->resrec.rDNSServer ? rr->resrec.rDNSServer->resGroupID : 0);
-            mDNSu16 id2 = (m->rec.r.resrec.rDNSServer ? m->rec.r.resrec.rDNSServer->resGroupID : 0);
+            const mDNSu32 id1 = (rr->resrec.rDNSServer ? rr->resrec.rDNSServer->resGroupID : 0);
+            const mDNSu32 id2 = (m->rec.r.resrec.rDNSServer ? m->rec.r.resrec.rDNSServer->resGroupID : 0);
             match = (id1 == id2);
         }
         else
@@ -11031,14 +11031,14 @@ mDNSexport mDNSBool DomainEnumQuery(const domainname *qname)
 // Note: InterfaceID is the InterfaceID of the question
 mDNSlocal mDNSBool DNSServerMatch(DNSServer *d, mDNSInterfaceID InterfaceID, mDNSs32 ServiceID)
 {
-    // 1) Unscoped questions (NULL InterfaceID) should  consider *only* unscoped DNSServers ( DNSServer
-    // with "scoped" set to kScopeNone)
+    // 1) Unscoped questions (NULL InterfaceID) should consider *only* unscoped DNSServers ( DNSServer
+    // with scopeType set to kScopeNone)
     //
     // 2) Scoped questions (non-NULL InterfaceID) should consider *only* scoped DNSServers (DNSServer
-    // with "scoped" set to kScopeInterfaceId) and their InterfaceIDs should match.
+    // with scopeType set to kScopeInterfaceID) and their InterfaceIDs should match.
     //
     // 3) Scoped questions (non-zero ServiceID) should consider *only* scoped DNSServers (DNSServer
-    // with "scoped" set to kScopeServiceID) and their ServiceIDs should match.
+    // with scopeType set to kScopeServiceID) and their ServiceIDs should match.
     //
     // The first condition in the "if" statement checks to see if both the question and the DNSServer are
     // unscoped. The question is unscoped only if InterfaceID is zero and ServiceID is -1.
@@ -11059,9 +11059,9 @@ mDNSlocal mDNSBool DNSServerMatch(DNSServer *d, mDNSInterfaceID InterfaceID, mDN
     // Note: mDNSInterface_Unicast is used only by .local unicast questions and are treated as unscoped.
     // If a question is scoped both to InterfaceID and ServiceID, the question will be scoped to InterfaceID.
 
-    if (((d->scoped == kScopeNone) && ((!InterfaceID && ServiceID == -1) || InterfaceID == mDNSInterface_Unicast)) ||
-        ((d->scoped == kScopeInterfaceID) && d->interface == InterfaceID) ||
-        ((d->scoped == kScopeServiceID) && d->serviceID == ServiceID))
+    if (((d->scopeType == kScopeNone) && ((!InterfaceID && ServiceID == -1) || InterfaceID == mDNSInterface_Unicast)) ||
+        ((d->scopeType == kScopeInterfaceID) && d->interface == InterfaceID) ||
+        ((d->scopeType == kScopeServiceID) && d->serviceID == ServiceID))
     {
         return mDNStrue;
     }
@@ -11099,14 +11099,16 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
         // Note: DNS configuration change will help pick the new dns servers but currently it does not affect the timeout
 
         // Skip DNSServers that are InterfaceID Scoped but have no valid interfaceid set OR DNSServers that are ServiceID Scoped but have no valid serviceid set
-        if ((curr->scoped == kScopeInterfaceID && curr->interface == mDNSInterface_Any) || (curr->scoped == kScopeServiceID && curr->serviceID <= 0))
+        if (((curr->scopeType == kScopeInterfaceID) && (curr->interface == mDNSInterface_Any)) ||
+            ((curr->scopeType == kScopeServiceID) && (curr->serviceID <= 0)))
         {
-            LogInfo("SetValidDNSServers: ScopeType[%d] Skipping DNS server %#a (Domain %##s) Interface:[%p] Serviceid:[%d]", curr->scoped, &curr->addr, curr->domain.c, curr->interface, curr->serviceID);
+            LogInfo("SetValidDNSServers: ScopeType[%d] Skipping DNS server %#a (Domain %##s) Interface:[%p] Serviceid:[%d]",
+                (int)curr->scopeType, &curr->addr, curr->domain.c, curr->interface, curr->serviceID);
             continue;
         }
 
         currcount = CountLabels(&curr->domain);
-        if ((!curr->cellIntf || (!DEQuery && !(question->flags & kDNSServiceFlagsDenyCellular))) &&
+        if ((!curr->isCell || (!DEQuery && !(question->flags & kDNSServiceFlagsDenyCellular))) &&
             (!curr->isExpensive || !(question->flags & kDNSServiceFlagsDenyExpensive)) &&
             DNSServerMatch(curr, question->InterfaceID, question->ServiceID))
         {
@@ -11130,7 +11132,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
                        curr->interface);
                 timeout += curr->timeout;
                 if (DEQuery)
-                    debugf("DomainEnumQuery: Question %##s, DNSServer %#a, cell %d", question->qname.c, &curr->addr, curr->cellIntf);
+                    debugf("DomainEnumQuery: Question %##s, DNSServer %#a, cell %d", question->qname.c, &curr->addr, curr->isCell);
                 bit_set_opaque128(question->validDNSServers, index);
             }
         }
@@ -11999,7 +12001,7 @@ mDNSlocal void InitDNSSECProxyState(mDNS *const m, DNSQuestion *const question)
     // at ValidationRequired setting also.
     if (question->qDNSServer)
     {
-        if (question->qDNSServer->cellIntf)
+        if (question->qDNSServer->isCell)
         {
             debugf("InitDNSSECProxyState: Turning off validation for %##s (%s); going over cell", question->qname.c, DNSTypeName(question->qtype));
             question->ValidationRequired = mDNSfalse;
@@ -12234,7 +12236,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
         mDNSu32             durationMs;
 
         queryName  = question->metrics.originalQName ? question->metrics.originalQName : &question->qname;
-        isForCell  = (question->qDNSServer && question->qDNSServer->cellIntf);
+        isForCell  = (question->qDNSServer && question->qDNSServer->isCell);
         durationMs = ((m->timenow - question->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond;
         MetricsUpdateDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, question->metrics.expiredAnswerState, durationMs, isForCell);
     }
@@ -13248,11 +13250,14 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
             // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
             for (q = m->Questions; q; q=q->next)
             {
-                if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0;
-                if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)
+                if (mDNSOpaque16IsZero(q->TargetQID))                   // Only deactivate multicast quesstions. (Unicast questions are stopped when/if the associated DNS server group goes away.)
                 {
-                    q->FlappingInterface2 = q->FlappingInterface1;
-                    q->FlappingInterface1 = set->InterfaceID;       // Keep history of the last two interfaces to go away
+                    if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0;
+                    if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)
+                    {
+                        q->FlappingInterface2 = q->FlappingInterface1;
+                        q->FlappingInterface1 = set->InterfaceID;       // Keep history of the last two interfaces to go away
+                    }
                 }
             }
 
diff --git a/mDNSResponder/mDNSCore/mDNSDebug.h b/mDNSResponder/mDNSCore/mDNSDebug.h
index d690fd2b..14b03c9e 100755
--- a/mDNSResponder/mDNSCore/mDNSDebug.h
+++ b/mDNSResponder/mDNSCore/mDNSDebug.h
@@ -166,6 +166,7 @@ extern void udns_validatelists(void *const v);
 extern void LogMemCorruption(const char *format, ...);
 #else
 #define mallocL(X,Y) malloc(Y)
+#define callocL(X,Y) calloc(1, Y)
 #define freeL(X,Y) free(Y)
 #endif
 
diff --git a/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h b/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
index e9f3bb8a..d714de49 100755
--- a/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
+++ b/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
@@ -1346,15 +1346,14 @@ enum {
 };
 typedef mDNSu8 MortalityState;
 
-// scoped values for DNSServer matching
-enum
+// ScopeType values for DNSServer matching
+typedef enum
 {
     kScopeNone         = 0,        // DNS server used by unscoped questions
     kScopeInterfaceID  = 1,        // Scoped DNS server used only by scoped questions
-    kScopeServiceID    = 2,         // Service specific DNS server used only by questions
+    kScopeServiceID    = 2         // Service specific DNS server used only by questions
                                    // have a matching serviceID
-    kScopesMaxCount    = 3         // Max count for scopes enum
-};
+} ScopeType;
 
 // Note: DNSSECAware is set if we are able to get a valid response to
 // a DNSSEC question. In some cases it is possible that the proxy
@@ -1373,11 +1372,11 @@ typedef struct DNSServer
     mDNSu32 flags;              // Set when we're planning to delete this from the list
     domainname domain;          // name->server matching for "split dns"
     mDNSs32 penaltyTime;        // amount of time this server is penalized
-    mDNSu32 scoped;             // See the scoped enum above
+    ScopeType scopeType;        // See the ScopeType enum above
     mDNSu32 timeout;            // timeout value for questions
-    mDNSu16 resGroupID;         // ID of the resolver group that contains this DNSServer
+    mDNSu32 resGroupID;         // ID of the resolver group that contains this DNSServer
     mDNSu8 retransDO;           // Total Retransmissions for queries sent with DO option
-    mDNSBool cellIntf;          // Resolver from Cellular Interface?
+    mDNSBool isCell;            // Resolver from Cellular Interface?
     mDNSBool req_A;             // If set, send v4 query (DNSConfig allows A queries)
     mDNSBool req_AAAA;          // If set, send v6 query (DNSConfig allows AAAA queries)
     mDNSBool req_DO;            // If set, okay to send DNSSEC queries (EDNS DO bit is supported)
@@ -2616,7 +2615,7 @@ extern const mDNSOpaque64 zeroOpaque64;
 extern const mDNSOpaque128 zeroOpaque128;
     
 extern mDNSBool StrictUnicastOrdering;
-extern mDNSu8 NumUnicastDNSServers;
+extern int NumUnicastDNSServers;
 #if APPLE_OSX_mDNSResponder
 extern mDNSu8 NumUnreachableDNSServers;
 #endif
@@ -3072,8 +3071,8 @@ extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCa
 extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
 extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr,  const mDNSAddr *v6addr, const mDNSAddr *router);
 extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, mDNSs32 serviceID, const mDNSAddr *addr,
-                                    const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46,
-                                    mDNSu16 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO);
+                                    const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46,
+                                    mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO);
 extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 responseFlags);
 extern void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID);
 
@@ -3166,6 +3165,7 @@ extern void mDNSPlatformQsort       (void *base, int nel, int width, int (*compa
 #define         mDNSPlatformMemAllocate(X) mallocL(# X, X)
 #else
 extern void *   mDNSPlatformMemAllocate (mDNSu32 len);
+extern void *   mDNSPlatformMemAllocateClear(mDNSu32 len);
 #endif
 extern void     mDNSPlatformMemFree     (void *mem);
 
diff --git a/mDNSResponder/mDNSCore/uDNS.c b/mDNSResponder/mDNSCore/uDNS.c
index 1f9b1543..6214c262 100755
--- a/mDNSResponder/mDNSCore/uDNS.c
+++ b/mDNSResponder/mDNSCore/uDNS.c
@@ -53,7 +53,7 @@ mDNSBool StrictUnicastOrdering = mDNSfalse;
 // question. Bit position is the index into the DNS server list. This is done so to try all
 // the servers exactly once before giving up. If we could allocate memory in the core, then
 // arbitrary limitation of 128 DNSServers can be removed.
-mDNSu8 NumUnicastDNSServers = 0;
+int NumUnicastDNSServers = 0;
 #define MAX_UNICAST_DNS_SERVERS 128
 #if APPLE_OSX_mDNSResponder
 mDNSu8 NumUnreachableDNSServers = 0;
@@ -118,11 +118,11 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mDNSu32 random)
 #define TrueFalseStr(X) ((X) ? "true" : "false")
 
 mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSs32 serviceID, const mDNSAddr *addr,
-                                        const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46,
-                                        mDNSu16 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
+                                        const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool isCell, mDNSBool isExpensive, mDNSBool isCLAT46,
+                                        mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
 {
-    DNSServer **p = &m->DNSServers;
-    DNSServer *tmp = mDNSNULL;
+    DNSServer **p;
+    DNSServer *server;
 
     if ((NumUnicastDNSServers + 1) > MAX_UNICAST_DNS_SERVERS)
     {
@@ -133,29 +133,39 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
     if (!d)
         d = (const domainname *)"";
 
-    LogInfo("mDNS_AddDNSServer(%d): Adding %#a for %##s, InterfaceID %p, serviceID %u, scoped %d, resGroupID %d req_A %s, req_AAAA %s, cell %s, expensive %s, CLAT46 %s, req_DO %s",
-        NumUnicastDNSServers, addr, d->c, interface, serviceID, scoped, resGroupID,
-        TrueFalseStr(reqA), TrueFalseStr(reqAAAA), TrueFalseStr(cellIntf), TrueFalseStr(isExpensive), TrueFalseStr(isCLAT46), TrueFalseStr(reqDO));
+    LogInfo("mDNS_AddDNSServer(%d): Adding %#a for %##s, InterfaceID %p, serviceID %u, scopeType %d, resGroupID %d req_A %s, req_AAAA %s, cell %s, expensive %s, CLAT46 %s, req_DO %s",
+        NumUnicastDNSServers, addr, d->c, interface, serviceID, (int)scopeType, resGroupID,
+        TrueFalseStr(reqA), TrueFalseStr(reqAAAA), TrueFalseStr(isCell), TrueFalseStr(isExpensive), TrueFalseStr(isCLAT46), TrueFalseStr(reqDO));
 
     mDNS_CheckLock(m);
 
-    while (*p)  // Check if we already have this {interface,address,port,domain} tuple registered + reqA/reqAAAA bits
-    {
-        if ((*p)->scoped == scoped && (*p)->interface == interface && (*p)->serviceID == serviceID &&
-            mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d) &&
-            (*p)->req_A == reqA && (*p)->req_AAAA == reqAAAA)
-        {
-            if (!((*p)->flags & DNSServer_FlagDelete))
+    for (p = &m->DNSServers; (server = *p) != mDNSNULL; p = &server->next)
+    {
+        if ((server->scopeType     == scopeType)     &&
+            (server->interface     == interface)     &&
+            (server->serviceID     == serviceID)     &&
+            mDNSSameAddress(&server->addr, addr)     &&
+            mDNSSameIPPort(server->port, port)       &&
+            (server->timeout       == timeout)       &&
+            (!!server->isCell      == !!isCell)      &&
+            (!!server->isExpensive == !!isExpensive) &&
+            (!!server->isCLAT46    == !!isCLAT46)    &&
+            (!!server->req_A       == !!reqA)        &&
+            (!!server->req_AAAA    == !!reqAAAA)     &&
+            (!!server->req_DO      == !!reqDO)       &&
+            SameDomainName(&server->domain, d))
+        {
+            if (!(server->flags & DNSServer_FlagDelete))
                 debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr, mDNSVal16(port), d->c, interface);
-            tmp = *p;
-            *p = tmp->next;
-            tmp->next = mDNSNULL;
-        }
-        else
-        {
-            p=&(*p)->next;
+            *p = server->next;
+            server->next = mDNSNULL;
+            break;
         }
     }
+    while (*p)
+    {
+        p = &(*p)->next;
+    }
 
     // NumUnicastDNSServers is the count of active DNS servers i.e., ones that are not marked
     // with DNSServer_FlagDelete. We should increment it:
@@ -167,61 +177,59 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
     // We have already accounted for it when it was added for the first time. This case happens when
     // we add DNS servers with the same address multiple times (mis-configuration).
 
-    if (!tmp || (tmp->flags & DNSServer_FlagDelete))
+    if (!server || (server->flags & DNSServer_FlagDelete))
         NumUnicastDNSServers++;
 
-
-    if (tmp)
+    if (server)
     {
-#if APPLE_OSX_mDNSResponder
-        if (tmp->flags & DNSServer_FlagDelete)
+        if (server->flags & DNSServer_FlagDelete)
         {
-            tmp->flags &= ~DNSServer_FlagUnreachable;
-        }
+#if APPLE_OSX_mDNSResponder
+            server->flags &= ~DNSServer_FlagUnreachable;
 #endif
-        tmp->flags &= ~DNSServer_FlagDelete;
-        *p = tmp; // move to end of list, to ensure ordering from platform layer
+            server->flags &= ~DNSServer_FlagDelete;
+        }
+        *p = server; // move to end of list, to ensure ordering from platform layer
     }
     else
     {
         // allocate, add to list
-        *p = mDNSPlatformMemAllocate(sizeof(**p));
-        if (!*p)
+        server = (DNSServer *)mDNSPlatformMemAllocateClear(sizeof(*server));
+        if (!server)
         {
             LogMsg("Error: mDNS_AddDNSServer - malloc");
         }
         else
         {
-            (*p)->scoped      = scoped;
-            (*p)->interface   = interface;
-            (*p)->serviceID   = serviceID;
-            (*p)->addr        = *addr;
-            (*p)->port        = port;
-            (*p)->flags       = DNSServer_FlagNew;
-            (*p)->timeout     = timeout;
-            (*p)->cellIntf    = cellIntf;
-            (*p)->isExpensive = isExpensive;
-            (*p)->isCLAT46    = isCLAT46;
-            (*p)->req_A       = reqA;
-            (*p)->req_AAAA    = reqAAAA;
-            (*p)->req_DO      = reqDO;
+            server->scopeType   = scopeType;
+            server->interface   = interface;
+            server->serviceID   = serviceID;
+            server->addr        = *addr;
+            server->port        = port;
+            server->flags       = DNSServer_FlagNew;
+            server->timeout     = timeout;
+            server->isCell      = isCell;
+            server->isExpensive = isExpensive;
+            server->isCLAT46    = isCLAT46;
+            server->req_A       = reqA;
+            server->req_AAAA    = reqAAAA;
+            server->req_DO      = reqDO;
             // We start off assuming that the DNS server is not DNSSEC aware and
             // when we receive the first response to a DNSSEC question, we set
             // it to true.
-            (*p)->DNSSECAware = mDNSfalse;
-            (*p)->retransDO = 0;
-            AssignDomainName(&(*p)->domain, d);
-            (*p)->next = mDNSNULL;
+            server->DNSSECAware = mDNSfalse;
+            server->retransDO = 0;
+            AssignDomainName(&server->domain, d);
+            *p = server;
         }
     }
-    if (*p) {
-        (*p)->penaltyTime = 0;
-        // We always update the ID (not just when we allocate a new instance) because we could
-        // be adding a new non-scoped resolver with a new ID and we want all the non-scoped
-        // resolvers belong to the same group.
-        (*p)->resGroupID  = resGroupID;
+    if (server) {
+        server->penaltyTime = 0;
+        // We always update the ID (not just when we allocate a new instance) because we want
+        // all the resGroupIDs for a particular domain to match.
+        server->resGroupID  = resGroupID;
     }
-    return(*p);
+    return(server);
 }
 
 // PenalizeDNSServer is called when the number of queries to the unicast
@@ -1331,7 +1339,7 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
             // LLQ Polling mode or non-LLQ uDNS over TCP
             InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, (DNSSECQuestion(q) ? DNSSecQFlags : uQueryFlags));
             end = putQuestion(&tcpInfo->request, tcpInfo->request.data, tcpInfo->request.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
-            if (DNSSECQuestion(q) && q->qDNSServer && !q->qDNSServer->cellIntf)
+            if (DNSSECQuestion(q) && q->qDNSServer && !q->qDNSServer->isCell)
             {
                 if (q->ProxyQuestion)
                     end = DNSProxySetAttributes(q, &tcpInfo->request.h, &tcpInfo->request, end, tcpInfo->request.data + AbsoluteMaxDNSMessageData);
@@ -4725,7 +4733,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
             InitializeDNSMessage(&m->omsg.h, q->TargetQID, (DNSSECQuestion(q) ? DNSSecQFlags : uQueryFlags));
 
             end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
-            if (DNSSECQuestion(q) && !q->qDNSServer->cellIntf)
+            if (DNSSECQuestion(q) && !q->qDNSServer->isCell)
             {
                 if (q->ProxyQuestion)
                     end = DNSProxySetAttributes(q, &m->omsg.h, &m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData);
@@ -4851,14 +4859,14 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                             q->ThisQInterval = LLQ_POLL_INTERVAL;
                         LogInfo("uDNS_CheckCurrentQuestion: private non polling question for %##s (%s) will be retried in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
                     }
-                    if (q->qDNSServer->cellIntf)
+                    if (q->qDNSServer->isCell)
                     {
                         // We don't want to retransmit too soon. Schedule our first retransmisson at
                         // MIN_UCAST_RETRANS_TIMEOUT seconds.
                         if (q->ThisQInterval < MIN_UCAST_RETRANS_TIMEOUT)
                             q->ThisQInterval = MIN_UCAST_RETRANS_TIMEOUT;
                     }
-                    debugf("uDNS_CheckCurrentQuestion: Increased ThisQInterval to %d for %##s (%s), cell %d", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer->cellIntf);
+                    debugf("uDNS_CheckCurrentQuestion: Increased ThisQInterval to %d for %##s (%s), cell %d", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer->isCell);
                 }
                 q->LastQTime = m->timenow;
             }
@@ -6205,7 +6213,7 @@ mDNSexport mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traver
 }
 
 mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSs32 serviceID, const mDNSAddr *addr,
-                                        const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSu16 resGroupID,
+                                        const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool isCell, mDNSBool isExpensive, mDNSu32 resGroupID,
                                         mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
 {
     (void) m;
@@ -6214,9 +6222,9 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
     (void) serviceID;
     (void) addr;
     (void) port;
-    (void) scoped;
+    (void) scopeType;
     (void) timeout;
-    (void) cellIntf;
+    (void) isCell;
     (void) isExpensive;
     (void) resGroupID;
     (void) reqA;
diff --git a/mDNSResponder/mDNSMacOSX/DNS64.c b/mDNSResponder/mDNSMacOSX/DNS64.c
index 6fef38f8..e167cdde 100644
--- a/mDNSResponder/mDNSMacOSX/DNS64.c
+++ b/mDNSResponder/mDNSMacOSX/DNS64.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Apple Inc. All rights reserved.
+ * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -54,12 +54,12 @@ check_compile_time(sizeof_field(DNS64, qnameStash)  == kDNS64IPv4OnlyFQDNLength)
 //  Local Prototypes
 //===========================================================================================================================
 
-mDNSlocal mStatus   DNS64GetIPv6Addrs(mDNS *m, mDNSu16 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount);
-mDNSlocal mStatus   DNS64GetPrefixes(mDNS *m, mDNSu16 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount);
+mDNSlocal mStatus   DNS64GetIPv6Addrs(mDNS *m, mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount);
+mDNSlocal mStatus   DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount);
 mDNSlocal mDNSBool  DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6_addr *outAddr);
 mDNSlocal mDNSu32   DNS64IPv4OnlyFQDNHash(void);
 mDNSlocal void      DNS64RestartQuestion(mDNS *m, DNSQuestion *q, DNS64State newState);
-mDNSlocal mDNSBool  DNS64TestIPv6Synthesis(mDNS *m, mDNSu16 inResGroupID, const mDNSv4Addr *inV4Addr);
+mDNSlocal mDNSBool  DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr);
 
 //===========================================================================================================================
 //  DNS64StateMachine
@@ -174,10 +174,10 @@ mDNSexport mDNSBool DNS64StateMachine(mDNS *m, DNSQuestion *inQ, const ResourceR
 }
 
 //===========================================================================================================================
-//  DNS64AnswerQuestion
+//  DNS64AnswerCurrentQuestion
 //===========================================================================================================================
 
-mDNSexport mStatus DNS64AnswerQuestion(mDNS *m, DNSQuestion *inQ, const ResourceRecord *inRR, QC_result inResult)
+mDNSexport mStatus DNS64AnswerCurrentQuestion(mDNS *m, const ResourceRecord *inRR, QC_result inResult)
 {
     mStatus                 err;
     ResourceRecord          newRR;
@@ -187,10 +187,11 @@ mDNSexport mStatus DNS64AnswerQuestion(mDNS *m, DNSQuestion *inQ, const Resource
     uint32_t                i;
     struct in_addr          v4Addr;
     struct in6_addr         synthV6;
+    DNSQuestion * const     q = m->CurrentQuestion;
 
-    require_action_quiet(inQ->qDNSServer, exit, err = mStatus_BadParamErr);
+    require_action_quiet(q->qDNSServer, exit, err = mStatus_BadParamErr);
 
-    err = DNS64GetPrefixes(m, inQ->qDNSServer->resGroupID, &prefixes, &prefixCount);
+    err = DNS64GetPrefixes(m, q->qDNSServer->resGroupID, &prefixes, &prefixCount);
     require_noerr_quiet(err, exit);
 
     newRR               = *inRR;
@@ -205,7 +206,8 @@ mDNSexport mStatus DNS64AnswerQuestion(mDNS *m, DNSQuestion *inQ, const Resource
         if (nw_nat64_synthesize_v6(&prefixes[i], &v4Addr, &synthV6))
         {
             memcpy(rdata.u.ipv6.b, synthV6.s6_addr, 16);
-            inQ->QuestionCallback(m, inQ, &newRR, inResult);
+            q->QuestionCallback(m, q, &newRR, inResult);
+            if (m->CurrentQuestion != q) break;
         }
     }
     err = mStatus_NoError;
@@ -354,7 +356,7 @@ mDNSexport void DNS64RestartQuestions(mDNS *m)
     ((RR)->RecordType != kDNSRecordTypePacketNegative) &&   \
     !(RR)->InterfaceID)
 
-mDNSlocal mStatus DNS64GetIPv6Addrs(mDNS *m, const mDNSu16 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount)
+mDNSlocal mStatus DNS64GetIPv6Addrs(mDNS *m, const mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount)
 {
     mStatus                 err;
     const CacheGroup *      cg;
@@ -403,7 +405,7 @@ exit:
 //  DNS64GetPrefixes
 //===========================================================================================================================
 
-mDNSlocal mStatus DNS64GetPrefixes(mDNS *m, mDNSu16 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount)
+mDNSlocal mStatus DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount)
 {
     mStatus                 err;
     struct in6_addr *       v6Addrs;
@@ -535,7 +537,7 @@ mDNSlocal void DNS64RestartQuestion(mDNS *const m, DNSQuestion *inQ, DNS64State
 //  DNS64TestIPv6Synthesis
 //===========================================================================================================================
 
-mDNSlocal mDNSBool DNS64TestIPv6Synthesis(mDNS *m, mDNSu16 inResGroupID, const mDNSv4Addr *inV4Addr)
+mDNSlocal mDNSBool DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr)
 {
     mStatus                 err;
     nw_nat64_prefix_t *     prefixes    = NULL;
diff --git a/mDNSResponder/mDNSMacOSX/DNS64.h b/mDNSResponder/mDNSMacOSX/DNS64.h
index 80eb7feb..dc07dcc1 100644
--- a/mDNSResponder/mDNSMacOSX/DNS64.h
+++ b/mDNSResponder/mDNSMacOSX/DNS64.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Apple Inc. All rights reserved.
+ * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@ extern "C" {
 #endif
 
 mDNSexport mDNSBool DNS64StateMachine(mDNS *m, DNSQuestion *inQ, const ResourceRecord *inRR, QC_result inResult);
-mDNSexport mStatus  DNS64AnswerQuestion(mDNS *m, DNSQuestion *inQ, const ResourceRecord *inRR, QC_result inResult);
+mDNSexport mStatus  DNS64AnswerCurrentQuestion(mDNS *m, const ResourceRecord *inRR, QC_result inResult);
 mDNSexport void     DNS64HandleNewQuestion(mDNS *m, DNSQuestion *inQ);
 mDNSexport void     DNS64ResetState(DNSQuestion *inQ);
 mDNSexport void     DNS64RestartQuestions(mDNS *m);
diff --git a/mDNSResponder/mDNSMacOSX/daemon.c b/mDNSResponder/mDNSMacOSX/daemon.c
index 695e4114..233ffb99 100644
--- a/mDNSResponder/mDNSMacOSX/daemon.c
+++ b/mDNSResponder/mDNSMacOSX/daemon.c
@@ -517,13 +517,13 @@ mDNSexport void INFOCallback(void)
         for (s = mDNSStorage.DNSServers; s; s = s->next)
         {
             NetworkInterfaceInfoOSX *ifx = IfindexToInterfaceInfoOSX(s->interface);
-            LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %d %s %d %d %s %s %s %s %s %s",
+            LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %d %s %d %u %s %s %s %s %s %s",
                           s->domain.c, ifx ? ifx->ifinfo.ifname : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port),
-                          s->penaltyTime ? s->penaltyTime - mDNS_TimeNow(&mDNSStorage) : 0, DNSScopeToString(s->scoped),
+                          s->penaltyTime ? (s->penaltyTime - mDNS_TimeNow(&mDNSStorage)) : 0, DNSScopeToString(s->scopeType),
                           s->timeout, s->resGroupID,
                           s->req_A ? "v4" : "!v4",  
                           s->req_AAAA ? "v6" : "!v6",
-                          s->cellIntf ? "cell" : "!cell",
+                          s->isCell ? "cell" : "!cell",
                           s->isExpensive ? "exp" : "!exp",
                           s->isCLAT46 ? "clat46" : "!clat46",
                           s->DNSSECAware ? "DNSSECAware" : "!DNSSECAware");
diff --git a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c
index b7e53032..126edd03 100644
--- a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c
+++ b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c
@@ -93,7 +93,6 @@
 
 // Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
 #include <Kernel/IOKit/apple80211/apple80211_var.h>
-#include <network_information.h>  // for nwi_state
 
 #if MDNSRESPONDER_BTMM_SUPPORT
 #include <AWACS.h>
@@ -3626,7 +3625,6 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(struct ifaddrs *ifa, mDNSs
 
     i->isExpensive     = (eflags & IFEF_EXPENSIVE) ? mDNStrue: mDNSfalse;
     i->isAWDL          = (eflags & IFEF_AWDL)      ? mDNStrue: mDNSfalse;
-    i->isCLAT46        = (eflags & IFEF_CLAT46)    ? mDNStrue: mDNSfalse;
     if (eflags & IFEF_AWDL)
     {
         // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
@@ -5410,7 +5408,7 @@ mDNSlocal void ConfigSearchDomains(dns_resolver_t *resolver, mDNSInterfaceID int
         {
             if (MakeDomainNameFromDNSNameString(&d, resolver->search[j]) != NULL)
             {
-                static char interface_buf[32];
+                char interface_buf[32];
                 mDNS_snprintf(interface_buf, sizeof(interface_buf), "for interface %s", InterfaceNameForID(&mDNSStorage,  interfaceId));
                 LogInfo("ConfigSearchDomains: (%s) configuring search domain %s %s (generation= %llu)", scopeString,
                         resolver->search[j], (interfaceId == mDNSInterface_Any) ? "" : interface_buf, generation);
@@ -5476,7 +5474,24 @@ mDNSlocal void ConfigNonUnicastResolver(dns_resolver_t *r)
     }
 }
 
-mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID)
+#if !defined(NWI_IFSTATE_FLAGS_HAS_CLAT46)
+#define NWI_IFSTATE_FLAGS_HAS_CLAT46    0x0040
+#endif
+
+mDNSlocal mDNSBool NWIInterfaceHasCLAT46(nwi_state_t state, uint32_t ifIndex)
+{
+    char ifNameBuf[IFNAMSIZ + 1];
+    const char *ifNamePtr = if_indextoname(ifIndex, ifNameBuf);
+    if (!ifNamePtr) return(mDNSfalse);
+
+    const nwi_ifstate_t ifState = nwi_state_get_ifstate(state, ifNamePtr);
+    if (!ifState) return(mDNSfalse);
+
+    const nwi_ifstate_flags flags = nwi_ifstate_get_flags(ifState);
+    return((flags & NWI_IFSTATE_FLAGS_HAS_CLAT46) ? mDNStrue : mDNSfalse);
+}
+
+mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu32 resGroupID)
 {
     int n;
     domainname d;
@@ -5509,7 +5524,15 @@ mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interface, mD
     reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
     info = IfindexToInterfaceInfoOSX(interface);
     isExpensive = (info && info->isExpensive) ? mDNStrue : mDNSfalse;
-    isCLAT46    = (info && info->isCLAT46)    ? mDNStrue : mDNSfalse;
+    if (mDNSStorage.p->NWIState && interface)
+    {
+        const uint32_t ifIndex = (uint32_t)((uintptr_t)interface);
+        isCLAT46 = NWIInterfaceHasCLAT46(mDNSStorage.p->NWIState, ifIndex);
+    }
+    else
+    {
+        isCLAT46 = mDNSfalse;
+    }
 
     for (n = 0; n < r->n_nameserver; n++)
     {
@@ -5553,7 +5576,7 @@ mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interface, mD
 // "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
 // a service identifier (q->ServiceID)
 //
-mDNSlocal void ConfigResolvers(dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc, mDNSu16 resGroupID)
+mDNSlocal void ConfigResolvers(dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc)
 {
     int i;
     dns_resolver_t **resolver;
@@ -5609,12 +5632,7 @@ mDNSlocal void ConfigResolvers(dns_config_t *config, mDNSu32 scope, mDNSBool set
         }
         else
         {
-            // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the
-            // scoped resolver are not used by other non-scoped or scoped resolvers.
-            if (scope != kScopeNone) 
-                resGroupID++;
-
-            ConfigDNSServers(r, interface, scope, resGroupID);
+            ConfigDNSServers(r, interface, scope, mDNS_GetNextResolverGroupID());
         }
     }
 }
@@ -5910,7 +5928,6 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setse
 {
     mDNS *const m = &mDNSStorage;
     MD5_CTX sdc;    // search domain context
-    static mDNSu16 resolverGroupID = 0;
 
     // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
     if (fqdn         ) fqdn->c[0]      = 0;
@@ -6011,20 +6028,9 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setse
             SetupActiveDirectoryDomain(config);
 #endif
 
-            // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry
-            // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need
-            // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between
-            // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the
-            // same resolverGroupID.
-            //
-            // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally.
-            ConfigResolvers(config, kScopeNone, setsearch, setservers, &sdc, ++resolverGroupID);
-            resolverGroupID += config->n_resolver;
-
-            ConfigResolvers(config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID);
-            resolverGroupID += config->n_scoped_resolver;
-
-            ConfigResolvers(config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID);
+            ConfigResolvers(config, kScopeNone, setsearch, setservers, &sdc);
+            ConfigResolvers(config, kScopeInterfaceID, setsearch, setservers, &sdc);
+            ConfigResolvers(config, kScopeServiceID, setsearch, setservers, &sdc);
 
             // Acking provides a hint to other processes that the current DNS configuration has completed
             // its update.  When configd receives the ack, it publishes a notification.
@@ -9532,6 +9538,36 @@ mDNSlocal void RegisterLocalOnlyAAAARecord(const domainname *const name, const m
 }
 #endif
 
+mDNSlocal void NWIEventHandler(void)
+{
+    mDNS * const m = &mDNSStorage;
+    nwi_state_t newState = nwi_state_copy();
+
+    KQueueLock();
+    const nwi_state_t oldState = m->p->NWIState;
+    m->p->NWIState = newState;
+    if (m->p->NWIState)
+    {
+        uint32_t lastIfIndex = 0;
+        mDNSBool lastCLAT46  = mDNSfalse;
+        for (DNSServer *server = m->DNSServers; server; server = server->next)
+        {
+            const uint32_t ifIndex = (uint32_t)((uintptr_t)server->interface);
+            if (ifIndex == 0) continue;
+            if (ifIndex == lastIfIndex)
+            {
+                server->isCLAT46 = lastCLAT46;
+                continue;
+            }
+            server->isCLAT46 = NWIInterfaceHasCLAT46(m->p->NWIState, ifIndex);
+            lastIfIndex      = ifIndex;
+            lastCLAT46       = server->isCLAT46;
+        }
+    }
+    KQueueUnlock("NWIEventHandler");
+    if (oldState) nwi_state_release(oldState);
+}
+
 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
 {
     mStatus err;
@@ -9672,6 +9708,18 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
     err = WatchForSysEvents(m);
     if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
 
+    m->p->NWIState = nwi_state_copy();
+    uint32_t status = notify_register_dispatch(nwi_state_get_notify_key(), &m->p->NWINotifyToken, dispatch_get_main_queue(),
+        ^(__unused int token) { NWIEventHandler(); });
+    if (status == NOTIFY_STATUS_OK)
+    {
+        m->p->NWINotifyRegistered = mDNStrue;
+    }
+    else
+    {
+        LogMsg("mDNSPlatformInit_setup: notify_register_dispatch failed %u", status);
+    }
+
     mDNSs32 utc = mDNSPlatformUTC();
     m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
     myGetIfAddrs(1);
@@ -9868,7 +9916,11 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
     }
 
     if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
-
+    if (m->p->NWINotifyRegistered)
+    {
+        notify_cancel(m->p->NWINotifyToken);
+        m->p->NWINotifyRegistered = mDNSfalse;
+    }
     terminateD2DPlugins();
 
     mDNSs32 utc = mDNSPlatformUTC();
@@ -9981,6 +10033,7 @@ mDNSexport void     mDNSPlatformQsort  (      void *base, int nel, int width, in
 }
 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
 mDNSexport void *   mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
+mDNSexport void *   mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL("mDNSPlatformMemAllocateClear", len)); }
 #endif
 mDNSexport void     mDNSPlatformMemFree    (void *mem)   { freeL("mDNSPlatformMemFree", mem); }
 
diff --git a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h
index 82de4331..23368183 100644
--- a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h
+++ b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h
@@ -28,7 +28,8 @@ extern "C" {
 #include <IOKit/pwr_mgt/IOPMLibPrivate.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
-#include "mDNSEmbeddedAPI.h"  // for domain name structure
+#include <network_information.h>    // for nwi_state
+#include "mDNSEmbeddedAPI.h"        // for domain name structure
 
 #include <net/if.h>
 #include <os/log.h>
@@ -154,7 +155,6 @@ struct NetworkInterfaceInfoOSX_struct
     u_int BPF_len;
     mDNSBool isExpensive;                       // True if this interface has the IFEF_EXPENSIVE flag set.
     mDNSBool isAWDL;                            // True if this interface has the IFEF_AWDL flag set.
-    mDNSBool isCLAT46;                          // True if this interface has the IFEF_CLAT46 flag set.
 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
     dispatch_source_t BPF_source;
 #else
@@ -185,6 +185,9 @@ struct mDNS_PlatformSupport_struct
     SCDynamicStoreRef Store;
     CFRunLoopSourceRef StoreRLS;
     CFRunLoopSourceRef PMRLS;
+    nwi_state_t NWIState;
+    int NWINotifyToken;
+    mDNSBool NWINotifyRegistered;
     int SysEventNotifier;
     KQueueEntry SysEventKQueue;
     IONotificationPortRef PowerPortRef;
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj b/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
index 8067d931..5df1073d 100644
--- a/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
@@ -347,6 +347,8 @@
 		BDB04224203FF18000419961 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BDB61845206ADB9D00AFF600 /* com.apple.mDNSResponder.plist in Copy Base Logging Profile */ = {isa = PBXBuildFile; fileRef = BDB61843206ADB7700AFF600 /* com.apple.mDNSResponder.plist */; };
 		BDBF9B941ED74B9C001498A8 /* DNS64State.h in Headers */ = {isa = PBXBuildFile; fileRef = BDBF9B931ED74B8C001498A8 /* DNS64State.h */; };
+		BDE5BCCA226D7181009C723C /* DNSCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = BDE5BCC9226D7181009C723C /* DNSCommon.h */; };
+		BDE5BCCC226D7198009C723C /* uDNS.h in Headers */ = {isa = PBXBuildFile; fileRef = BDE5BCCB226D7197009C723C /* uDNS.h */; };
 		BDF8BB902208E2A800419B62 /* mDNSResponder.plist in Copy BATS test plist */ = {isa = PBXBuildFile; fileRef = BDF8BB8F2208E26E00419B62 /* mDNSResponder.plist */; };
 		D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
 		D284BE580ADD80740027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
@@ -1018,6 +1020,8 @@
 		BDB61846206ADDDF00AFF600 /* com.apple.mDNSResponder.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.mDNSResponder.plist; sourceTree = "<group>"; };
 		BDBF9B931ED74B8C001498A8 /* DNS64State.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNS64State.h; sourceTree = "<group>"; };
 		BDE238C11DF69D8300B9F696 /* dns_sd_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_sd_internal.h; path = ../mDNSShared/dns_sd_internal.h; sourceTree = "<group>"; };
+		BDE5BCC9226D7181009C723C /* DNSCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DNSCommon.h; path = ../mDNSCore/DNSCommon.h; sourceTree = "<group>"; };
+		BDE5BCCB226D7197009C723C /* uDNS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uDNS.h; path = ../mDNSCore/uDNS.h; sourceTree = "<group>"; };
 		BDF8BB8F2208E26E00419B62 /* mDNSResponder.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = mDNSResponder.plist; sourceTree = "<group>"; };
 		D284BE730ADD80740027CCDF /* mDNSResponder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder; sourceTree = BUILT_PRODUCTS_DIR; };
 		D284BEB00ADD80920027CCDF /* dns-sd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "dns-sd"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1347,6 +1351,7 @@
 				84F4C08F188F04CF00D1E1DE /* dns_services.h */,
 				848DA5D516547F7200D2E8B4 /* dns_xpc.h */,
 				7F18A9F60587CEF6001880B3 /* DNSCommon.c */,
+				BDE5BCC9226D7181009C723C /* DNSCommon.h */,
 				7F461DB5062DBF2900672BF3 /* DNSDigest.c */,
 				FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */,
 				FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */,
@@ -1398,6 +1403,7 @@
 				FFCB6D73075D539900B8AF62 /* PlatformCommon.c */,
 				BD03E88C1AD31278005E8A81 /* SymptomReporter.c */,
 				7F18A9F70587CEF6001880B3 /* uDNS.c */,
+				BDE5BCCB226D7197009C723C /* uDNS.h */,
 				216D9ACD1720C9F5008066E1 /* uDNSPathEvalulation.c */,
 				F525E72804AA167501F1CF4D /* uds_daemon.c */,
 				4A2E69DD0F5475A3004A87B0 /* uds_daemon.h */,
@@ -1835,7 +1841,9 @@
 				2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
 				21A57F4E145B2AE100939099 /* CryptoAlg.h in Headers */,
 				21A57F55145B2B1400939099 /* CryptoSupport.h in Headers */,
+				BDE5BCCA226D7181009C723C /* DNSCommon.h in Headers */,
 				2124FA2C1471E98C0021D7BB /* nsec.h in Headers */,
+				BDE5BCCC226D7198009C723C /* uDNS.h in Headers */,
 				2124FA301471E9B50021D7BB /* dnssec.h in Headers */,
 				BD691B2B1ED2F4AB00E6F317 /* DNS64.h in Headers */,
 				218E8E53156D8C0300720DA0 /* dnsproxy.h in Headers */,
diff --git a/mDNSResponder/mDNSPosix/mDNSPosix.c b/mDNSResponder/mDNSPosix/mDNSPosix.c
index 5ed4a045..308252fb 100755
--- a/mDNSResponder/mDNSPosix/mDNSPosix.c
+++ b/mDNSResponder/mDNSPosix/mDNSPosix.c
@@ -1504,6 +1504,7 @@ mDNSexport void    mDNSPlatformMemZero(void *dst, mDNSu32 len)
 }
 
 mDNSexport void *  mDNSPlatformMemAllocate(mDNSu32 len) { return(malloc(len)); }
+mDNSexport void *  mDNSPlatformMemAllocateClear(mDNSu32 len) { return(calloc(1, len)); }
 mDNSexport void    mDNSPlatformMemFree    (void *mem)   { free(mem); }
 
 #if _PLATFORM_HAS_STRONG_PRNG_
diff --git a/mDNSResponder/mDNSShared/dns_sd.h b/mDNSResponder/mDNSShared/dns_sd.h
index 5989f17c..675eec51 100644
--- a/mDNSResponder/mDNSShared/dns_sd.h
+++ b/mDNSResponder/mDNSShared/dns_sd.h
@@ -66,7 +66,7 @@
  */
 
 #ifndef _DNS_SD_H
-#define _DNS_SD_H 8806001
+#define _DNS_SD_H 8807002
 
 #ifdef  __cplusplus
 extern "C" {
diff --git a/mDNSResponder/mDNSShared/dnsextd.c b/mDNSResponder/mDNSShared/dnsextd.c
index 96ee520c..cbdab57c 100644
--- a/mDNSResponder/mDNSShared/dnsextd.c
+++ b/mDNSResponder/mDNSShared/dnsextd.c
@@ -3100,7 +3100,7 @@ void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const e
                      const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID iid)
 { ( void ) m; ( void ) msg; ( void ) end; ( void ) srcaddr; ( void ) srcport; ( void ) dstaddr; ( void ) dstport; ( void ) iid; }
 DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const int serviceID, const mDNSAddr *addr, const mDNSIPPort port, 
-                             mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46, mDNSu16 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
+                             mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46, mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
 { ( void ) m; ( void ) d; ( void ) interface; ( void ) serviceID; ( void ) addr; ( void ) port; ( void ) scoped; ( void ) timeout; (void) cellIntf; (void) isExpensive; (void) isCLAT46;
  (void) resGroupID; (void) reqA; (void) reqAAAA; (void) reqDO; return(NULL); }
 void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID) { (void)domain; (void) InterfaceID;}
diff --git a/mDNSResponder/mDNSShared/uds_daemon.c b/mDNSResponder/mDNSShared/uds_daemon.c
index d1fbc7f2..4d110e7a 100644
--- a/mDNSResponder/mDNSShared/uds_daemon.c
+++ b/mDNSResponder/mDNSShared/uds_daemon.c
@@ -5765,7 +5765,7 @@ mDNSexport void udsserver_info()
                 const char *ifname;
                 mDNSInterfaceID InterfaceID = cr->resrec.InterfaceID;
                 mDNSu32 *const countPtr = InterfaceID ? &mcastRecordCount : &ucastRecordCount;
-                if (!InterfaceID && cr->resrec.rDNSServer && cr->resrec.rDNSServer->scoped)
+                if (!InterfaceID && cr->resrec.rDNSServer && (cr->resrec.rDNSServer->scopeType != kScopeNone))
                     InterfaceID = cr->resrec.rDNSServer->interface;
                 ifname = InterfaceNameForID(m, InterfaceID);
                 if (cr->CRActiveQuestion) CacheActive++;
diff --git a/mDNSResponder/unittests/uds_daemon_ut.c b/mDNSResponder/unittests/uds_daemon_ut.c
index 8a07e9ba..971a1419 100644
--- a/mDNSResponder/unittests/uds_daemon_ut.c
+++ b/mDNSResponder/unittests/uds_daemon_ut.c
@@ -23,7 +23,7 @@ mDNSexport void LogCacheRecords_ut(mDNSs32 now, mDNSu32* retCacheUsed, mDNSu32*
 				const mDNSs32 remain = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond;
 				const char *ifname;
 				mDNSInterfaceID InterfaceID = cr->resrec.InterfaceID;
-				if (!InterfaceID && cr->resrec.rDNSServer && cr->resrec.rDNSServer->scoped)
+				if (!InterfaceID && cr->resrec.rDNSServer && (cr->resrec.rDNSServer->scopeType != kScopeNone))
 					InterfaceID = cr->resrec.rDNSServer->interface;
 				ifname = InterfaceNameForID(&mDNSStorage, InterfaceID);
 				if (cr->CRActiveQuestion) CacheActive++;
-- 
2.26.2



More information about the devel mailing list