diff options
Diffstat (limited to 'mDNSResponder/mDNSCore/mDNS.c')
-rwxr-xr-x | mDNSResponder/mDNSCore/mDNS.c | 801 |
1 files changed, 407 insertions, 394 deletions
diff --git a/mDNSResponder/mDNSCore/mDNS.c b/mDNSResponder/mDNSCore/mDNS.c index a58a6c1a..0d4d8ae4 100755 --- a/mDNSResponder/mDNSCore/mDNS.c +++ b/mDNSResponder/mDNSCore/mDNS.c @@ -45,6 +45,7 @@ #endif #include "dns_sd.h" // for kDNSServiceFlags* definitions +#include "dns_sd_internal.h" #if APPLE_OSX_mDNSResponder #include <WebFilterDNS/WebFilterDNS.h> @@ -65,15 +66,22 @@ void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import)); #define NO_WCF 1 #endif // APPLE_OSX_mDNSResponder -#if TARGET_OS_EMBEDDED +#if AWD_METRICS #include "Metrics.h" #endif +#if USE_DNS64 +#include "DNS64.h" +#endif + +#ifdef UNIT_TEST +#include "unittest.h" +#endif + // Forward declarations mDNSlocal void BeginSleepProcessing(mDNS *const m); mDNSlocal void RetrySPSRegistrations(mDNS *const m); mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password, mDNSBool unicastOnly); -mDNSlocal mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q); mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q); mDNSlocal void mDNS_PurgeForQuestion(mDNS *const m, DNSQuestion *q); mDNSlocal void CheckForDNSSECRecords(mDNS *const m, DNSQuestion *q); @@ -109,6 +117,10 @@ mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *et #define NR_AnswerMulticast (mDNSu8*)~0 #define NR_AnswerUnicast (mDNSu8*)~1 +// Question default timeout values +#define DEFAULT_MCAST_TIMEOUT 5 +#define DEFAULT_LO_OR_P2P_TIMEOUT 5 + // The code (see SendQueries() and BuildQuestion()) needs to have the // RequestUnicast value set to a value one greater than the number of times you want the query // sent with the "request unicast response" (QU) bit set. @@ -274,24 +286,27 @@ mDNSlocal AuthEntity *GetAuthEntity(AuthHash *r, const AuthGroup *const Preserve return(e); } -mDNSexport AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name) +mDNSexport AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 namehash, const domainname *const name) { AuthGroup *ag; + const mDNSu32 slot = namehash % AUTH_HASH_SLOTS; + for (ag = r->rrauth_hash[slot]; ag; ag=ag->next) if (ag->namehash == namehash && SameDomainName(ag->name, name)) break; return(ag); } -mDNSexport AuthGroup *AuthGroupForRecord(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr) +mDNSexport AuthGroup *AuthGroupForRecord(AuthHash *r, const ResourceRecord *const rr) { - return(AuthGroupForName(r, slot, rr->namehash, rr->name)); + return(AuthGroupForName(r, rr->namehash, rr->name)); } -mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr) +mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const ResourceRecord *const rr) { mDNSu16 namelen = DomainNameLength(rr->name); AuthGroup *ag = (AuthGroup*)GetAuthEntity(r, mDNSNULL); + const mDNSu32 slot = rr->namehash % AUTH_HASH_SLOTS; if (!ag) { LogMsg("GetAuthGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); } ag->next = r->rrauth_hash[slot]; ag->namehash = rr->namehash; @@ -310,9 +325,9 @@ mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const mDNSu32 slot, const Resourc } AssignDomainName(ag->name, rr->name); - if (AuthGroupForRecord(r, slot, rr)) LogMsg("GetAuthGroup: Already have AuthGroup for %##s", rr->name->c); + if (AuthGroupForRecord(r, rr)) LogMsg("GetAuthGroup: Already have AuthGroup for %##s", rr->name->c); r->rrauth_hash[slot] = ag; - if (AuthGroupForRecord(r, slot, rr) != ag) LogMsg("GetAuthGroup: Not finding AuthGroup for %##s", rr->name->c); + if (AuthGroupForRecord(r, rr) != ag) LogMsg("GetAuthGroup: Not finding AuthGroup for %##s", rr->name->c); return(ag); } @@ -320,11 +335,11 @@ mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const mDNSu32 slot, const Resourc // Returns the AuthGroup in which the AuthRecord was inserted mDNSexport AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr) { - (void)m; AuthGroup *ag; - const mDNSu32 slot = AuthHashSlot(rr->resrec.name); - ag = AuthGroupForRecord(r, slot, &rr->resrec); - if (!ag) ag = GetAuthGroup(r, slot, &rr->resrec); // If we don't have a AuthGroup for this name, make one now + + (void)m; + ag = AuthGroupForRecord(r, &rr->resrec); + if (!ag) ag = GetAuthGroup(r, &rr->resrec); // If we don't have a AuthGroup for this name, make one now if (ag) { *(ag->rrauth_tail) = rr; // Append this record to tail of cache slot list @@ -337,9 +352,8 @@ mDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *r { AuthGroup *a; AuthRecord **rp; - const mDNSu32 slot = AuthHashSlot(rr->resrec.name); - a = AuthGroupForRecord(r, slot, &rr->resrec); + a = AuthGroupForRecord(r, &rr->resrec); if (!a) { LogMsg("RemoveAuthRecord: ERROR!! AuthGroup not found for %s", ARDisplayString(m, rr)); return mDNSNULL; } rp = &a->members; while (*rp) @@ -359,18 +373,19 @@ mDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *r return a; } -mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name) +mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 namehash, const domainname *const name) { CacheGroup *cg; + mDNSu32 slot = HashSlotFromNameHash(namehash); for (cg = m->rrcache_hash[slot]; cg; cg=cg->next) if (cg->namehash == namehash && SameDomainName(cg->name, name)) break; return(cg); } -mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr) +mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const ResourceRecord *const rr) { - return(CacheGroupForName(m, slot, rr->namehash, rr->name)); + return(CacheGroupForName(m, rr->namehash, rr->name)); } mDNSexport mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr) @@ -472,7 +487,7 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re const mDNSu32 c = q->CNAMEReferrals + 1; // Stash a copy of the new q->CNAMEReferrals value UDPSocket *sock = q->LocalSocket; mDNSOpaque16 id = q->TargetQID; -#if TARGET_OS_EMBEDDED +#if AWD_METRICS uDNSMetrics metrics; #endif @@ -496,7 +511,7 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re LogInfo("AnswerQuestionByFollowingCNAME: %p %##s (%s) following CNAME referral %d for %s", q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, RRDisplayString(m, rr)); -#if TARGET_OS_EMBEDDED +#if AWD_METRICS if ((q->CNAMEReferrals == 0) && !q->metrics.originalQName) { domainname * qName; @@ -532,7 +547,7 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re // Record how many times we've done this. We need to do this *after* mDNS_StartQuery_internal, // because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero q->CNAMEReferrals = c; -#if TARGET_OS_EMBEDDED +#if AWD_METRICS q->metrics = metrics; #endif if (sock) @@ -787,7 +802,6 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec (X) &kDNSRecordTypeActiveUniqueMask ? DefaultAnnounceIntervalForTypeUnique : 0) #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0) -#define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR)) #define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond) #define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR)) @@ -962,9 +976,9 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) } rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval; } - // Skip kDNSRecordTypeKnownUnique records here and set their LastAPTime in the "else" block below so that they get announced immediately, - // otherwise, their announcement would be delayed until all other record probes complete. - else if ((rr->resrec.RecordType != kDNSRecordTypeKnownUnique) && m->SuppressProbes && m->SuppressProbes - m->timenow >= 0) + // Skip kDNSRecordTypeKnownUnique and kDNSRecordTypeShared records here and set their LastAPTime in the "else" block below so + // that they get announced immediately, otherwise, their announcement would be delayed until the based on the SuppressProbes value. + else if ((rr->resrec.RecordType != kDNSRecordTypeKnownUnique) && (rr->resrec.RecordType != kDNSRecordTypeShared) && m->SuppressProbes && (m->SuppressProbes - m->timenow >= 0)) rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval + DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2; else rr->LastAPTime = m->timenow - rr->ThisAPInterval; @@ -1155,9 +1169,8 @@ mDNSlocal AuthRecord *CheckAuthIdenticalRecord(AuthHash *r, AuthRecord *rr) { const AuthGroup *a; AuthRecord *rp; - const mDNSu32 slot = AuthHashSlot(rr->resrec.name); - a = AuthGroupForRecord(r, slot, &rr->resrec); + a = AuthGroupForRecord(r, &rr->resrec); if (!a) return mDNSNULL; rp = a->members; while (rp) @@ -1181,9 +1194,8 @@ mDNSlocal mDNSBool CheckAuthRecordConflict(AuthHash *r, AuthRecord *rr) { const AuthGroup *a; const AuthRecord *rp; - const mDNSu32 slot = AuthHashSlot(rr->resrec.name); - a = AuthGroupForRecord(r, slot, &rr->resrec); + a = AuthGroupForRecord(r, &rr->resrec); if (!a) return mDNSfalse; rp = a->members; while (rp) @@ -1203,9 +1215,8 @@ mDNSlocal AuthRecord *CheckAuthSameRecord(AuthHash *r, AuthRecord *rr) { const AuthGroup *a; AuthRecord *rp; - const mDNSu32 slot = AuthHashSlot(rr->resrec.name); - a = AuthGroupForRecord(r, slot, &rr->resrec); + a = AuthGroupForRecord(r, &rr->resrec); if (!a) return mDNSNULL; rp = a->members; while (rp) @@ -1386,9 +1397,9 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) { if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified; - else + else if (rr->resrec.RecordType != kDNSRecordTypeKnownUnique) { - LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique", + LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique or kDNSRecordTypeKnownUnique", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return(mStatus_Invalid); } @@ -1630,7 +1641,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) getKeepaliveRaddr(m, rr, &raddr); // This is an asynchronous call. Once the remote MAC address is available, helper will schedule an // asynchronous task to update the resource record - mDNSPlatformGetRemoteMacAddr(m, &raddr); + mDNSPlatformGetRemoteMacAddr(&raddr); } return(mStatus_NoError); @@ -1679,9 +1690,8 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, { AuthGroup *a; AuthRecord **rp; - const mDNSu32 slot = AuthHashSlot(rr->resrec.name); - a = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec); + a = AuthGroupForRecord(&m->rrauth, &rr->resrec); if (!a) return mDNSfalse; rp = &a->members; while (*rp && *rp != rr) rp=&(*rp)->next; @@ -1954,6 +1964,27 @@ mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthR debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); } +mDNSlocal void AddRRSetAdditionalsToResponseList(mDNS *const m, AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *additional, const mDNSInterfaceID InterfaceID) +{ + AuthRecord *rr2; + if (additional->resrec.RecordType & kDNSRecordTypeUniqueMask) + { + for (rr2 = m->ResourceRecords; rr2; rr2 = rr2->next) + { + if ((rr2->resrec.namehash == additional->resrec.namehash) && + (rr2->resrec.rrtype == additional->resrec.rrtype) && + (rr2 != additional) && + (rr2->resrec.RecordType & kDNSRecordTypeUniqueMask) && + (rr2->resrec.rrclass == additional->resrec.rrclass) && + ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && + SameDomainName(rr2->resrec.name, additional->resrec.name)) + { + AddRecordToResponseList(nrpp, rr2, rr); + } + } + } +} + mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID) { AuthRecord *rr, *rr2; @@ -1962,10 +1993,16 @@ mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseR // (Note: This is an "if", not a "while". If we add a record, we'll find it again // later in the "for" loop, and we will follow further "additional" links then.) if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID)) + { AddRecordToResponseList(nrpp, rr->Additional1, rr); + AddRRSetAdditionalsToResponseList(m, nrpp, rr, rr->Additional1, InterfaceID); + } if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID)) + { AddRecordToResponseList(nrpp, rr->Additional2, rr); + AddRRSetAdditionalsToResponseList(m, nrpp, rr, rr->Additional2, InterfaceID); + } // For SRV records, automatically add the Address record(s) for the target host if (rr->resrec.rrtype == kDNSType_SRV) @@ -2485,7 +2522,7 @@ mDNSlocal void SendResponses(mDNS *const m) mDNSs32 maxExistingAnnounceInterval = 0; const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces); - m->NextScheduledResponse = m->timenow + 0x78000000; + m->NextScheduledResponse = m->timenow + FutureTime; if (m->SleepState == SleepState_Transferring) RetrySPSRegistrations(m); @@ -3059,13 +3096,18 @@ mDNSexport void SetNextCacheCheckTimeForRecord(mDNS *const m, CacheRecord *const verbosedebugf("SetNextCacheCheckTimeForRecord: NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks for %s", (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m,rr)); } - ScheduleNextCacheCheckTime(m, HashSlot(rr->resrec.name), NextCacheCheckEvent(rr)); + ScheduleNextCacheCheckTime(m, HashSlotFromNameHash(rr->resrec.namehash), NextCacheCheckEvent(rr)); } #define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5) #define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5) #define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 5) -#define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 5) + +// Delay before restarting questions on a flapping interface. +#define kDefaultQueryDelayTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 3) +// After kDefaultQueryDelayTimeForFlappingInterface seconds, allow enough time for up to three queries (0, 1, and 4 seconds) +// plus three seconds for "response delay" before removing the reconfirmed records from the cache. +#define kDefaultReconfirmTimeForFlappingInterface (kDefaultQueryDelayTimeForFlappingInterface + ((mDNSu32)mDNSPlatformOneSecond * 7)) mDNSexport mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval) { @@ -3080,7 +3122,7 @@ mDNSexport mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, // Add a 33% random amount to the interval, to avoid synchronization between multiple hosts // For all the reconfirmations in a given batch, we want to use the same random value // so that the reconfirmation questions can be grouped into a single query packet - if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(0x3FFFFFFF); + if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(FutureTime); interval += m->RandomReconfirmDelay % ((interval/3) + 1); rr->TimeRcvd = m->timenow - (mDNSs32)interval * 3; rr->resrec.rroriginalttl = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond; @@ -3110,8 +3152,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, const NetworkInterfaceInfo *intf else { mDNSu32 forecast = *answerforecast + anoninfo_space; - const mDNSu32 slot = HashSlot(&q->qname); - const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); + const CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname); CacheRecord *rr; CacheRecord **ka = *kalistptrptr; // Make a working copy of the pointer we're going to update @@ -3204,7 +3245,7 @@ mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name, // to get a AAAA response is not grounds to doubt the PTR/SRV chain that lead us to that name. mDNSlocal const CacheRecord *CacheHasAddressTypeForName(mDNS *const m, const domainname *const name, const mDNSu32 namehash) { - CacheGroup *const cg = CacheGroupForName(m, HashSlot(name), namehash, name); + CacheGroup *const cg = CacheGroupForName(m, namehash, name); const CacheRecord *cr = cg ? cg->members : mDNSNULL; while (cr && !RRTypeIsAddressType(cr->resrec.rrtype)) cr=cr->next; return(cr); @@ -3214,7 +3255,7 @@ mDNSlocal const CacheRecord *CacheHasAddressTypeForName(mDNS *const m, const dom mDNSlocal const CacheRecord *FindSPSInCache1(mDNS *const m, const DNSQuestion *const q, const CacheRecord *const c0, const CacheRecord *const c1) { #ifndef SPC_DISABLED - CacheGroup *const cg = CacheGroupForName(m, HashSlot(&q->qname), q->qnamehash, &q->qname); + CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname); const CacheRecord *cr, *bestcr = mDNSNULL; mDNSu32 bestmetric = 1000000; for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) @@ -3365,7 +3406,7 @@ mDNSlocal void mDNSSendWakeOnResolve(mDNS *const m, DNSQuestion *q) mDNSPlatformMemCopy(IPAddr, &d->c[i + 1], len - i); IPAddr[len - i] = 0; m->mDNSStats.WakeOnResolves++; - mDNSPlatformSendWakeupPacket(m, InterfaceID, EthAddr, IPAddr, InitialWakeOnResolveCount - q->WakeOnResolveCount); + mDNSPlatformSendWakeupPacket(InterfaceID, EthAddr, IPAddr, InitialWakeOnResolveCount - q->WakeOnResolveCount); return; } else if (d->c[i] == ':') @@ -3386,8 +3427,7 @@ mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q) { // We forecast: qname (n) type (2) class (2) mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4; - const mDNSu32 slot = HashSlot(&q->qname); - const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); + const CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname); const CacheRecord *rr; for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache, if (rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet @@ -3490,7 +3530,7 @@ mDNSlocal void SendQueries(mDNS *const m) const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data); // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time - if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort); + if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(zeroIPPort); if (q->LocalSocket) { InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags); @@ -3531,7 +3571,7 @@ mDNSlocal void SendQueries(mDNS *const m) // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list, // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very // next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value. - m->NextScheduledQuery = m->timenow + 0x78000000; + m->NextScheduledQuery = m->timenow + FutureTime; for (q = m->Questions; q && q != m->NewQuestions; q=q->next) { if (mDNSOpaque16IsZero(q->TargetQID) @@ -3610,7 +3650,7 @@ mDNSlocal void SendQueries(mDNS *const m) // 2. Scan our authoritative RR list to see what probes we might need to send - m->NextScheduledProbe = m->timenow + 0x78000000; + m->NextScheduledProbe = m->timenow + FutureTime; if (m->CurrentRecord) LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); @@ -4110,7 +4150,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco return; } -#if TARGET_OS_EMBEDDED +#if AWD_METRICS if ((AddRecord == QC_add) && Question_uDNS(q) && !followcname) { const domainname * queryName; @@ -4169,6 +4209,11 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us +#if USE_DNS64 + // If DNS64StateMachine() returns true, then the question was restarted as a different question, so return. + if (!mDNSOpaque16IsZero(q->TargetQID) && DNS64StateMachine(m, q, &rr->resrec, AddRecord)) return; +#endif + #ifdef USE_LIBIDN if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) // If negative answer, check if we need to try Punycode conversion { @@ -4209,7 +4254,18 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco q->QuestionCallback(m, q, &neg.resrec, AddRecord); } else - q->QuestionCallback(m, q, &rr->resrec, AddRecord); + { +#if USE_DNS64 + if (DNS64ShouldAnswerQuestion(q, &rr->resrec)) + { + DNS64AnswerQuestion(m, q, &rr->resrec, AddRecord); + } + else +#endif + { + q->QuestionCallback(m, q, &rr->resrec, AddRecord); + } + } mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again } // If this is an "Add" operation and this question needs validation, validate the response. @@ -4265,12 +4321,12 @@ mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr) m->CurrentQuestion = mDNSNULL; } -mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu32 slot, mDNSBool *purge) +mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, mDNSBool *purge) { const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond; // See if there are any records expiring within one second const mDNSs32 start = m->timenow - 0x10000000; mDNSs32 delay = start; - CacheGroup *cg = CacheGroupForName(m, slot, namehash, name); + CacheGroup *cg = CacheGroupForName(m, namehash, name); const CacheRecord *rr; if (purge) @@ -4559,13 +4615,12 @@ mDNSlocal void ReleaseAdditionalCacheRecords(mDNS *const m, CacheRecord **rp) mDNSexport void ReleaseCacheRecord(mDNS *const m, CacheRecord *r) { CacheGroup *cg; - const mDNSu32 slot = HashSlot(r->resrec.name); //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r)); if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->smallrdatastorage) mDNSPlatformMemFree(r->resrec.rdata); r->resrec.rdata = mDNSNULL; - cg = CacheGroupForRecord(m, slot, &r->resrec); + cg = CacheGroupForRecord(m, &r->resrec); if (!cg) { @@ -4662,7 +4717,7 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGrou m->NextScheduledQuery = m->timenow; // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTimeForRecord(), // which will correctly update m->NextCacheCheck for us. - event = m->timenow + 0x3FFFFFFF; + event = m->timenow + FutureTime; } } } @@ -4687,15 +4742,13 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGrou // returns true to indicate the same. mDNSlocal mDNSBool AnswerQuestionWithLORecord(mDNS *const m, DNSQuestion *q, mDNSBool checkOnly) { - mDNSu32 slot; AuthRecord *lr; AuthGroup *ag; if (m->CurrentRecord) LogMsg("AnswerQuestionWithLORecord ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); - slot = AuthHashSlot(&q->qname); - ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); + ag = AuthGroupForName(&m->rrauth, q->qnamehash, &q->qname); if (ag) { m->CurrentRecord = ag->members; @@ -4772,8 +4825,19 @@ mDNSlocal mDNSBool AnswerQuestionWithLORecord(mDNS *const m, DNSQuestion *q, mDN // reasons for suppressing the query, this function should be updated. mDNSlocal void AnswerSuppressedQuestion(mDNS *const m, DNSQuestion *q) { - mDNSBool SuppressQuery = q->SuppressQuery; - mDNSBool DisallowPID = q->DisallowPID; + mDNSBool SuppressQuery; + mDNSBool DisallowPID; + + // If the client did not set the kDNSServiceFlagsReturnIntermediates flag, then don't generate a negative response, just + // deactivate the DNSQuestion. + if (!q->ReturnIntermed) + { + q->ThisQInterval = 0; + return; + } + + SuppressQuery = q->SuppressQuery; + DisallowPID = q->DisallowPID; // make sure that QuerySuppressed() returns false q->SuppressQuery = mDNSfalse; @@ -4789,13 +4853,15 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) { mDNSBool ShouldQueryImmediately = mDNStrue; DNSQuestion *const q = m->NewQuestions; // Grab the question we're going to answer - mDNSu32 slot = HashSlot(&q->qname); - CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); +#if USE_DNS64 + if (!mDNSOpaque16IsZero(q->TargetQID)) DNS64HandleNewQuestion(m, q); +#endif + CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname); mDNSBool AnsweredFromCache = mDNSfalse; verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); - if (cg) CheckCacheExpiration(m, slot, cg); + if (cg) CheckCacheExpiration(m, HashSlotFromNameHash(q->qnamehash), cg); if (m->NewQuestions != q) { LogInfo("AnswerNewQuestion: Question deleted while doing CheckCacheExpiration"); goto exit; } m->NewQuestions = q->next; // Advance NewQuestions to the next *after* calling CheckCacheExpiration, because if we advance it first @@ -4935,11 +5001,10 @@ exit: // appropriate answers, stopping if it reaches a NewLocalOnlyRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) { - mDNSu32 slot; AuthGroup *ag; DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer - m->NewLocalOnlyQuestions = q->next; // Advance NewLocalOnlyQuestions to the next (if any) mDNSBool retEv = mDNSfalse; + m->NewLocalOnlyQuestions = q->next; // Advance NewLocalOnlyQuestions to the next (if any) debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); @@ -4954,8 +5019,7 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) // 1. First walk the LocalOnly records answering the LocalOnly question // 2. As LocalOnly questions should also be answered by any other Auth records local to the machine, // walk the ResourceRecords list delivering the answers - slot = AuthHashSlot(&q->qname); - ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); + ag = AuthGroupForName(&m->rrauth, q->qnamehash, &q->qname); if (ag) { m->CurrentRecord = ag->members; @@ -5120,9 +5184,9 @@ mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const Res } AssignDomainName(cg->name, rr->name); - if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c); + if (CacheGroupForRecord(m, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c); m->rrcache_hash[slot] = cg; - if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c); + if (CacheGroupForRecord(m, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c); return(cg); } @@ -5162,7 +5226,7 @@ mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m) // had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute(). // (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set) #define SetSPSProxyListChanged(X) do { \ - if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \ + if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m->SPSProxyListChanged); \ m->SPSProxyListChanged = (X); } while(0) // Called from mDNS_Execute() to expire stale proxy records @@ -5221,13 +5285,12 @@ mDNSlocal void CheckRmvEventsForLocalRecords(mDNS *const m) } } -mDNSlocal void TimeoutQuestions(mDNS *const m) +mDNSlocal void TimeoutQuestions_internal(mDNS *const m, DNSQuestion* questions, mDNSInterfaceID InterfaceID) { - m->NextScheduledStopTime = m->timenow + 0x3FFFFFFF; if (m->CurrentQuestion) LogMsg("TimeoutQuestions ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); - m->CurrentQuestion = m->Questions; + m->CurrentQuestion = questions; while (m->CurrentQuestion) { DNSQuestion *const q = m->CurrentQuestion; @@ -5239,7 +5302,8 @@ mDNSlocal void TimeoutQuestions(mDNS *const m) if (m->timenow - q->StopTime >= 0) { LogInfo("TimeoutQuestions: question %p %##s timed out, time %d", q, q->qname.c, m->timenow - q->StopTime); - GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse); + q->LOAddressAnswers = 0; // unset since timing out the question + GenerateNegativeResponse(m, InterfaceID, QC_forceresponse); if (m->CurrentQuestion == q) q->StopTime = 0; } else @@ -5257,6 +5321,13 @@ mDNSlocal void TimeoutQuestions(mDNS *const m) m->CurrentQuestion = mDNSNULL; } +mDNSlocal void TimeoutQuestions(mDNS *const m) +{ + m->NextScheduledStopTime = m->timenow + FutureTime; // push reschedule of TimeoutQuestions to way off into the future + TimeoutQuestions_internal(m, m->Questions, mDNSInterface_Any); + TimeoutQuestions_internal(m, m->LocalOnlyQuestions, mDNSInterface_LocalOnly); +} + mDNSlocal void mDNSCoreFreeProxyRR(mDNS *const m) { AuthRecord *rrPtr = m->SPSRRSet, *rrNext = mDNSNULL; @@ -5274,10 +5345,6 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) { mDNS_Lock(m); // Must grab lock before trying to read m->timenow -#if APPLE_OSX_mDNSResponder - mDNSLogStatistics(m); -#endif // APPLE_OSX_mDNSResponder - if (m->timenow - m->NextScheduledEvent >= 0) { int i; @@ -5304,13 +5371,13 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0) { mDNSu32 numchecked = 0; - m->NextCacheCheck = m->timenow + 0x3FFFFFFF; + m->NextCacheCheck = m->timenow + FutureTime; for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) { if (m->timenow - m->rrcache_nextcheck[slot] >= 0) { CacheGroup **cp = &m->rrcache_hash[slot]; - m->rrcache_nextcheck[slot] = m->timenow + 0x3FFFFFFF; + m->rrcache_nextcheck[slot] = m->timenow + FutureTime; while (*cp) { debugf("m->NextCacheCheck %4d Slot %3d %##s", numchecked, slot, *cp ? (*cp)->name : (domainname*)"\x04NULL"); @@ -5330,7 +5397,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) if (m->timenow - m->NextScheduledSPS >= 0) { - m->NextScheduledSPS = m->timenow + 0x3FFFFFFF; + m->NextScheduledSPS = m->timenow + FutureTime; CheckProxyRecords(m, m->DuplicateRecords); // Clear m->DuplicateRecords first, then m->ResourceRecords CheckProxyRecords(m, m->ResourceRecords); } @@ -5341,7 +5408,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) // as records could have expired during that check if (m->timenow - m->NextScheduledKA >= 0) { - m->NextScheduledKA = m->timenow + 0x3FFFFFFF; + m->NextScheduledKA = m->timenow + FutureTime; mDNS_SendKeepalives(m); } @@ -5525,16 +5592,17 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) m->RandomQueryDelay = 0; m->RandomReconfirmDelay = 0; + // See if any questions (or local-only questions) have timed out if (m->NextScheduledStopTime && m->timenow - m->NextScheduledStopTime >= 0) TimeoutQuestions(m); #ifndef UNICAST_DISABLED if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0) UpdateAllSRVRecords(m); if (m->timenow - m->NextScheduledNATOp >= 0) CheckNATMappings(m); if (m->timenow - m->NextuDNSEvent >= 0) uDNS_Tasks(m); #endif -#if APPLE_OSX_mDNSResponder +#if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR extern void serviceBLE(); if (m->NextBLEServiceTime && (m->timenow - m->NextBLEServiceTime >= 0)) serviceBLE(); -#endif // APPLE_OSX_mDNSResponder +#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR } // Note about multi-threaded systems: @@ -5574,11 +5642,9 @@ mDNSlocal void SuspendLLQs(mDNS *m) mDNSlocal mDNSBool QuestionHasLocalAnswers(mDNS *const m, DNSQuestion *q) { AuthRecord *rr; - mDNSu32 slot; AuthGroup *ag; - slot = AuthHashSlot(&q->qname); - ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); + ag = AuthGroupForName(&m->rrauth, q->qnamehash, &q->qname); if (ag) { for (rr = ag->members; rr; rr=rr->next) @@ -5614,7 +5680,7 @@ mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, !SameDomainLabel(question->qname.c, (const mDNSu8 *)"\x0c_autotunnel6")&& question->QuestionCallback != AutoTunnelCallback) { question->NoAnswer = NoAnswer_Suspended; - AddNewClientTunnel(m, question); + AddNewClientTunnel(question); return; } #endif // APPLE_OSX_mDNSResponder @@ -5890,7 +5956,7 @@ mDNSexport void mDNS_UpdateAllowSleep(mDNS *const m) } // Call the platform code to enable/disable sleep - mDNSPlatformSetAllowSleep(m, allowSleep, reason); + mDNSPlatformSetAllowSleep(allowSleep, reason); #else (void) m; #endif /* !defined(IDLESLEEPCONTROL_DISABLED) */ @@ -6001,7 +6067,7 @@ mDNSexport mStatus UpdateKeepaliveRData(mDNS *const m, AuthRecord *rr, NetworkIn // now, then we don't update the DNS NULL record. But we do not prevent it from registering with the SPS. When SPS sees // this DNS NULL record, it does not send any keepalives as it does not have all the information mDNSPlatformMemZero(&mti, sizeof (mDNSTCPInfo)); - ret = mDNSPlatformRetrieveTCPInfo(m, &laddr, &lport, &raddr, &rport, &mti); + ret = mDNSPlatformRetrieveTCPInfo(&laddr, &lport, &raddr, &rport, &mti); if (ret != mStatus_NoError) { LogMsg("mDNSPlatformRetrieveTCPInfo: mDNSPlatformRetrieveTCPInfo failed %d", ret); @@ -6568,15 +6634,14 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m) m->NextScheduledSPRetry = m->timenow; + // Clear out the SCDynamic entry that stores the external SPS information + mDNSPlatformClearSPSData(); + if (!m->SystemWakeOnLANEnabled) LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false"); else if (!mDNSCoreHaveAdvertisedMulticastServices(m)) LogSPS("BeginSleepProcessing: No advertised services"); else // If we have at least one advertised service { NetworkInterfaceInfo *intf; - - // Clear out the SCDynamic entry that stores the external SPS information - mDNSPlatformClearSPSData(); - for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) { // Intialize it to false. These values make sense only when SleepState is set to Sleeping. @@ -6616,7 +6681,7 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m) else if (SupportsInNICProxy(intf)) { mDNSBool keepaliveOnly = mDNSfalse; - if (ActivateLocalProxy(m, intf, &keepaliveOnly) == mStatus_NoError) + if (ActivateLocalProxy(intf, &keepaliveOnly) == mStatus_NoError) { SendGoodbyesForWakeOnlyService(m, &WakeOnlyService); @@ -6833,11 +6898,6 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep) // 2. Re-validate our cache records currtime = mDNSPlatformUTC(); -#if APPLE_OSX_mDNSResponder - // start time of this statistics gathering interval - m->StatStartTime = currtime; -#endif // APPLE_OSX_mDNSResponder - diff = currtime - m->TimeSlept; FORALL_CACHERECORDS(slot, cg, cr) { @@ -6984,7 +7044,7 @@ mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now) if (rr->state == regState_Refresh && rr->tcp) { LogSPS("mDNSCoreReadyForSleep: waiting for Record updateIntID 0x%x 0x%x (updateid %d) %s", rr->updateIntID.l[1], rr->updateIntID.l[0], mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; } #if APPLE_OSX_mDNSResponder - if (!RecordReadyForSleep(m, rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; } + if (!RecordReadyForSleep(rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; } #endif } @@ -7315,8 +7375,7 @@ exit: mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const ResourceRecord *const pktrr) { - mDNSu32 slot = HashSlot(pktrr->name); - CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr); + CacheGroup *cg = CacheGroupForRecord(m, pktrr); CacheRecord *rr; mDNSBool match; for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) @@ -7563,7 +7622,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con // We only mark this question for sending if it is at least one second since the last time we multicast it // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it. // This is to guard against the case where someone blasts us with queries as fast as they can. - if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 || + if ((mDNSu32)(m->timenow - rr->LastMCTime) >= (mDNSu32)mDNSPlatformOneSecond || (rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID)) rr->NR_AnswerTo = NR_AnswerMulticast; } @@ -7592,44 +7651,25 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con if (query->h.flags.b[0] & kDNSFlag0_TC) m->mDNSStats.KnownAnswerMultiplePkts++; -#if ENABLE_MULTI_PACKET_QUERY_SNOOPING - if (QuestionNeedsMulticastResponse) -#else // We only do the following accelerated cache expiration and duplicate question suppression processing // for non-truncated multicast queries with multicast responses. // For any query generating a unicast response we don't do this because we can't assume we will see the response. // For truncated queries we don't do this because a response we're expecting might be suppressed by a subsequent // known-answer packet, and when there's packet loss we can't safely assume we'll receive *all* known-answer packets. if (QuestionNeedsMulticastResponse && !(query->h.flags.b[0] & kDNSFlag0_TC)) -#endif { #if POOF_ENABLED - const mDNSu32 slot = HashSlot(&pktq.qname); - CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname); + CacheGroup *cg = CacheGroupForName(m, pktq.qnamehash, &pktq.qname); CacheRecord *cr; // Make a list indicating which of our own cache records we expect to see updated as a result of this query // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated -#if ENABLE_MULTI_PACKET_QUERY_SNOOPING - if (!(query->h.flags.b[0] & kDNSFlag0_TC)) -#endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit) if (!cr->NextInKAList && eap != &cr->NextInKAList) { *eap = cr; eap = &cr->NextInKAList; -#if ENABLE_MULTI_PACKET_QUERY_SNOOPING - if (cr->MPUnansweredQ == 0 || m->timenow - cr->MPLastUnansweredQT >= mDNSPlatformOneSecond) - { - // Although MPUnansweredQ is only really used for multi-packet query processing, - // we increment it for both single-packet and multi-packet queries, so that it stays in sync - // with the MPUnansweredKA value, which by necessity is incremented for both query types. - cr->MPUnansweredQ++; - cr->MPLastUnansweredQT = m->timenow; - cr->MPExpectingKA = mDNStrue; - } -#endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING } #endif // POOF_ENABLED @@ -7637,9 +7677,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con // We only do this for non-truncated queries. Right now it would be too complicated to try // to keep track of duplicate suppression state between multiple packets, especially when we // can't guarantee to receive all of the Known Answer packets that go with a particular query. -#if ENABLE_MULTI_PACKET_QUERY_SNOOPING - if (!(query->h.flags.b[0] & kDNSFlag0_TC)) -#endif // For anonymous question, the duplicate suppressesion should happen if the // question belongs in the same group. As the group is expected to be // small, we don't do the optimization for now. @@ -7723,16 +7760,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec); - #if ENABLE_MULTI_PACKET_QUERY_SNOOPING - // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always, - // even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list). - if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond) - { - ourcacherr->MPUnansweredKA++; - ourcacherr->MPExpectingKA = mDNSfalse; - } - #endif - #if POOF_ENABLED // Having built our ExpectedAnswers list from the questions in this packet, we then remove // any records that are suppressed by the Known Answer list in this packet. @@ -7779,13 +7806,9 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con mDNSBool SendMulticastResponse = mDNSfalse; // Send modern multicast response mDNSBool SendUnicastResponse = mDNSfalse; // Send modern unicast response (not legacy unicast response) -#if !TARGET_OS_EMBEDDED - // always honor kDNSQClass_UnicastResponse in embedded environment to increase reliability - // in high multicast packet loss environments. - // If it's been one TTL/4 since we multicast this, then send a multicast response // for conflict detection, etc. - if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0) + if ((mDNSu32)(m->timenow - rr->LastMCTime) >= (mDNSu32)TicksTTL(rr)/4) { SendMulticastResponse = mDNStrue; // If this record was marked for modern (delayed) unicast response, then mark it as promoted to @@ -7797,7 +7820,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con rr->NR_AnswerTo = NR_AnswerMulticast; } } -#endif // !TARGET_OS_EMBEDDED // If the client insists on a multicast response, then we'd better send one if (rr->NR_AnswerTo == NR_AnswerMulticast) @@ -7925,12 +7947,7 @@ exit: cr->UnansweredQueries++; cr->LastUnansweredTime = m->timenow; if (cr->UnansweredQueries > 1) - #if ENABLE_MULTI_PACKET_QUERY_SNOOPING - debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s", - cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); - #else debugf("ProcessQuery: UnansweredQueries %lu %s", cr->UnansweredQueries, CRDisplayString(m, cr)); - #endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING SetNextCacheCheckTimeForRecord(m, cr); } @@ -7940,49 +7957,12 @@ exit: { // Only show debugging message if this record was not about to expire anyway if (RRExpireTime(cr) - m->timenow > (mDNSs32) kDefaultReconfirmTimeForNoAnswer * 4 / 3 + mDNSPlatformOneSecond) - #if ENABLE_MULTI_PACKET_QUERY_SNOOPING - debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s", - cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); - #else - LogInfo("ProcessQuery: UnansweredQueries %lu TTL %lu mDNS_Reconfirm() for %s", - cr->UnansweredQueries, (RRExpireTime(cr) - m->timenow + mDNSPlatformOneSecond-1) / mDNSPlatformOneSecond, CRDisplayString(m, cr)); - #endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING + LogInfo("ProcessQuery: UnansweredQueries %lu interface %lu TTL %lu mDNS_Reconfirm() for %s", + cr->UnansweredQueries, InterfaceID, (RRExpireTime(cr) - m->timenow + mDNSPlatformOneSecond-1) / mDNSPlatformOneSecond, CRDisplayString(m, cr)); m->mDNSStats.PoofCacheDeletions++; mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); } -#if ENABLE_MULTI_PACKET_QUERY_SNOOPING - // Make a guess, based on the multi-packet query / known answer counts, whether we think we - // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for - // possible packet loss of up to 20% of the additional KA packets.) - else if (cr->MPUnansweredQ * 4 > cr->MPUnansweredKA * 5 + 8) - { - // We want to do this conservatively. - // If there are so many machines on the network that they have to use multi-packet known-answer lists, - // then we don't want them to all hit the network simultaneously with their final expiration queries. - // By setting the record to expire in four minutes, we achieve two things: - // (a) the 90-95% final expiration queries will be less bunched together - // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own - mDNSu32 remain = (mDNSu32)(RRExpireTime(cr) - m->timenow) / 4; - if (remain > 240 * (mDNSu32)mDNSPlatformOneSecond) - remain = 240 * (mDNSu32)mDNSPlatformOneSecond; - - // Only show debugging message if this record was not about to expire anyway - if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond) - debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s", - cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); - - if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond) - cr->UnansweredQueries++; // Treat this as equivalent to one definite unanswered query - cr->MPUnansweredQ = 0; // Clear MPQ/MPKA statistics - cr->MPUnansweredKA = 0; - cr->MPExpectingKA = mDNSfalse; - - if (remain < kDefaultReconfirmTimeForNoAnswer) - remain = kDefaultReconfirmTimeForNoAnswer; - mDNS_Reconfirm_internal(m, cr, remain); - } -#endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING } #endif // POOF_ENABLED @@ -8229,19 +8209,13 @@ mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl) rr->TimeRcvd = m->timenow; rr->resrec.rroriginalttl = ttl; rr->UnansweredQueries = 0; -#if ENABLE_MULTI_PACKET_QUERY_SNOOPING - rr->MPUnansweredQ = 0; - rr->MPUnansweredKA = 0; - rr->MPExpectingKA = mDNSfalse; -#endif SetNextCacheCheckTimeForRecord(m, rr); } mDNSexport void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease) { CacheRecord *rr; - const mDNSu32 slot = HashSlot(&q->qname); - CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); + CacheGroup *cg = CacheGroupForName(m, q->qnamehash, &q->qname); for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) if (rr->CRActiveQuestion == q) { @@ -8454,8 +8428,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage * if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr))) { CacheRecord *rr, *neg = mDNSNULL; - mDNSu32 slot = HashSlot(&q.qname); - CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname); + CacheGroup *cg = CacheGroupForName(m, q.qnamehash, &q.qname); for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) if (SameNameRecordAnswersQuestion(&rr->resrec, qptr)) { @@ -8524,8 +8497,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage * ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec); if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_SOA) { - const mDNSu32 s = HashSlot(m->rec.r.resrec.name); - CacheGroup *cgSOA = CacheGroupForRecord(m, s, &m->rec.r.resrec); + CacheGroup *cgSOA = CacheGroupForRecord(m, &m->rec.r.resrec); const rdataSOA *const soa = (const rdataSOA *)m->rec.r.resrec.rdata->u.data; mDNSu32 ttl_s = soa->min; // We use the lesser of the SOA.MIN field and the SOA record's TTL, *except* @@ -8537,7 +8509,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage * // Create the SOA record as we may have to return this to the questions // that we are acting as a proxy for currently or in the future. - SOARecord = CreateNewCacheEntry(m, s, cgSOA, 1, mDNSfalse, mDNSNULL); + SOARecord = CreateNewCacheEntry(m, HashSlotFromNameHash(m->rec.r.resrec.namehash), cgSOA, 1, mDNSfalse, mDNSNULL); // Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer, // with an Authority Section SOA record for d.com, then this is a hint that the authority @@ -8620,12 +8592,12 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage * // been NULL. If we pass NULL cg to new cache entries that we create below, // it will create additional cache groups for the same name. To avoid that, // look up the cache group again to re-initialize cg again. - cg = CacheGroupForName(m, slot, hash, name); + cg = CacheGroupForName(m, hash, name); if (NSECRecords && DNSSECQuestion(qptr)) { // Create the cache entry with delay and then add the NSEC records // to it and add it immediately. - negcr = CreateNewCacheEntry(m, slot, cg, 1, mDNStrue, mDNSNULL); + negcr = CreateNewCacheEntry(m, HashSlotFromNameHash(hash), cg, 1, mDNStrue, mDNSNULL); if (negcr) { negcr->CRDNSSECQuestion = 0; @@ -8650,7 +8622,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage * else { // Need to add with a delay so that we can tag the SOA record - negcr = CreateNewCacheEntry(m, slot, cg, 1, mDNStrue, mDNSNULL); + negcr = CreateNewCacheEntry(m, HashSlotFromNameHash(hash), cg, 1, mDNStrue, mDNSNULL); if (negcr) { negcr->CRDNSSECQuestion = 0; @@ -8674,9 +8646,6 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage * repeat--; name = (const domainname *)(name->c + 1 + name->c[0]); hash = DomainNameHashValue(name); - slot = HashSlot(name); - // For now, we don't need to update cg here, because we'll do it again immediately, back up at the start of this loop - //cg = CacheGroupForName(m, slot, hash, name); } } } @@ -8891,7 +8860,6 @@ mDNSlocal void mDNSParseNSEC3Records(mDNS *const m, const DNSMessage *const resp } for (i = 0; i < response->h.numAuthorities && ptr && ptr < end; i++) { - mDNSu32 slot; CacheGroup *cg; ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec); @@ -8901,11 +8869,10 @@ mDNSlocal void mDNSParseNSEC3Records(mDNS *const m, const DNSMessage *const resp m->rec.r.resrec.RecordType = 0; continue; } - slot = HashSlot(m->rec.r.resrec.name); - cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec); + cg = CacheGroupForRecord(m, &m->rec.r.resrec); // Create the cache entry but don't add it to the cache it. We need // to cache this along with the main cache record. - rr = CreateNewCacheEntry(m, slot, cg, 0, mDNSfalse, mDNSNULL); + rr = CreateNewCacheEntry(m, HashSlotFromNameHash(m->rec.r.resrec.namehash), cg, 0, mDNSfalse, mDNSNULL); if (rr) { debugf("mDNSParseNSEC3Records: %s", CRDisplayString(m, rr)); @@ -9027,8 +8994,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, CacheRecord *rr; // Remember the unicast question that we found, which we use to make caching // decisions later on in this function - const mDNSu32 slot = HashSlot(&q.qname); - CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname); + CacheGroup *cg = CacheGroupForName(m, q.qnamehash, &q.qname); if (!mDNSOpaque16IsZero(response->h.id)) { unicastQuestion = qptr; @@ -9401,7 +9367,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // have any record(s) of the same type that we should re-assert to rescue them // (see note about "multi-homing and bridged networks" at the end of this function). else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype) - if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2) + if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && (mDNSu32)(m->timenow - rr->LastMCTime) > (mDNSu32)mDNSPlatformOneSecond/2) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; } } } @@ -9420,8 +9386,8 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, if (!AcceptableResponse) LogInfo("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r)); if (m->rrcache_size && AcceptableResponse) { - const mDNSu32 slot = HashSlot(m->rec.r.resrec.name); - CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec); + const mDNSu32 slot = HashSlotFromNameHash(m->rec.r.resrec.namehash); + CacheGroup *cg = CacheGroupForRecord(m, &m->rec.r.resrec); CacheRecord *rr = mDNSNULL; if (McastNSEC3Records) @@ -9447,7 +9413,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, if (AddToCFList) delay = NonZeroTime(m->timenow + mDNSPlatformOneSecond); else - delay = CheckForSoonToExpireRecords(m, m->rec.r.resrec.name, m->rec.r.resrec.namehash, slot, mDNSNULL); + delay = CheckForSoonToExpireRecords(m, m->rec.r.resrec.name, m->rec.r.resrec.namehash, mDNSNULL); // If unique, assume we may have to delay delivery of this 'add' event. // Below, where we walk the CacheFlushRecords list, we either call CacheRecordDeferredAdd() @@ -9513,8 +9479,8 @@ exit: while (CacheFlushRecords != (CacheRecord*)1) { CacheRecord *r1 = CacheFlushRecords, *r2; - const mDNSu32 slot = HashSlot(r1->resrec.name); - const CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec); + const mDNSu32 slot = HashSlotFromNameHash(r1->resrec.namehash); + const CacheGroup *cg = CacheGroupForRecord(m, &r1->resrec); CacheFlushRecords = CacheFlushRecords->NextInCFList; r1->NextInCFList = mDNSNULL; @@ -9664,7 +9630,7 @@ exit: NSECRecords = mDNSNULL; NSECCachePtr = mDNSNULL; } - r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot, mDNSNULL); + r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, mDNSNULL); // If no longer delaying, deliver answer now, else schedule delivery for the appropriate time if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1); else ScheduleNextCacheCheckTime(m, slot, r1->DelayDelivery); @@ -10382,13 +10348,14 @@ mDNSlocal mDNSu32 mDNSGenerateOwnerOptForInterface(mDNS *const m, const mDNSInte mDNSu8 *end = mDNSNULL; mDNSu32 length = 0; AuthRecord opt; + NetworkInterfaceInfo *intf; mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); opt.resrec.rrclass = NormalMaxDNSMessageData; opt.resrec.rdlength = sizeof(rdataOPT); opt.resrec.rdestimate = sizeof(rdataOPT); - NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); + intf = FirstInterfaceForID(m, InterfaceID); SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]); LogSPS("Generated OPT record : %s", ARDisplayString(m, &opt)); @@ -10405,30 +10372,18 @@ mDNSlocal mDNSu32 mDNSGenerateOwnerOptForInterface(mDNS *const m, const mDNSInte return length; } +// Note that this routine is called both for Sleep Proxy Registrations, and for Standard Dynamic +// DNS registrations, but (currently) only has to handle the Sleep Proxy Registration reply case, +// and should ignore Standard Dynamic DNS registration replies, because those are handled elsewhere. +// Really, both should be unified and handled in one place. mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end, const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID) { if (InterfaceID) { - mDNSu32 updatelease = 60 * 60; // If SPS fails to indicate lease time, assume one hour - const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space); - mDNSAddr spsaddr; - char *ifname; - if (ptr) - { - ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); - if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT) - { - const rdataOPT *o; - const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength]; - for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++) - if (o->opt == kDNSOpt_Lease) - { - updatelease = o->u.updatelease; - LogSPS("Sleep Proxy granted lease time %4d seconds, updateid %d, InterfaceID %p", updatelease, mDNSVal16(msg->h.id), InterfaceID); - } - } - m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it - } + mDNSu32 pktlease = 0, spsupdates = 0; + const mDNSBool gotlease = GetPktLease(m, msg, end, &pktlease); + const mDNSu32 updatelease = gotlease ? pktlease : 60 * 60; // If SPS fails to indicate lease time, assume one hour + if (gotlease) LogSPS("DNS Update response contains lease option granting %4d seconds, updateid %d, InterfaceID %p", updatelease, mDNSVal16(msg->h.id), InterfaceID); if (m->CurrentRecord) LogMsg("mDNSCoreReceiveUpdateR ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); @@ -10447,7 +10402,8 @@ mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg if (mDNSOpaque64IsZero(&rr->updateIntID)) rr->updateid = zeroID; rr->expire = NonZeroTime(m->timenow + updatelease * mDNSPlatformOneSecond); - LogSPS("Sleep Proxy %s record %5d 0x%x 0x%x (%d) %s", rr->WakeUp.HMAC.l[0] ? "transferred" : "registered", updatelease, rr->updateIntID.l[1], rr->updateIntID.l[0], mDNSVal16(rr->updateid), ARDisplayString(m,rr)); + spsupdates++; + LogSPS("Sleep Proxy %s record %2d %5d 0x%x 0x%x (%d) %s", rr->WakeUp.HMAC.l[0] ? "transferred" : "registered", spsupdates, updatelease, rr->updateIntID.l[1], rr->updateIntID.l[0], mDNSVal16(rr->updateid), ARDisplayString(m,rr)); if (rr->WakeUp.HMAC.l[0]) { rr->WakeUp.HMAC = zeroEthAddr; // Clear HMAC so that mDNS_Deregister_internal doesn't waste packets trying to wake this host @@ -10460,22 +10416,26 @@ mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now m->CurrentRecord = rr->next; } - - // Update the dynamic store with the IP Address and MAC address of the sleep proxy - ifname = InterfaceNameForID(m, InterfaceID); - mDNSPlatformMemCopy(&spsaddr, srcaddr, sizeof (mDNSAddr)); - mDNSPlatformStoreSPSMACAddr(&spsaddr, ifname); - - // Store the Owner OPT record for this interface. - // Configd may use the OPT record if it detects a conflict with the BSP when the system wakes up - DNSMessage optMsg; - int length = 0; - InitializeDNSMessage(&optMsg.h, zeroID, ResponseFlags); - length = mDNSGenerateOwnerOptForInterface(m, InterfaceID, &optMsg); - if (length != 0) + if (spsupdates) // Only do this dynamic store stuff if this was, in fact, a Sleep Proxy Update response { - length += sizeof(DNSMessageHeader); - mDNSPlatformStoreOwnerOptRecord(ifname, &optMsg, length); + char *ifname; + mDNSAddr spsaddr; + DNSMessage optMsg; + int length; + // Update the dynamic store with the IP Address and MAC address of the sleep proxy + ifname = InterfaceNameForID(m, InterfaceID); + mDNSPlatformMemCopy(&spsaddr, srcaddr, sizeof (mDNSAddr)); + mDNSPlatformStoreSPSMACAddr(&spsaddr, ifname); + + // Store the Owner OPT record for this interface. + // Configd may use the OPT record if it detects a conflict with the BSP when the system wakes up + InitializeDNSMessage(&optMsg.h, zeroID, ResponseFlags); + length = mDNSGenerateOwnerOptForInterface(m, InterfaceID, &optMsg); + if (length != 0) + { + length += sizeof(DNSMessageHeader); + mDNSPlatformStoreOwnerOptRecord(ifname, &optMsg, length); + } } } // If we were waiting to go to sleep, then this SPS registration or wide-area record deletion @@ -10512,12 +10472,6 @@ mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr, cr->CRActiveQuestion = mDNSNULL; cr->UnansweredQueries = 0; cr->LastUnansweredTime = 0; -#if ENABLE_MULTI_PACKET_QUERY_SNOOPING - cr->MPUnansweredQ = 0; - cr->MPLastUnansweredQT = 0; - cr->MPUnansweredKA = 0; - cr->MPExpectingKA = mDNSfalse; -#endif cr->NextInCFList = mDNSNULL; cr->nsec = mDNSNULL; cr->soa = mDNSNULL; @@ -10595,7 +10549,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS // Track the number of multicast packets received from a source outside our subnet. // Check the destination address to avoid accounting for spurious packets that // comes in with message id zero. - if (!mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr) && + if (!mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr) && dstaddr && mDNSAddressIsAllDNSLinkGroup(dstaddr)) { m->RemoteSubnet++; @@ -10624,8 +10578,8 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS { static int msgCount = 0; if (msgCount < 1000) { - msgCount++; int i = 0; + msgCount++; LogInfo("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d length %d on %p (ignored)", msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), (int)(end - pkt), InterfaceID); while (i < (int)(end - pkt)) @@ -10658,6 +10612,11 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS #define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \ (mDNSSameAddress(& (A)->Target, & (B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort))) +// SameQuestionKind is true if *both* questions are either multicast or unicast +// TargetQID is used for this determination. +#define SameQuestionKind(A,B) ((mDNSOpaque16IsZero(A) && mDNSOpaque16IsZero(B)) || \ + ((!mDNSOpaque16IsZero(A)) && (!mDNSOpaque16IsZero(B)))) + // Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the // circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV" // and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails @@ -10701,8 +10660,9 @@ mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuest (q->DisallowPID == question->DisallowPID) && // Disallowing a PID should not affect a PID that is allowed (q->BrowseThreshold == question->BrowseThreshold) && // browse thresholds must match q->qnamehash == question->qnamehash && - (IsAWDLIncluded(q) == IsAWDLIncluded(question)) && // Inclusion of AWDL interface must match - SameDomainName(&q->qname, &question->qname)) // and name + (IsAWDLIncluded(q) == IsAWDLIncluded(question)) && // Inclusion of AWDL interface must match + SameQuestionKind(q->TargetQID, question->TargetQID) && // mDNS or uDNS must match + SameDomainName(&q->qname, &question->qname)) // and name return(q); return(mDNSNULL); } @@ -11007,7 +10967,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question) mDNSu32 timeout = 0; mDNSBool DEQuery; - question->validDNSServers = zeroOpaque64; + question->validDNSServers = zeroOpaque128; DEQuery = DomainEnumQuery(&question->qname); for (curr = m->DNSServers; curr; curr = curr->next) { @@ -11036,6 +10996,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question) currcount = CountLabels(&curr->domain); if ((!curr->cellIntf || (!DEQuery && !(question->flags & kDNSServiceFlagsDenyCellular))) && + (!curr->isExpensive || !(question->flags & kDNSServiceFlagsDenyExpensive)) && DNSServerMatch(curr, question->InterfaceID, question->ServiceID)) { bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen); @@ -11050,7 +11011,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question) if (bettermatch) { debugf("SetValidDNSServers: Resetting all the bits"); - question->validDNSServers = zeroOpaque64; + question->validDNSServers = zeroOpaque128; timeout = 0; } debugf("SetValidDNSServers: question %##s Setting the bit for DNS server Address %#a (Domain %##s), Scoped:%d index %d," @@ -11059,15 +11020,15 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question) timeout += curr->timeout; if (DEQuery) debugf("DomainEnumQuery: Question %##s, DNSServer %#a, cell %d", question->qname.c, &curr->addr, curr->cellIntf); - bit_set_opaque64(question->validDNSServers, index); + bit_set_opaque128(question->validDNSServers, index); } } index++; } question->noServerResponse = 0; - debugf("SetValidDNSServers: ValidDNSServer bits 0x%x%x for question %p %##s (%s)", - question->validDNSServers.l[1], question->validDNSServers.l[0], question, question->qname.c, DNSTypeName(question->qtype)); + debugf("SetValidDNSServers: ValidDNSServer bits 0x%x%x%x%x for question %p %##s (%s)", + question->validDNSServers.l[3], question->validDNSServers.l[2], question->validDNSServers.l[1], question->validDNSServers.l[0], question, question->qname.c, DNSTypeName(question->qtype)); // If there are no matching resolvers, then use the default timeout value. // For ProxyQuestion, shorten the timeout so that dig does not timeout on us in case of no response. return ((question->ProxyQuestion || question->ValidatingResponse) ? DEFAULT_UDNSSEC_TIMEOUT : timeout ? timeout : DEFAULT_UDNS_TIMEOUT); @@ -11075,7 +11036,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question) // Get the Best server that matches a name. If you find penalized servers, look for the one // that will come out of the penalty box soon -mDNSlocal DNSServer *GetBestServer(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID, mDNSs32 ServiceID, mDNSOpaque64 validBits, +mDNSlocal DNSServer *GetBestServer(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID, mDNSs32 ServiceID, mDNSOpaque128 validBits, int *selected, mDNSBool nameMatch) { DNSServer *curmatch = mDNSNULL; @@ -11154,7 +11115,7 @@ mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInter { DNSServer *curmatch = mDNSNULL; char *ifname = mDNSNULL; // for logging purposes only - mDNSOpaque64 allValid; + mDNSOpaque128 allValid; if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly)) InterfaceID = mDNSNULL; @@ -11162,7 +11123,7 @@ mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInter if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID); // By passing in all ones, we make sure that every DNS server is considered - allValid.l[0] = allValid.l[1] = 0xFFFFFFFF; + allValid.l[0] = allValid.l[1] = allValid.l[2] = allValid.l[3] = 0xFFFFFFFF; curmatch = GetBestServer(m, name, InterfaceID, ServiceID, allValid, mDNSNULL, mDNStrue); @@ -11191,11 +11152,11 @@ mDNSexport DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question) if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID); - if (!mDNSOpaque64IsZero(&question->validDNSServers)) + if (!mDNSOpaque128IsZero(&question->validDNSServers)) { curmatch = GetBestServer(m, name, InterfaceID, question->ServiceID, question->validDNSServers, &currindex, mDNSfalse); if (currindex != -1) - bit_clr_opaque64(question->validDNSServers, currindex); + bit_clr_opaque128(question->validDNSServers, currindex); } if (curmatch != mDNSNULL) @@ -11289,6 +11250,13 @@ mDNSlocal mDNSBool ShouldSuppressUnicastQuery(mDNS *const m, DNSQuestion *q, DNS DNSTypeName(q->qtype), d->domain.c, &d->addr, mDNSVal16(d->port)); return mDNSfalse; } +#if USE_DNS64 + if (DNS64IsQueryingARecord(q->dns64.state)) + { + LogInfo("ShouldSuppressUnicastQuery: DNS64 query not suppressed for %##s, qtype %s", q->qname.c, DNSTypeName(q->qtype)); + return mDNSfalse; + } +#endif LogInfo("ShouldSuppressUnicastQuery: Query suppressed for %##s, qtype %s, since DNS Configuration does not allow (req_A is %s and req_AAAA is %s)", q->qname.c, DNSTypeName(q->qtype), d->req_A ? "true" : "false", d->req_AAAA ? "true" : "false"); @@ -11384,11 +11352,9 @@ mDNSlocal mDNSBool ShouldSuppressQuery(mDNS *const m, DNSQuestion *q) mDNSlocal void CacheRecordRmvEventsForCurrentQuestion(mDNS *const m, DNSQuestion *q) { CacheRecord *rr; - mDNSu32 slot; CacheGroup *cg; - slot = HashSlot(&q->qname); - cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); + cg = CacheGroupForName(m, q->qnamehash, &q->qname); for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) { // Don't deliver RMV events for negative records @@ -11445,7 +11411,6 @@ mDNSlocal mDNSBool IsQuestionNew(mDNS *const m, DNSQuestion *question) mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q) { AuthRecord *rr; - mDNSu32 slot; AuthGroup *ag; if (m->CurrentQuestion) @@ -11458,8 +11423,7 @@ mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q return mDNStrue; } m->CurrentQuestion = q; - slot = AuthHashSlot(&q->qname); - ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); + ag = AuthGroupForName(&m->rrauth, q->qnamehash, &q->qname); if (ag) { for (rr = ag->members; rr; rr=rr->next) @@ -11485,7 +11449,7 @@ mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q // Returns false if the question got deleted while delivering the RMV events // The caller should handle the case -mDNSlocal mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q) +mDNSexport mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q) { if (m->CurrentQuestion) LogMsg("CacheRecordRmvEventsForQuestion: ERROR m->CurrentQuestion already set: %##s (%s)", @@ -11684,33 +11648,29 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question) { // First reset all DNS Configuration question->qDNSServer = mDNSNULL; - question->validDNSServers = zeroOpaque64; + question->validDNSServers = zeroOpaque128; question->triedAllServersOnce = 0; question->noServerResponse = 0; - question->StopTime = 0; -#if TARGET_OS_EMBEDDED + question->StopTime = (question->TimeoutQuestion) ? question->StopTime : 0; +#if AWD_METRICS mDNSPlatformMemZero(&question->metrics, sizeof(question->metrics)); #endif - // Need not initialize the DNS Configuration for Local Only OR P2P Questions - if (LocalOnlyOrP2PInterface(question->InterfaceID)) + // Need not initialize the DNS Configuration for Local Only OR P2P Questions when timeout not specified + if (LocalOnlyOrP2PInterface(question->InterfaceID) && !question->TimeoutQuestion) return; // Proceed to initialize DNS Configuration (some are set in SetValidDNSServers()) if (!mDNSOpaque16IsZero(question->TargetQID)) { mDNSu32 timeout = SetValidDNSServers(m, question); - // We set the timeout whenever mDNS_StartQuery_internal is called. This means if we have - // a networking change/search domain change that calls this function again we keep - // reinitializing the timeout value which means it may never timeout. If this becomes - // a common case in the future, we can easily fix this by adding extra state that - // indicates that we have already set the StopTime. - // - // Note that we set the timeout for all questions. If this turns out to be a duplicate, + // We set the timeout value the first time mDNS_StartQuery_internal is called for a question. + // So if a question is restarted when a network change occurs, the StopTime is not reset. + // Note that we set the timeout for all questions. If this turns out to be a duplicate, // it gets a full timeout value even if the original question times out earlier. - if (question->TimeoutQuestion) + if (question->TimeoutQuestion && !question->StopTime) { question->StopTime = NonZeroTime(m->timenow + timeout * mDNSPlatformOneSecond); - LogInfo("InitDNSConfig: Setting StopTime on question %p %##s (%s)", question, question->qname.c, DNSTypeName(question->qtype)); + LogInfo("InitDNSConfig: Setting StopTime on the uDNS question %p %##s (%s)", question, question->qname.c, DNSTypeName(question->qtype)); } question->qDNSServer = GetServerForQuestion(m, question); @@ -11719,17 +11679,22 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question) question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL, mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort)); } - else + else if (question->TimeoutQuestion && !question->StopTime) { - if (question->TimeoutQuestion) - question->StopTime = NonZeroTime(m->timenow + GetTimeoutForMcastQuestion(m, question) * mDNSPlatformOneSecond); + // If the question is to be timed out and its a multicast, local-only or P2P case, + // then set it's stop time. + mDNSu32 timeout = LocalOnlyOrP2PInterface(question->InterfaceID) ? + DEFAULT_LO_OR_P2P_TIMEOUT : GetTimeoutForMcastQuestion(m, question); + question->StopTime = NonZeroTime(m->timenow + timeout * mDNSPlatformOneSecond); + LogInfo("InitDNSConfig: Setting StopTime on question %p %##s (%s)", question, question->qname.c, DNSTypeName(question->qtype)); } // Set StopTime here since it is a part of DNS Configuration if (question->StopTime) SetNextQueryStopTime(m, question); - // SetNextQueryTime() need not be initialized for LocalOnly OR P2P Questions since those questions - // will never be transmitted on the wire. Hence we call SetNextQueryTime() here. - SetNextQueryTime(m,question); + // Don't call SetNextQueryTime() if a LocalOnly OR P2P Question since those questions + // will never be transmitted on the wire. + if (!(LocalOnlyOrP2PInterface(question->InterfaceID))) + SetNextQueryTime(m,question); } // InitCommonState() is called by mDNS_StartQuery_internal() to initialize the common(uDNS/mDNS) internal @@ -11755,7 +11720,7 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question) // turned ON which can allocate memory e.g., base64 encoding, in the case of DNSSEC. question->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question question->qnamehash = DomainNameHashValue(&question->qname); - question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname), &purge); + question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, &purge); question->LastQTime = m->timenow; question->ExpectUnicastResp = 0; question->LastAnswerPktNum = m->PktNum; @@ -11792,7 +11757,7 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question) if (!(question->flags & kDNSServiceFlagsServiceIndex)) { #if APPLE_OSX_mDNSResponder - mDNSPlatformGetDNSRoutePolicy(m, question, &isBlocked); + mDNSPlatformGetDNSRoutePolicy(question, &isBlocked); #else question->ServiceID = -1; #endif @@ -11897,10 +11862,12 @@ mDNSlocal void InitLLQState(DNSQuestion *const question) question->id = zeroOpaque64; } +#ifdef DNS_PUSH_ENABLED mDNSlocal void InitDNSPNState(DNSQuestion *const question) { question->dnsPushState = DNSPUSH_INIT; } +#endif // DNS_PUSH_ENABLED // InitDNSSECProxyState() is called by mDNS_StartQuery_internal() to initialize // DNSSEC & DNS Proxy fields of the DNS Question. @@ -11941,6 +11908,16 @@ mDNSlocal void FinalizeUnicastQuestion(mDNS *const m, DNSQuestion *question, mDN if (question->DuplicateOf) { question->validDNSServers = question->DuplicateOf->validDNSServers; + // If current(dup) question has DNS Server assigned but the original question has no DNS Server assigned to it, + // then we log a line as it could indicate an issue + if (question->DuplicateOf->qDNSServer == mDNSNULL) + { + if (question->qDNSServer) + LogInfo("FinalizeUnicastQuestion: Current(dup) question %p has DNSServer(%#a:%d) but original question(%p) has no DNS Server! %##s (%s)", + question, question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL, + mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort), + question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype)); + } question->qDNSServer = question->DuplicateOf->qDNSServer; LogInfo("FinalizeUnicastQuestion: Duplicate question %p (%p) %##s (%s), DNS Server %#a:%d", question, question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype), @@ -12031,7 +12008,9 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu purge = InitCommonState(m, question); InitWABState(question); InitLLQState(question); +#ifdef DNS_PUSH_ENABLED InitDNSPNState(question); +#endif // DNS_PUSH_ENABLED InitDNSSECProxyState(m, question); // FindDuplicateQuestion should be called last after all the intialization @@ -12108,8 +12087,7 @@ mDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta) mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question) { - const mDNSu32 slot = HashSlot(&question->qname); - CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname); + CacheGroup *cg = CacheGroupForName(m, question->qnamehash, &question->qname); CacheRecord *rr; DNSQuestion **qp = &m->Questions; @@ -12139,24 +12117,16 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que } #endif // BONJOUR_ON_DEMAND -#if TARGET_OS_EMBEDDED +#if AWD_METRICS if (Question_uDNS(question) && !question->metrics.answered && (question->metrics.querySendCount > 0)) { const domainname * queryName; mDNSBool isForCell; mDNSu32 durationMs; - queryName = question->metrics.originalQName ? question->metrics.originalQName : &question->qname; - isForCell = (question->qDNSServer && question->qDNSServer->cellIntf); - - if (question->metrics.querySendCount > 0) - { - durationMs = ((m->timenow - question->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond; - } - else - { - durationMs = 0; - } + queryName = question->metrics.originalQName ? question->metrics.originalQName : &question->qname; + isForCell = (question->qDNSServer && question->qDNSServer->cellIntf); + durationMs = ((m->timenow - question->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond; MetricsUpdateUDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, durationMs, isForCell); } #endif @@ -12279,6 +12249,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que question->tcp = mDNSNULL; } } +#ifdef DNS_PUSH_ENABLED else if (question->dnsPushState == DNSPUSH_ESTABLISHED) { if (question->tcp) @@ -12288,6 +12259,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que question->tcp = mDNSNULL; } } +#endif // DNS_PUSH_ENABLED #if APPLE_OSX_mDNSResponder UpdateAutoTunnelDomainStatuses(m); #endif @@ -12306,7 +12278,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que FreeAnonInfo(question->AnonInfo); question->AnonInfo = mDNSNULL; } -#if TARGET_OS_EMBEDDED +#if AWD_METRICS if (question->metrics.originalQName) { mDNSPlatformMemFree(question->metrics.originalQName); @@ -12314,6 +12286,10 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que } #endif +#if USE_DNS64 + DNS64ResetState(question); +#endif + return(mStatus_NoError); } @@ -12352,8 +12328,7 @@ mDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const q if (status == mStatus_NoError && !qq) { const CacheRecord *rr; - const mDNSu32 slot = HashSlot(&question->qname); - CacheGroup *const cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname); + CacheGroup *const cg = CacheGroupForName(m, question->qnamehash, &question->qname); LogInfo("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question)) @@ -12585,6 +12560,8 @@ mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m) return(intf); } +// The parameter "set" here refers to the set of AuthRecords used to advertise this interface. +// (It's a set of records, not a set of interfaces.) mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) { char buffer[MAX_REVERSE_MAPPING_NAME]; @@ -12599,6 +12576,8 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) primary = FindFirstAdvertisedInterface(m); if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary + // We should never have primary be NULL, because even if there is + // no other interface yet, we should always find ourself in the list. // If interface is marked as a direct link, we can assume the address record is unique // and does not need to go through the probe phase of the probe/announce packet sequence. @@ -12608,9 +12587,9 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) LogInfo("AdvertiseInterface: Marking address record as kDNSRecordTypeKnownUnique for %s", set->ifname); // Send dynamic update for non-linklocal IPv4 Addresses - mDNS_SetupResourceRecord(&set->RR_A, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, recordType, AuthRecordAny, mDNS_HostNameCallback, set); - mDNS_SetupResourceRecord(&set->RR_PTR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); - mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL); + mDNS_SetupResourceRecord(&set->RR_A, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, recordType, AuthRecordAny, mDNS_HostNameCallback, set); + mDNS_SetupResourceRecord(&set->RR_PTR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); + mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL); #if ANSWER_REMOTE_HOSTNAME_QUERIES set->RR_A.AllowRemoteQuery = mDNStrue; @@ -12907,7 +12886,7 @@ mDNSexport void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceI } } -mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping) +mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, InterfaceActivationSpeed activationSpeed) { AuthRecord *rr; mDNSBool FirstOfType = mDNStrue; @@ -12978,32 +12957,56 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s // We don't want to do a probe, and then see a stale echo of an announcement we ourselves sent, // and think it's a conflicting answer to our probe. // In the case of a flapping interface, we pause for five seconds, and reduce the announcement count to one packet. - const mDNSs32 probedelay = flapping ? mDNSPlatformOneSecond * 5 : mDNSPlatformOneSecond / 2; - const mDNSu8 numannounce = flapping ? (mDNSu8)1 : InitialAnnounceCount; + mDNSs32 probedelay; + mDNSu8 numannounce; + switch (activationSpeed) + { + case FastActivation: + probedelay = (mDNSs32)0; + numannounce = InitialAnnounceCount; + LogMsg("mDNS_RegisterInterface: Using fast activation for DirectLink interface %s (%#a)", set->ifname, &set->ip); + break; - // Use a small amount of randomness: - // In the case of a network administrator turning on an Ethernet hub so that all the - // connected machines establish link at exactly the same time, we don't want them all - // to go and hit the network with identical queries at exactly the same moment. - // We set a random delay of up to InitialQuestionInterval (1/3 second). - // We must *never* set m->SuppressSending to more than that (or set it repeatedly in a way - // that causes mDNSResponder to remain in a prolonged state of SuppressSending, because - // suppressing packet sending for more than about 1/3 second can cause protocol correctness - // to start to break down (e.g. we don't answer probes fast enough, and get name conflicts). - // See <rdar://problem/4073853> mDNS: m->SuppressSending set too enthusiastically - if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval); + case SlowActivation: + probedelay = mDNSPlatformOneSecond * 5; + numannounce = (mDNSu8)1; + LogMsg("mDNS_RegisterInterface: Frequent transitions for interface %s (%#a), doing slow activation", set->ifname, &set->ip); + m->mDNSStats.InterfaceUpFlap++; + break; - if (flapping) - { - LogMsg("mDNS_RegisterInterface: Frequent transitions for interface %s (%#a)", set->ifname, &set->ip); - m->mDNSStats.InterfaceUpFlap++; + case NormalActivation: + default: + probedelay = mDNSPlatformOneSecond / 2; + numannounce = InitialAnnounceCount; + break; } LogInfo("mDNS_RegisterInterface: %s (%#a) probedelay %d", set->ifname, &set->ip, probedelay); - if (m->SuppressProbes == 0 || - m->SuppressProbes - NonZeroTime(m->timenow + probedelay) < 0) - m->SuppressProbes = NonZeroTime(m->timenow + probedelay); + // No probe or sending suppression on DirectLink type interfaces. + if (activationSpeed == FastActivation) + { + m->SuppressSending = 0; + m->SuppressProbes = 0; + } + else + { + // Use a small amount of randomness: + // In the case of a network administrator turning on an Ethernet hub so that all the + // connected machines establish link at exactly the same time, we don't want them all + // to go and hit the network with identical queries at exactly the same moment. + // We set a random delay of up to InitialQuestionInterval (1/3 second). + // We must *never* set m->SuppressSending to more than that (or set it repeatedly in a way + // that causes mDNSResponder to remain in a prolonged state of SuppressSending, because + // suppressing packet sending for more than about 1/3 second can cause protocol correctness + // to start to break down (e.g. we don't answer probes fast enough, and get name conflicts). + // See <rdar://problem/4073853> mDNS: m->SuppressSending set too enthusiastically + if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval); + + if (m->SuppressProbes == 0 || + m->SuppressProbes - NonZeroTime(m->timenow + probedelay) < 0) + m->SuppressProbes = NonZeroTime(m->timenow + probedelay); + } // Include OWNER option in packets for 60 seconds after connecting to the network. Setting // it here also handles the wake up case as the network link comes UP after waking causing @@ -13020,10 +13023,10 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface, { // then reactivate this question // If flapping, delay between first and second queries is nine seconds instead of one second - mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID); + mDNSBool dodelay = (activationSpeed == SlowActivation) && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID); mDNSs32 initial = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval; - mDNSs32 qdelay = dodelay ? mDNSPlatformOneSecond * 5 : 0; - if (dodelay) LogInfo("No cache records expired for %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype)); + mDNSs32 qdelay = dodelay ? kDefaultQueryDelayTimeForFlappingInterface : 0; + if (dodelay) LogInfo("No cache records expired for %##s (%s); delaying questions by %d seconds", q->qname.c, DNSTypeName(q->qtype), qdelay); if (!q->ThisQInterval || q->ThisQInterval > initial) { @@ -13066,7 +13069,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s // Note: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change // the record list and/or question list. // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. -mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping) +mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, InterfaceActivationSpeed activationSpeed) { NetworkInterfaceInfo **p = &m->HostInterfaces; mDNSBool revalidate = mDNSfalse; @@ -13126,7 +13129,7 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se m->mDNSStats.InterfaceDown++; - if (set->McastTxRx && flapping) + if (set->McastTxRx && (activationSpeed == SlowActivation)) { LogMsg("mDNS_DeregisterInterface: Frequent transitions for interface %s (%#a)", set->ifname, &set->ip); m->mDNSStats.InterfaceDownFlap++; @@ -13152,9 +13155,10 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se { // If this interface is deemed flapping, // postpone deleting the cache records in case the interface comes back again - if (set->McastTxRx && flapping) + if (set->McastTxRx && (activationSpeed == SlowActivation)) { - // For a flapping interface we want these record to go away after 30 seconds + // For a flapping interface we want these records to go away after + // kDefaultReconfirmTimeForFlappingInterface seconds if they are not reconfirmed. mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface); // We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them -- // if the interface does come back, any relevant questions will be reactivated anyway @@ -13314,10 +13318,7 @@ mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result) } -// Derive AuthRecType from the coreFlag* values. -// Note, this is not using the external flags values, kDNSServiceFlags*, defined in dns_sd.h. -// It should be changed to do so once the use of coreFlag* is completely replaced with -// the use the kDNSServiceFlags* definitions within mDNSResponder. +// Derive AuthRecType from the kDNSServiceFlags* values. mDNSlocal AuthRecType setAuthRecType(mDNSInterfaceID InterfaceID, mDNSu32 flags) { AuthRecType artype; @@ -13326,12 +13327,12 @@ mDNSlocal AuthRecType setAuthRecType(mDNSInterfaceID InterfaceID, mDNSu32 flags) artype = AuthRecordLocalOnly; else if (InterfaceID == mDNSInterface_P2P || InterfaceID == mDNSInterface_BLE) artype = AuthRecordP2P; - else if ((InterfaceID == mDNSInterface_Any) && (flags & coreFlagIncludeP2P) - && (flags & coreFlagIncludeAWDL)) + else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeP2P) + && (flags & kDNSServiceFlagsIncludeAWDL)) artype = AuthRecordAnyIncludeAWDLandP2P; - else if ((InterfaceID == mDNSInterface_Any) && (flags & coreFlagIncludeP2P)) + else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeP2P)) artype = AuthRecordAnyIncludeP2P; - else if ((InterfaceID == mDNSInterface_Any) && (flags & coreFlagIncludeAWDL)) + else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeAWDL)) artype = AuthRecordAnyIncludeAWDL; else artype = AuthRecordAny; @@ -13370,7 +13371,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, mDNSu32 i; mDNSu32 hostTTL; AuthRecType artype; - mDNSu8 recordType = (flags & coreFlagKnownUnique) ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique; + mDNSu8 recordType = (flags & kDNSServiceFlagsKnownUnique) ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique; sr->ServiceCallback = Callback; sr->ServiceContext = Context; @@ -13388,7 +13389,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, artype, ServiceCallback, sr); mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, artype, ServiceCallback, sr); - if (flags & coreFlagWakeOnly) + if (flags & kDNSServiceFlagsWakeOnlyService) { sr->RR_PTR.AuthFlags = AuthFlagsWakeOnly; } @@ -13399,7 +13400,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, hostTTL = kHostNameTTL; mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, hostTTL, recordType, artype, ServiceCallback, sr); - mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique, artype, ServiceCallback, sr); + mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, recordType, artype, ServiceCallback, sr); // If port number is zero, that means the client is really trying to do a RegisterNoSuchService if (mDNSIPPortIsZero(port)) @@ -13841,7 +13842,7 @@ mDNSlocal void mDNSCoreReceiveRawARP(mDNS *const m, const ARP_EthIP *const arp, } else if (msg == msg3) { - mDNSPlatformSetLocalAddressCacheEntry(m, &rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID); + mDNSPlatformSetLocalAddressCacheEntry(&rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID); } else if (msg == msg4) { @@ -13947,7 +13948,7 @@ mDNSlocal void mDNSCoreReceiveRawND(mDNS *const m, const mDNSEthAddr *const sha, LogSPS("Reached maximum number of restarts for probing - %s", ARDisplayString(m,rr)); } else if (msg == msg3) - mDNSPlatformSetLocalAddressCacheEntry(m, &rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID); + mDNSPlatformSetLocalAddressCacheEntry(&rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID); else if (msg == msg4) SendNDP(m, NDP_Adv, NDP_Solicited, rr, &ndp->target, mDNSNULL, spa, sha); else if (msg == msg5) @@ -14286,7 +14287,7 @@ mDNSexport void mDNSCoreBeSleepProxyServer_internal(mDNS *const m, mDNSu8 sps, m { if (!m->SPSSocket) { - m->SPSSocket = mDNSPlatformUDPSocket(m, zeroIPPort); + m->SPSSocket = mDNSPlatformUDPSocket(zeroIPPort); if (!m->SPSSocket) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); goto fail; } } #ifndef SPC_DISABLED @@ -14328,9 +14329,9 @@ mDNSexport void mDNS_GrowCache(mDNS *const m, CacheEntity *storage, mDNSu32 numr mDNS_Unlock(m); } -mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, - CacheEntity *rrcachestorage, mDNSu32 rrcachesize, - mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context) +mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p, + CacheEntity *rrcachestorage, mDNSu32 rrcachesize, + mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context) { mDNSu32 slot; mDNSs32 timenow; @@ -14370,14 +14371,14 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->timenow_last = timenow; m->NextScheduledEvent = timenow; m->SuppressSending = timenow; - m->NextCacheCheck = timenow + 0x78000000; - m->NextScheduledQuery = timenow + 0x78000000; - m->NextScheduledProbe = timenow + 0x78000000; - m->NextScheduledResponse = timenow + 0x78000000; - m->NextScheduledNATOp = timenow + 0x78000000; - m->NextScheduledSPS = timenow + 0x78000000; - m->NextScheduledKA = timenow + 0x78000000; - m->NextScheduledStopTime = timenow + 0x78000000; + m->NextCacheCheck = timenow + FutureTime; + m->NextScheduledQuery = timenow + FutureTime; + m->NextScheduledProbe = timenow + FutureTime; + m->NextScheduledResponse = timenow + FutureTime; + m->NextScheduledNATOp = timenow + FutureTime; + m->NextScheduledSPS = timenow + FutureTime; + m->NextScheduledKA = timenow + FutureTime; + m->NextScheduledStopTime = timenow + FutureTime; m->NextBLEServiceTime = 0; // zero indicates inactive #if BONJOUR_ON_DEMAND @@ -14399,9 +14400,6 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->SleepLimit = 0; #if APPLE_OSX_mDNSResponder - m->StatStartTime = mDNSPlatformUTC(); - m->NextStatLogTime = m->StatStartTime + kDefaultNextStatsticsLogTime; - m->ActiveStatTime = 0; m->UnicastPacketsSent = 0; m->MulticastPacketsSent = 0; m->RemoteSubnet = 0; @@ -14424,7 +14422,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) { m->rrcache_hash[slot] = mDNSNULL; - m->rrcache_nextcheck[slot] = timenow + 0x78000000;; + m->rrcache_nextcheck[slot] = timenow + FutureTime;; } mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize); @@ -14450,8 +14448,8 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->SuppressProbes = 0; #ifndef UNICAST_DISABLED - m->NextuDNSEvent = timenow + 0x78000000; - m->NextSRVUpdate = timenow + 0x78000000; + m->NextuDNSEvent = timenow + FutureTime; + m->NextSRVUpdate = timenow + FutureTime; m->DNSServers = mDNSNULL; @@ -14482,7 +14480,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->NATTraversals = mDNSNULL; m->CurrentNATTraversal = mDNSNULL; m->retryIntervalGetAddr = 0; // delta between time sent and retry - m->retryGetAddr = timenow + 0x78000000; // absolute time when we retry + m->retryGetAddr = timenow + FutureTime; // absolute time when we retry m->ExtAddress = zerov4Addr; m->PCPNonce[0] = mDNSRandom(-1); m->PCPNonce[1] = mDNSRandom(-1); @@ -14531,6 +14529,17 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, #endif + return(result); +} + +mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, + CacheEntity *rrcachestorage, mDNSu32 rrcachesize, + mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context) +{ + mStatus result = mDNS_InitStorage(m, p, rrcachestorage, rrcachesize, AdvertiseLocalAddresses, Callback, Context); + if (result != mStatus_NoError) + return(result); + result = mDNSPlatformInit(m); #ifndef UNICAST_DISABLED @@ -14604,8 +14613,7 @@ mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const mDNSlocal void mDNS_PurgeForQuestion(mDNS *const m, DNSQuestion *q) { - const mDNSu32 slot = HashSlot(&q->qname); - CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); + CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname); CacheRecord *rp; mDNSu8 validatingResponse = 0; @@ -14640,8 +14648,7 @@ mDNSlocal void mDNS_PurgeForQuestion(mDNS *const m, DNSQuestion *q) // them. mDNSlocal void CheckForDNSSECRecords(mDNS *const m, DNSQuestion *q) { - const mDNSu32 slot = HashSlot(&q->qname); - CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); + CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname); CacheRecord *rp; for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next) @@ -14664,8 +14671,7 @@ mDNSlocal void CheckForDNSSECRecords(mDNS *const m, DNSQuestion *q) mDNSexport mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype) { DNSQuestion question; - const mDNSu32 slot = HashSlot(&q->qname); - CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); + CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname); CacheRecord *rp; // Create an identical question but with qtype @@ -14788,7 +14794,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) // hence we are ready to ack the configuration as this is the last call to mDNSPlatformSetConfig // for the dns configuration change notification. SetConfigState(m, mDNStrue); - if (!mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL, mDNStrue)) + if (!mDNSPlatformSetDNSConfig(mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL, mDNStrue)) { SetDynDNSHostNameIfChanged(m, &fqdn); SetConfigState(m, mDNSfalse); @@ -14844,6 +14850,9 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) // cache records and as the resGroupID is different, you can't use the cache record from the scoped DNSServer to answer the // non-scoped question and vice versa. // +#if USE_DNS64 + DNS64RestartQuestions(m); +#endif for (q = m->Questions; q; q=q->next) { if (!mDNSOpaque16IsZero(q->TargetQID)) @@ -15007,7 +15016,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) { LogMsg("uDNS_SetupDNSConfig: ERROR!! Cache Record %s Active question %##s (%s) (scope:%p) pointing to DNSServer Address %#a" " to be freed", CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype), qptr->InterfaceID, &ptr->addr); - qptr->validDNSServers = zeroOpaque64; + qptr->validDNSServers = zeroOpaque128; qptr->qDNSServer = mDNSNULL; cr->resrec.rDNSServer = mDNSNULL; } @@ -15070,7 +15079,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) v4 = v6 = r = zeroAddr; v4.type = r.type = mDNSAddrType_IPv4; - if (mDNSPlatformGetPrimaryInterface(m, &v4, &v6, &r) == mStatus_NoError && !mDNSv4AddressIsLinkLocal(&v4.ip.v4)) + if (mDNSPlatformGetPrimaryInterface(&v4, &v6, &r) == mStatus_NoError && !mDNSv4AddressIsLinkLocal(&v4.ip.v4)) { mDNS_SetPrimaryInterfaceInfo(m, !mDNSIPv4AddressIsZero(v4.ip.v4) ? &v4 : mDNSNULL, @@ -15256,3 +15265,7 @@ mDNSexport void mDNS_FinalExit(mDNS *const m) LogInfo("mDNS_FinalExit: done"); } + +#ifdef UNIT_TEST +#include "../unittests/mdns_ut.c" +#endif |