summaryrefslogtreecommitdiffstats
path: root/mDNSResponder/mDNSCore/mDNS.c
diff options
context:
space:
mode:
Diffstat (limited to 'mDNSResponder/mDNSCore/mDNS.c')
-rwxr-xr-xmDNSResponder/mDNSCore/mDNS.c1826
1 files changed, 983 insertions, 843 deletions
diff --git a/mDNSResponder/mDNSCore/mDNS.c b/mDNSResponder/mDNSCore/mDNS.c
index 6b02be46..d1841a5e 100755
--- a/mDNSResponder/mDNSCore/mDNS.c
+++ b/mDNSResponder/mDNSCore/mDNS.c
@@ -49,6 +49,9 @@
#if APPLE_OSX_mDNSResponder
#include <WebFilterDNS/WebFilterDNS.h>
+// Delay in seconds before disabling multicast after there are no active queries or registrations.
+#define BONJOUR_DISABLE_DELAY 60
+
#if !NO_WCF
WCFConnection *WCFConnectionNew(void) __attribute__((weak_import));
void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import));
@@ -69,7 +72,7 @@ void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import));
// 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);
+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);
@@ -106,16 +109,39 @@ mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *et
#define NR_AnswerMulticast (mDNSu8*)~0
#define NR_AnswerUnicast (mDNSu8*)~1
-// Defined to set the kDNSQClass_UnicastResponse bit in the first four query packets.
-// else, it's just set it the first query.
-#define mDNS_REQUEST_UNICAST_RESPONSE 0
-
// 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.
#define SET_QU_IN_FIRST_QUERY 2
-#define SET_QU_IN_FIRST_FOUR_QUERIES 5
+#define kDefaultRequestUnicastCount SET_QU_IN_FIRST_QUERY
+
+// The time needed to offload records to a sleep proxy after powerd sends the kIOMessageSystemWillSleep notification
+#define DARK_WAKE_DELAY_SLEEP 5
+#define kDarkWakeDelaySleep (mDNSPlatformOneSecond * DARK_WAKE_DELAY_SLEEP)
+
+// The maximum number of times we delay probing to prevent spurious conflicts due to stale packets
+#define MAX_CONFLICT_PROCESSING_DELAYS 3
+
+// RFC 6762 defines Passive Observation Of Failures (POOF)
+//
+// A host observes the multicast queries issued by the other hosts on
+// the network. One of the major benefits of also sending responses
+// using multicast is that it allows all hosts to see the responses
+// (or lack thereof) to those queries.
+//
+// If a host sees queries, for which a record in its cache would be
+// expected to be given as an answer in a multicast response, but no
+// such answer is seen, then the host may take this as an indication
+// that the record may no longer be valid.
+//
+// After seeing two or more of these queries, and seeing no multicast
+// response containing the expected answer within ten seconds, then even
+// though its TTL may indicate that it is not yet due to expire, that
+// record SHOULD be flushed from the cache.
+//
+// <https://tools.ietf.org/html/rfc6762#section-10.5>
+#define POOF_ENABLED 1
mDNSexport const char *const mDNS_DomainTypeNames[] =
{
@@ -294,13 +320,13 @@ 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
if (ag)
{
- LogInfo("InsertAuthRecord: inserting auth record %s from table", ARDisplayString(m, rr));
*(ag->rrauth_tail) = rr; // Append this record to tail of cache slot list
ag->rrauth_tail = &(rr->next); // Advance tail pointer
}
@@ -310,13 +336,12 @@ mDNSexport AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *r
mDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr)
{
AuthGroup *a;
- AuthGroup **ag = &a;
AuthRecord **rp;
const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
a = AuthGroupForRecord(r, slot, &rr->resrec);
if (!a) { LogMsg("RemoveAuthRecord: ERROR!! AuthGroup not found for %s", ARDisplayString(m, rr)); return mDNSNULL; }
- rp = &(*ag)->members;
+ rp = &a->members;
while (*rp)
{
if (*rp != rr)
@@ -330,7 +355,7 @@ mDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *r
}
}
// TBD: If there are no more members, release authgroup ?
- (*ag)->rrauth_tail = rp;
+ a->rrauth_tail = rp;
return a;
}
@@ -412,14 +437,15 @@ mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID Interfa
}
// Caller should hold the lock
-mDNSlocal void GenerateNegativeResponse(mDNS *const m, QC_result qc)
+mDNSlocal void GenerateNegativeResponse(mDNS *const m, mDNSInterfaceID InterfaceID, QC_result qc)
{
DNSQuestion *q;
if (!m->CurrentQuestion) { LogMsg("GenerateNegativeResponse: ERROR!! CurrentQuestion not set"); return; }
q = m->CurrentQuestion;
LogInfo("GenerateNegativeResponse: Generating negative response for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, mDNSNULL);
+ MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, InterfaceID, mDNSNULL);
+
// We need to force the response through in the following cases
//
// a) SuppressUnusable questions that are suppressed
@@ -447,28 +473,10 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re
UDPSocket *sock = q->LocalSocket;
mDNSOpaque16 id = q->TargetQID;
#if TARGET_OS_EMBEDDED
- domainname *originalQName;
+ uDNSMetrics metrics;
#endif
- // if there is a message waiting at the socket, we want to process that instead
- // of throwing it away. If we have a CNAME response that answers
- // both A and AAAA question and while answering it we don't want to throw
- // away the response where the actual addresses are present.
- // This is a stupid hack and we should get rid of it.
- // The chance of there being a second unicast UDP packet already waiting in the kernel before we’ve
- // finished processing the previous one is virtually nil, and will only happen by luck on very rare
- // occasions when running on a machine with a fast network connection and a slow or busy processor.
- // The idea that we’d rely for correctness on this random chance event occurring is ridiculous.
- // -- SC
- if (mDNSPlatformPeekUDP(m, q->LocalSocket))
- {
- LogInfo("AnswerQuestionByFollowingCNAME: Preserving UDP socket for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- q->LocalSocket = mDNSNULL;
- }
- else
- {
- sock = mDNSNULL;
- }
+ q->LocalSocket = mDNSNULL;
// The SameDomainName check above is to ignore bogus CNAME records that point right back at
// themselves. Without that check we can get into a case where we have two duplicate questions,
@@ -489,29 +497,24 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re
q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, RRDisplayString(m, rr));
#if TARGET_OS_EMBEDDED
- if (q->metrics.originalQName)
- {
- originalQName = q->metrics.originalQName;
- q->metrics.originalQName = mDNSNULL;
- }
- else
+ if ((q->CNAMEReferrals == 0) && !q->metrics.originalQName)
{
- mDNSu16 qNameLen;
+ domainname * qName;
+ mDNSu16 qNameLen;
qNameLen = DomainNameLength(&q->qname);
if ((qNameLen > 0) && (qNameLen <= MAX_DOMAIN_NAME))
{
- originalQName = mDNSPlatformMemAllocate(qNameLen);
- if (originalQName)
+ qName = mDNSPlatformMemAllocate(qNameLen);
+ if (qName)
{
- mDNSPlatformMemCopy(originalQName->c, q->qname.c, qNameLen);
+ mDNSPlatformMemCopy(qName->c, q->qname.c, qNameLen);
+ q->metrics.originalQName = qName;
}
}
- else
- {
- originalQName = mDNSNULL;
- }
}
+ metrics = q->metrics;
+ mDNSPlatformMemZero(&q->metrics, sizeof(q->metrics));
#endif
mDNS_StopQuery_internal(m, q); // Stop old query
AssignDomainName(&q->qname, &rr->rdata->u.name); // Update qname
@@ -530,19 +533,96 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re
// because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero
q->CNAMEReferrals = c;
#if TARGET_OS_EMBEDDED
- q->metrics.originalQName = originalQName;
+ q->metrics = metrics;
#endif
if (sock)
{
- // We have a message waiting and that should answer this question.
- if (q->LocalSocket)
- mDNSPlatformUDPClose(q->LocalSocket);
- q->LocalSocket = sock;
- q->TargetQID = id;
+ // If our new query is a duplicate, then it can't have a socket of its own, so we have to close the one we saved.
+ if (q->DuplicateOf) mDNSPlatformUDPClose(sock);
+ else
+ {
+ // Transplant the old socket into the new question, and copy the query ID across too.
+ // No need to close the old q->LocalSocket value because it won't have been created yet (they're made lazily on-demand).
+ q->LocalSocket = sock;
+ q->TargetQID = id;
+ }
}
}
}
+#ifdef USE_LIBIDN
+
+#include <unicode/uidna.h>
+
+// #define DEBUG_PUNYCODE 1
+
+mDNSlocal mDNSu8 *PunycodeConvert(const mDNSu8 *const src, mDNSu8 *const dst, const mDNSu8 *const end)
+{
+ UErrorCode errorCode = U_ZERO_ERROR;
+ UIDNAInfo info = UIDNA_INFO_INITIALIZER;
+ UIDNA *uts46 = uidna_openUTS46(UIDNA_USE_STD3_RULES|UIDNA_NONTRANSITIONAL_TO_UNICODE, &errorCode);
+ int32_t len = uidna_nameToASCII_UTF8(uts46, (const char *)src+1, src[0], (char *)dst+1, end-(dst+1), &info, &errorCode);
+ uidna_close(uts46);
+ #if DEBUG_PUNYCODE
+ if (errorCode) LogMsg("uidna_nameToASCII_UTF8(%##s) failed errorCode %d", src, errorCode);
+ if (info.errors) LogMsg("uidna_nameToASCII_UTF8(%##s) failed info.errors 0x%08X", src, info.errors);
+ if (len > MAX_DOMAIN_LABEL) LogMsg("uidna_nameToASCII_UTF8(%##s) result too long %d", src, len);
+ #endif
+ if (errorCode || info.errors || len > MAX_DOMAIN_LABEL) return mDNSNULL;
+ *dst = len;
+ return(dst + 1 + len);
+}
+
+mDNSlocal mDNSBool IsHighASCIILabel(const mDNSu8 *d)
+{
+ int i;
+ for (i=1; i<=d[0]; i++) if (d[i] & 0x80) return mDNStrue;
+ return mDNSfalse;
+}
+
+mDNSlocal const mDNSu8 *FindLastHighASCIILabel(const domainname *const d)
+{
+ const mDNSu8 *ptr = d->c;
+ const mDNSu8 *ans = mDNSNULL;
+ while (ptr[0])
+ {
+ const mDNSu8 *const next = ptr + 1 + ptr[0];
+ if (ptr[0] > MAX_DOMAIN_LABEL || next >= d->c + MAX_DOMAIN_NAME) return mDNSNULL;
+ if (IsHighASCIILabel(ptr)) ans = ptr;
+ ptr = next;
+ }
+ return ans;
+}
+
+mDNSlocal mDNSBool PerformNextPunycodeConversion(const DNSQuestion *const q, domainname *const newname)
+{
+ const mDNSu8 *h = FindLastHighASCIILabel(&q->qname);
+ #if DEBUG_PUNYCODE
+ LogMsg("PerformNextPunycodeConversion: %##s (%s) Last High-ASCII Label %##s", q->qname.c, DNSTypeName(q->qtype), h);
+ #endif
+ if (!h) return mDNSfalse; // There are no high-ascii labels to convert
+
+ mDNSu8 *const dst = PunycodeConvert(h, newname->c + (h - q->qname.c), newname->c + MAX_DOMAIN_NAME);
+ if (!dst)
+ return mDNSfalse; // The label was not convertible to Punycode
+ else
+ {
+ // If Punycode conversion of final eligible label was successful, copy the rest of the domainname
+ const mDNSu8 *const src = h + 1 + h[0];
+ const mDNSu8 remainder = DomainNameLength((domainname*)src);
+ if (dst + remainder > newname->c + MAX_DOMAIN_NAME) return mDNSfalse; // Name too long -- cannot be converted to Punycode
+
+ mDNSPlatformMemCopy(newname->c, q->qname.c, h - q->qname.c); // Fill in the leading part
+ mDNSPlatformMemCopy(dst, src, remainder); // Fill in the trailing part
+ #if DEBUG_PUNYCODE
+ LogMsg("PerformNextPunycodeConversion: %##s converted to %##s", q->qname.c, newname->c);
+ #endif
+ return mDNStrue;
+ }
+}
+
+#endif // USE_LIBIDN
+
// For a single given DNSQuestion pointed to by CurrentQuestion, deliver an add/remove result for the single given AuthRecord
// Note: All the callers should use the m->CurrentQuestion to see if the question is still valid or not
mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
@@ -766,6 +846,8 @@ mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, cons
pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) || authrr->WakeUp.HMAC.l[0])
if (pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
+ if ((authrr->resrec.InterfaceID == mDNSInterface_Any) &&
+ !mDNSPlatformValidRecordForInterface(authrr, pktrr->resrec.InterfaceID)) return(mDNSfalse);
return (mDNSBool)(
pktrr->resrec.rrclass == authrr->resrec.rrclass &&
pktrr->resrec.namehash == authrr->resrec.namehash &&
@@ -843,11 +925,12 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
{
// To allow us to aggregate probes when a group of services are registered together,
- // the first probe is delayed 1/4 second. This means the common-case behaviour is:
- // 1/4 second wait; probe
+ // the first probe is delayed by a random delay in the range 1/8 to 1/4 second.
+ // This means the common-case behaviour is:
+ // randomized wait; probe
// 1/4 second wait; probe
// 1/4 second wait; probe
- // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
+ // 1/4 second wait; announce (i.e. service is normally announced 7/8 to 1 second after being registered)
m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2));
// If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation
@@ -879,7 +962,9 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
}
rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval;
}
- else if (m->SuppressProbes && m->SuppressProbes - m->timenow >= 0)
+ // 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)
rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval + DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
else
rr->LastAPTime = m->timenow - rr->ThisAPInterval;
@@ -890,7 +975,7 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
// and we can begin broadcasting our announcements to take over ownership of that IP address.
// If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk
// (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address.
- if (rr->AddressProxy.type)
+ if (rr->AddressProxy.type)
rr->LastAPTime = m->timenow;
// Set LastMCTime to now, to inhibit multicast responses
@@ -1068,26 +1153,25 @@ mDNSexport void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
mDNSlocal AuthRecord *CheckAuthIdenticalRecord(AuthHash *r, AuthRecord *rr)
{
- AuthGroup *a;
- AuthGroup **ag = &a;
- AuthRecord **rp;
+ const AuthGroup *a;
+ AuthRecord *rp;
const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
a = AuthGroupForRecord(r, slot, &rr->resrec);
if (!a) return mDNSNULL;
- rp = &(*ag)->members;
- while (*rp)
+ rp = a->members;
+ while (rp)
{
- if (!RecordIsLocalDuplicate(*rp, rr))
- rp=&(*rp)->next;
+ if (!RecordIsLocalDuplicate(rp, rr))
+ rp = rp->next;
else
{
- if ((*rp)->resrec.RecordType == kDNSRecordTypeDeregistering)
+ if (rp->resrec.RecordType == kDNSRecordTypeDeregistering)
{
- (*rp)->AnnounceCount = 0;
- rp=&(*rp)->next;
+ rp->AnnounceCount = 0;
+ rp = rp->next;
}
- else return *rp;
+ else return rp;
}
}
return (mDNSNULL);
@@ -1095,22 +1179,21 @@ mDNSlocal AuthRecord *CheckAuthIdenticalRecord(AuthHash *r, AuthRecord *rr)
mDNSlocal mDNSBool CheckAuthRecordConflict(AuthHash *r, AuthRecord *rr)
{
- AuthGroup *a;
- AuthGroup **ag = &a;
- AuthRecord **rp;
+ const AuthGroup *a;
+ const AuthRecord *rp;
const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
a = AuthGroupForRecord(r, slot, &rr->resrec);
if (!a) return mDNSfalse;
- rp = &(*ag)->members;
- while (*rp)
+ rp = a->members;
+ while (rp)
{
const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr;
- const AuthRecord *s2 = (*rp)->RRSet ? (*rp)->RRSet : *rp;
- if (s1 != s2 && SameResourceRecordSignature((*rp), rr) && !IdenticalSameNameRecord(&(*rp)->resrec, &rr->resrec))
+ const AuthRecord *s2 = rp->RRSet ? rp->RRSet : rp;
+ if (s1 != s2 && SameResourceRecordSignature(rp, rr) && !IdenticalSameNameRecord(&rp->resrec, &rr->resrec))
return mDNStrue;
else
- rp=&(*rp)->next;
+ rp = rp->next;
}
return (mDNSfalse);
}
@@ -1118,21 +1201,20 @@ mDNSlocal mDNSBool CheckAuthRecordConflict(AuthHash *r, AuthRecord *rr)
// checks to see if "rr" is already present
mDNSlocal AuthRecord *CheckAuthSameRecord(AuthHash *r, AuthRecord *rr)
{
- AuthGroup *a;
- AuthGroup **ag = &a;
- AuthRecord **rp;
+ const AuthGroup *a;
+ AuthRecord *rp;
const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
a = AuthGroupForRecord(r, slot, &rr->resrec);
if (!a) return mDNSNULL;
- rp = &(*ag)->members;
- while (*rp)
+ rp = a->members;
+ while (rp)
{
- if (*rp != rr)
- rp=&(*rp)->next;
+ if (rp != rr)
+ rp = rp->next;
else
{
- return *rp;
+ return rp;
}
}
return (mDNSNULL);
@@ -1158,20 +1240,22 @@ mDNSlocal void DecrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
LogInfo("DecrementAutoTargetServices: AutoTargetServices %d Record %s", m->AutoTargetServices, ARDisplayString(m, rr));
}
-#if TARGET_OS_WATCH
+#if BONJOUR_ON_DEMAND
if (!AuthRecord_uDNS(rr))
{
if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
- m->NetworkChanged = m->timenow;
+ m->NextBonjourDisableTime = NonZeroTime(m->timenow + (BONJOUR_DISABLE_DELAY * mDNSPlatformOneSecond));
m->NumAllInterfaceRecords--;
LogInfo("DecrementAutoTargetServices: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %s",
m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, ARDisplayString(m, rr));
}
-#endif
+#endif // BONJOUR_ON_DEMAND
}
mDNSlocal void IncrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
{
+ mDNSBool enablingBonjour = 0;
+
if (RRLocalOnly(rr))
{
// A sanity check, this should be prevented in calling code.
@@ -1179,34 +1263,51 @@ mDNSlocal void IncrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
return;
}
-#if TARGET_OS_WATCH
+#if BONJOUR_ON_DEMAND
if (!AuthRecord_uDNS(rr))
{
m->NumAllInterfaceRecords++;
LogInfo("IncrementAutoTargetServices: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %s",
m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, ARDisplayString(m, rr));
if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
- m->NetworkChanged = m->timenow;
+ {
+ m->NextBonjourDisableTime = 0;
+ if (m->BonjourEnabled == 0)
+ {
+ // Enable Bonjour immediately by scheduling network changed processing where
+ // we will join the multicast group on each active interface.
+ m->BonjourEnabled = 1;
+ enablingBonjour = 1;
+ m->NetworkChanged = m->timenow;
+ }
+ }
}
-#endif
+#endif // BONJOUR_ON_DEMAND
if (!AuthRecord_uDNS(rr) && rr->resrec.rrtype == kDNSType_SRV && rr->AutoTarget == Target_AutoHost)
{
m->AutoTargetServices++;
LogInfo("IncrementAutoTargetServices: AutoTargetServices %d Record %s", m->AutoTargetServices, ARDisplayString(m, rr));
- // If this is the first advertised service
- if (m->AutoTargetServices == 1)
+
+ // If this is the first advertised service and we did not just enable Bonjour above, then
+ // advertise all the interface records. If we did enable Bonjour above, the interface records will
+ // be advertised during the network changed processing scheduled above, so no need
+ // to do it here.
+ if ((m->AutoTargetServices == 1) && (enablingBonjour == 0))
AdvertiseAllInterfaceRecords(m);
}
}
mDNSlocal void getKeepaliveRaddr(mDNS *const m, AuthRecord *rr, mDNSAddr *raddr)
{
- mDNSAddr laddr;
- mDNSEthAddr eth;
- mDNSIPPort lport, rport;
- mDNSu32 timeout, seq, ack;
- mDNSu16 win;
+ mDNSAddr laddr = zeroAddr;
+ mDNSEthAddr eth = zeroEthAddr;
+ mDNSIPPort lport = zeroIPPort;
+ mDNSIPPort rport = zeroIPPort;
+ mDNSu32 timeout = 0;
+ mDNSu32 seq = 0;
+ mDNSu32 ack = 0;
+ mDNSu16 win = 0;
if (mDNS_KeepaliveRecord(&rr->resrec))
{
@@ -1305,15 +1406,15 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
// Set up by client prior to call
// Field Group 2: Persistent metadata for Authoritative Records
-// rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
-// rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
-// rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
-// rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
-// rr->Callback = already set in mDNS_SetupResourceRecord
-// rr->Context = already set in mDNS_SetupResourceRecord
-// rr->RecordType = already set in mDNS_SetupResourceRecord
-// rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
-// rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
+// rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
+// rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
+// rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
+// rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
+// rr->Callback = already set in mDNS_SetupResourceRecord
+// rr->Context = already set in mDNS_SetupResourceRecord
+// rr->RecordType = already set in mDNS_SetupResourceRecord
+// rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
+// rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
// Make sure target is not uninitialized data, or we may crash writing debugging log messages
if (rr->AutoTarget && target) target->c[0] = 0;
@@ -1336,9 +1437,9 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
rr->NR_AnswerTo = mDNSNULL;
rr->NR_AdditionalTo = mDNSNULL;
if (!rr->AutoTarget) InitializeLastAPTime(m, rr);
-// rr->LastAPTime = Set for us in InitializeLastAPTime()
-// rr->LastMCTime = Set for us in InitializeLastAPTime()
-// rr->LastMCInterface = Set for us in InitializeLastAPTime()
+// rr->LastAPTime = Set for us in InitializeLastAPTime()
+// rr->LastMCTime = Set for us in InitializeLastAPTime()
+// rr->LastMCInterface = Set for us in InitializeLastAPTime()
rr->NewRData = mDNSNULL;
rr->newrdlength = 0;
rr->UpdateCallback = mDNSNULL;
@@ -1371,12 +1472,12 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
// times with different values if the external NAT port changes during the lifetime of the service registration.
//if (rr->resrec.rrtype == kDNSType_SRV) rr->NATinfo.IntPort = rr->resrec.rdata->u.srv.port;
-// rr->resrec.interface = already set in mDNS_SetupResourceRecord
-// rr->resrec.name->c = MUST be set by client
-// rr->resrec.rrtype = already set in mDNS_SetupResourceRecord
-// rr->resrec.rrclass = already set in mDNS_SetupResourceRecord
-// rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord
-// rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
+// rr->resrec.interface = already set in mDNS_SetupResourceRecord
+// rr->resrec.name->c = MUST be set by client
+// rr->resrec.rrtype = already set in mDNS_SetupResourceRecord
+// rr->resrec.rrclass = already set in mDNS_SetupResourceRecord
+// rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord
+// rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
// BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
// since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
@@ -1471,7 +1572,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
if (r)
{
- debugf("mDNS_Register_internal:Adding to duplicate list %s", ARDisplayString(m,rr));
+ LogInfo("mDNS_Register_internal: Adding to duplicate list %s", ARDisplayString(m,rr));
*d = rr;
// If the previous copy of this record is already verified unique,
// then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
@@ -1482,7 +1583,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
}
else
{
- debugf("mDNS_Register_internal: Adding to active record list %s", ARDisplayString(m,rr));
+ LogInfo("mDNS_Register_internal: Adding to active record list %s", ARDisplayString(m,rr));
if (RRLocalOnly(rr))
{
AuthGroup *ag;
@@ -1504,6 +1605,19 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
}
}
+ if (!AuthRecord_uDNS(rr)) // This check is superfluous, given that for unicast records we (currently) bail out above
+ {
+ // We have inserted the record in the list. See if we have to advertise the A/AAAA, HINFO, PTR records.
+ IncrementAutoTargetServices(m, rr);
+
+ // For records that are not going to probe, acknowledge them right away
+ if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
+ AcknowledgeRecord(m, rr);
+
+ // Adding a record may affect whether or not we should sleep
+ mDNS_UpdateAllowSleep(m);
+ }
+
// If this is a non-sleep proxy keepalive record, fetch the MAC address of the remote host.
// This is used by the in-NIC proxy to send the keepalive packets.
if (!rr->WakeUp.HMAC.l[0] && mDNS_KeepaliveRecord(&rr->resrec))
@@ -1519,19 +1633,6 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
mDNSPlatformGetRemoteMacAddr(m, &raddr);
}
- if (!AuthRecord_uDNS(rr)) // This check is superfluous, given that for unicast records we (currently) bail out above
- {
- // We have inserted the record in the list. See if we have to advertise the A/AAAA, HINFO, PTR records.
- IncrementAutoTargetServices(m, rr);
-
- // For records that are not going to probe, acknowledge them right away
- if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
- AcknowledgeRecord(m, rr);
-
- // Adding a record may affect whether or not we should sleep
- mDNS_UpdateAllowSleep(m);
- }
-
return(mStatus_NoError);
}
@@ -1577,13 +1678,12 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
if (RRLocalOnly(rr))
{
AuthGroup *a;
- AuthGroup **ag = &a;
AuthRecord **rp;
const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
a = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec);
if (!a) return mDNSfalse;
- rp = &(*ag)->members;
+ rp = &a->members;
while (*rp && *rp != rr) rp=&(*rp)->next;
p = rp;
}
@@ -1793,7 +1893,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
if (drt != mDNS_Dereg_conflict)
{
mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
- LogInfo("mDNS_Deregister_internal: mStatus_MemFree for %s", ARDisplayString(m, rr));
+ LogInfo("mDNS_Deregister_internal: callback with mStatus_MemFree for %s", ARDisplayString(m, rr));
if (rr->RecordCallback)
rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this
mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
@@ -1817,6 +1917,10 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
}
else
{
+#if APPLE_OSX_mDNSResponder
+ // See if this record was also registered with any D2D plugins.
+ D2D_stop_advertising_record(r2);
+#endif
mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict);
// As this is a duplicate record, it will be unlinked from the list
// immediately
@@ -1927,9 +2031,8 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d
rr->v6Requester = zerov6Addr;
// Only sent records registered for P2P over P2P interfaces
- if (intf && !mDNSPlatformValidRecordForInterface(rr, intf))
+ if (intf && !mDNSPlatformValidRecordForInterface(rr, intf->InterfaceID))
{
- LogInfo("SendDelayedUnicastResponse: Not sending %s, on %s", ARDisplayString(m, rr), InterfaceNameForID(m, InterfaceID));
continue;
}
@@ -2343,6 +2446,22 @@ mDNSlocal mDNSBool ShouldSendGoodbyesBeforeSleep(mDNS *const m, const NetworkInt
}
}
+mDNSlocal mDNSBool IsInterfaceValidForAuthRecord(const AuthRecord *ar, mDNSInterfaceID InterfaceID)
+{
+ mDNSBool result;
+
+ if (ar->resrec.InterfaceID == mDNSInterface_Any)
+ {
+ result = mDNSPlatformValidRecordForInterface(ar, InterfaceID);
+ }
+ else
+ {
+ result = (ar->resrec.InterfaceID == InterfaceID);
+ }
+
+ return(result);
+}
+
// Note about acceleration of announcements to facilitate automatic coalescing of
// multiple independent threads of announcements into a single synchronized thread:
// The announcements in the packet may be at different stages of maturity;
@@ -2404,8 +2523,10 @@ mDNSlocal void SendResponses(mDNS *const m)
}
else
{
+ mDNSBool unicastOnly;
LogSPS("SendResponses: Sending wakeup %2d for %.6a %s", rr->AnnounceCount-3, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
- SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password);
+ unicastOnly = ((rr->AnnounceCount == WakeupCount) || (rr->AnnounceCount == WakeupCount - 1)) ? mDNStrue : mDNSfalse;
+ SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password, unicastOnly);
for (r2 = rr; r2; r2=r2->next)
if ((r2->resrec.RecordType == kDNSRecordTypeDeregistering) && r2->AnnounceCount && (r2->resrec.InterfaceID == rr->resrec.InterfaceID) &&
mDNSSameEthAddress(&r2->WakeUp.IMAC, &rr->WakeUp.IMAC) && !mDNSSameEthAddress(&zeroEthAddr, &r2->WakeUp.HMAC))
@@ -2506,17 +2627,28 @@ mDNSlocal void SendResponses(mDNS *const m)
if (rr->ImmedAnswer) // If we're sending this as answer, see that its whole RRSet is similarly marked
{
for (r2 = m->ResourceRecords; r2; r2=r2->next)
- if (ResourceRecordIsValidAnswer(r2))
- if (r2->ImmedAnswer != mDNSInterfaceMark &&
- r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(r2, rr))
- r2->ImmedAnswer = !r2->ImmedAnswer ? rr->ImmedAnswer : mDNSInterfaceMark;
+ {
+ if ((r2->resrec.RecordType & kDNSRecordTypeUniqueMask) && ResourceRecordIsValidAnswer(r2) &&
+ (r2->ImmedAnswer != mDNSInterfaceMark) && (r2->ImmedAnswer != rr->ImmedAnswer) &&
+ SameResourceRecordSignature(r2, rr) &&
+ ((rr->ImmedAnswer == mDNSInterfaceMark) || IsInterfaceValidForAuthRecord(r2, rr->ImmedAnswer)))
+ {
+ r2->ImmedAnswer = !r2->ImmedAnswer ? rr->ImmedAnswer : mDNSInterfaceMark;
+ }
+ }
}
else if (rr->ImmedAdditional) // If we're sending this as additional, see that its whole RRSet is similarly marked
{
for (r2 = m->ResourceRecords; r2; r2=r2->next)
- if (ResourceRecordIsValidAnswer(r2))
- if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(r2, rr))
- r2->ImmedAdditional = rr->ImmedAdditional;
+ {
+ if ((r2->resrec.RecordType & kDNSRecordTypeUniqueMask) && ResourceRecordIsValidAnswer(r2) &&
+ (r2->ImmedAdditional != rr->ImmedAdditional) &&
+ SameResourceRecordSignature(r2, rr) &&
+ IsInterfaceValidForAuthRecord(r2, rr->ImmedAdditional))
+ {
+ r2->ImmedAdditional = rr->ImmedAdditional;
+ }
+ }
}
}
@@ -2529,6 +2661,7 @@ mDNSlocal void SendResponses(mDNS *const m)
rr->ImmedAdditional = mDNSNULL; // No need to send as additional if sending as answer
rr->LastMCTime = m->timenow;
rr->LastMCInterface = rr->ImmedAnswer;
+ rr->ProbeRestartCount = 0; // Reset the probe restart count
// If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done
if (TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2))
{
@@ -2576,9 +2709,8 @@ mDNSlocal void SendResponses(mDNS *const m)
// Skip this interface if the record InterfaceID is *Any and the record is not
// appropriate for the interface type.
if ((rr->SendRNow == intf->InterfaceID) &&
- ((rr->resrec.InterfaceID == mDNSInterface_Any) && !mDNSPlatformValidRecordForInterface(rr, intf)))
+ ((rr->resrec.InterfaceID == mDNSInterface_Any) && !mDNSPlatformValidRecordForInterface(rr, intf->InterfaceID)))
{
- // LogInfo("SendResponses: Not sending %s, on %s", ARDisplayString(m, rr), InterfaceNameForID(m, rr->SendRNow));
rr->SendRNow = GetNextActiveInterfaceID(intf);
}
else if (rr->SendRNow == intf->InterfaceID)
@@ -2651,7 +2783,7 @@ mDNSlocal void SendResponses(mDNS *const m)
// Get the reserved space back
OwnerRecordSpace -= AnoninfoSpace;
- TraceRecordSpace -= AnoninfoSpace;
+ TraceRecordSpace -= AnoninfoSpace;
newptr = responseptr;
for (rr = m->ResourceRecords; rr; rr=rr->next)
{
@@ -2800,10 +2932,9 @@ mDNSlocal void SendResponses(mDNS *const m)
SetupTracerOpt(m, &opt.resrec.rdata->u.opt[0]);
}
newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &opt.resrec);
- if (newptr)
- {
- responseptr = newptr;
- LogInfo("SendResponses put %s %s: %s %s", OwnerRecordSpace ? "OWNER" : "", TraceRecordSpace ? "TRACER" : "", intf->ifname, ARDisplayString(m, &opt));
+ if (newptr)
+ {
+ responseptr = newptr;
}
else if (m->omsg.h.numAnswers + m->omsg.h.numAuthorities + m->omsg.h.numAdditionals == 1)
{
@@ -2816,7 +2947,7 @@ mDNSlocal void SendResponses(mDNS *const m)
m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
}
}
-
+
debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
numDereg, numDereg == 1 ? "" : "s",
numAnnounce, numAnnounce == 1 ? "" : "s",
@@ -3097,11 +3228,11 @@ mDNSlocal const CacheRecord *FindSPSInCache1(mDNS *const m, const DNSQuestion *c
}
return(bestcr);
#else // SPC_DISABLED
- (void) m;
- (void) q;
- (void) c0;
- (void) c1;
- (void) c1;
+ (void) m;
+ (void) q;
+ (void) c0;
+ (void) c1;
+ (void) c1;
return mDNSNULL;
#endif // SPC_DISABLED
}
@@ -3199,7 +3330,7 @@ mDNSlocal void mDNSSendWakeOnResolve(mDNS *const m, DNSQuestion *q)
domainname *d = &q->qname;
// We can't send magic packets without knowing which interface to send it on.
- if (InterfaceID == mDNSInterface_Any || InterfaceID == mDNSInterface_LocalOnly || InterfaceID == mDNSInterface_P2P)
+ if (InterfaceID == mDNSInterface_Any || LocalOnlyOrP2PInterface(InterfaceID))
{
LogMsg("mDNSSendWakeOnResolve: ERROR!! Invalid InterfaceID %p for question %##s", InterfaceID, q->qname.c);
return;
@@ -3415,7 +3546,7 @@ mDNSlocal void SendQueries(mDNS *const m)
// don't send it again until MaxQuestionInterval unless:
// one of its cached answers needs to be refreshed,
// or it's the initial query for a kDNSServiceFlagsThresholdFinder mode browse.
- if (q->BrowseThreshold
+ if (q->BrowseThreshold
&& (q->CurrentAnswers >= q->BrowseThreshold)
&& (q->CachedAnswerNeedsUpdate == mDNSfalse)
&& !((q->flags & kDNSServiceFlagsThresholdFinder) && (q->ThisQInterval == InitialQuestionInterval)))
@@ -3437,7 +3568,7 @@ mDNSlocal void SendQueries(mDNS *const m)
debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d",
q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval / InitialQuestionInterval, q->RequestUnicast);
- if (q->ThisQInterval >= QuestionIntervalThreshold)
+ if (q->ThisQInterval > MaxQuestionInterval)
{
q->ThisQInterval = MaxQuestionInterval;
}
@@ -3500,11 +3631,11 @@ mDNSlocal void SendQueries(mDNS *const m)
{
if (ar->AddressProxy.type == mDNSAddrType_IPv4)
{
- // There's a problem here. If a host is waking up, and we probe to see if it responds, then
- // it will see those ARP probes as signalling intent to use the address, so it picks a different one.
- // A more benign way to find out if a host is responding to ARPs might be send a standard ARP *request*
- // (using our sender IP address) instead of an ARP *probe* (using all-zero sender IP address).
- // A similar concern may apply to the NDP Probe too. -- SC
+ // There's a problem here. If a host is waking up, and we probe to see if it responds, then
+ // it will see those ARP probes as signalling intent to use the address, so it picks a different one.
+ // A more benign way to find out if a host is responding to ARPs might be send a standard ARP *request*
+ // (using our sender IP address) instead of an ARP *probe* (using all-zero sender IP address).
+ // A similar concern may apply to the NDP Probe too. -- SC
LogSPS("SendQueries ARP Probe %d %s %s", ar->ProbeCount, InterfaceNameForID(m, ar->resrec.InterfaceID), ARDisplayString(m,ar));
SendARP(m, 1, ar, &zerov4Addr, &zeroEthAddr, &ar->AddressProxy.ip.v4, &ar->WakeUp.IMAC);
}
@@ -3596,7 +3727,6 @@ mDNSlocal void SendQueries(mDNS *const m)
// If interface is P2P type, verify that query should be sent over it.
if (!mDNSPlatformValidQuestionForInterface(q, intf))
{
- LogInfo("SendQueries: Not sending (%s) %##s on %s", DNSTypeName(q->qtype), q->qname.c, InterfaceNameForID(m, intf->InterfaceID));
q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
}
// If we're suppressing this question, or we successfully put it, update its SendQNow state
@@ -3636,24 +3766,62 @@ mDNSlocal void SendQueries(mDNS *const m)
// Put probe questions in this packet
for (ar = m->ResourceRecords; ar; ar=ar->next)
- if (ar->SendRNow == intf->InterfaceID)
+ {
+ if (ar->SendRNow != intf->InterfaceID)
+ continue;
+
+ // If interface is a P2P variant, verify that the probe should be sent over it.
+ if (!mDNSPlatformValidRecordForInterface(ar, intf->InterfaceID))
+ {
+ ar->SendRNow = (ar->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
+ ar->IncludeInProbe = mDNSfalse;
+ }
+ else
{
mDNSBool ucast = (ar->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353 && intf->SupportsUnicastMDNSResponse;
mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.numQuestions ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData);
// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
mDNSu32 forecast = answerforecast + 12 + ar->resrec.rdestimate;
- mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit - forecast, ar->resrec.name, kDNSQType_ANY, (mDNSu16)(ar->resrec.rrclass | ucbit));
- if (newptr)
+ mDNSBool putProbe = mDNStrue;
+ mDNSu16 qclass = ar->resrec.rrclass | ucbit;
+
+ {// Determine if this probe question is already in packet's dns message
+ const mDNSu8 *questionptr = m->omsg.data;
+ DNSQuestion question;
+ mDNSu16 n;
+ for (n = 0; n < m->omsg.h.numQuestions && questionptr; n++)
+ {
+ questionptr = getQuestion(&m->omsg, questionptr, limit, mDNSInterface_Any, &question);
+ if (questionptr && (question.qtype == kDNSQType_ANY) && (question.qclass == qclass) &&
+ (question.qnamehash == ar->resrec.namehash) && SameDomainName(&question.qname, ar->resrec.name))
+ {
+ putProbe = mDNSfalse; // set to false if already in message
+ break;
+ }
+ }
+ }
+
+ if (putProbe)
+ {
+ mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit - forecast, ar->resrec.name, kDNSQType_ANY, qclass);
+ if (newptr)
+ {
+ queryptr = newptr;
+ answerforecast = forecast;
+ ar->SendRNow = (ar->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
+ ar->IncludeInProbe = mDNStrue;
+ verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d InterfaceID= %d %d %d",
+ ar->resrec.name->c, DNSTypeName(ar->resrec.rrtype), ar->ProbeCount, ar->resrec.InterfaceID, ar->resrec.rdestimate, answerforecast);
+ }
+ }
+ else
{
- queryptr = newptr;
- answerforecast = forecast;
ar->SendRNow = (ar->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
ar->IncludeInProbe = mDNStrue;
- verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d",
- ar->resrec.name->c, DNSTypeName(ar->resrec.rrtype), ar->ProbeCount);
}
}
+ }
}
// Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
@@ -3719,7 +3887,7 @@ mDNSlocal void SendQueries(mDNS *const m)
AuthRecord opt;
mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
opt.resrec.rrclass = NormalMaxDNSMessageData;
- opt.resrec.rdlength = sizeof(rdataOPT);
+ opt.resrec.rdlength = sizeof(rdataOPT);
opt.resrec.rdestimate = sizeof(rdataOPT);
if (OwnerRecordSpace && TraceRecordSpace)
{
@@ -3736,19 +3904,18 @@ mDNSlocal void SendQueries(mDNS *const m)
{
SetupTracerOpt(m, &opt.resrec.rdata->u.opt[0]);
}
- LogInfo("SendQueries putting %s %s: %s %s", OwnerRecordSpace ? "OWNER" : "", TraceRecordSpace ? "TRACER" : "", intf->ifname, ARDisplayString(m, &opt));
queryptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAdditionals,
&opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData);
if (!queryptr)
- {
+ {
LogMsg("SendQueries: How did we fail to have space for %s %s OPT record (%d/%d/%d/%d) %s", OwnerRecordSpace ? "OWNER" : "", TraceRecordSpace ? "TRACER" : "",
m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
}
if (queryptr > m->omsg.data + NormalMaxDNSMessageData)
{
if (m->omsg.h.numQuestions != 1 || m->omsg.h.numAnswers != 0 || m->omsg.h.numAuthorities != 1 || m->omsg.h.numAdditionals != 1)
- LogMsg("SendQueries: Why did we generate oversized packet with %s %s OPT record %p %p %p (%d/%d/%d/%d) %s", OwnerRecordSpace ? "OWNER" : "",
- TraceRecordSpace ? "TRACER" : "", m->omsg.data, m->omsg.data + NormalMaxDNSMessageData, queryptr, m->omsg.h.numQuestions, m->omsg.h.numAnswers,
+ LogMsg("SendQueries: Why did we generate oversized packet with %s %s OPT record %p %p %p (%d/%d/%d/%d) %s", OwnerRecordSpace ? "OWNER" : "",
+ TraceRecordSpace ? "TRACER" : "", m->omsg.data, m->omsg.data + NormalMaxDNSMessageData, queryptr, m->omsg.h.numQuestions, m->omsg.h.numAnswers,
m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
}
}
@@ -3817,17 +3984,21 @@ mDNSlocal void SendQueries(mDNS *const m)
{
DNSQuestion *x;
for (x = m->NewQuestions; x; x=x->next) if (x == q) break; // Check if this question is a NewQuestion
- LogInfo("SendQueries: No active interface %d to send %s question: %d %##s (%s)",
- (uint32_t)q->SendQNow, x ? "new" : "old", (uint32_t)q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
+ // There will not be an active interface for questions applied to mDNSInterface_BLE
+ // so don't log the warning in that case.
+ if (q->InterfaceID != mDNSInterface_BLE)
+ LogInfo("SendQueries: No active interface %d to send %s question: %d %##s (%s)",
+ (uint32_t)q->SendQNow, x ? "new" : "old", (uint32_t)q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
q->SendQNow = mDNSNULL;
}
q->CachedAnswerNeedsUpdate = mDNSfalse;
}
}
-mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password)
+mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password, mDNSBool unicastOnly)
{
int i, j;
+
mDNSu8 *ptr = m->omsg.data;
NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
if (!intf) { LogMsg("SendARP: No interface with InterfaceID %p found", InterfaceID); return; }
@@ -3853,13 +4024,16 @@ mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAdd
mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID);
- // For Ethernet switches that don't flood-foward packets with unknown unicast destination MAC addresses,
- // broadcast is the only reliable way to get a wakeup packet to the intended target machine.
- // For 802.11 WPA networks, where a sleeping target machine may have missed a broadcast/multicast
- // key rotation, unicast is the only way to get a wakeup packet to the intended target machine.
- // So, we send one of each, unicast first, then broadcast second.
- for (i=0; i<6; i++) m->omsg.data[i] = 0xFF;
- mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID);
+ if (!unicastOnly)
+ {
+ // For Ethernet switches that don't flood-foward packets with unknown unicast destination MAC addresses,
+ // broadcast is the only reliable way to get a wakeup packet to the intended target machine.
+ // For 802.11 WPA networks, where a sleeping target machine may have missed a broadcast/multicast
+ // key rotation, unicast is the only way to get a wakeup packet to the intended target machine.
+ // So, we send one of each, unicast first, then broadcast second.
+ for (i=0; i<6; i++) m->omsg.data[i] = 0xFF;
+ mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID);
+ }
}
// ***************************************************************************
@@ -3891,7 +4065,7 @@ mDNSlocal void ResetQuestionState(mDNS *const m, DNSQuestion *q)
mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord)
{
DNSQuestion *const q = m->CurrentQuestion;
- mDNSBool followcname = FollowCNAME(q, &rr->resrec, AddRecord);
+ const mDNSBool followcname = FollowCNAME(q, &rr->resrec, AddRecord);
verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s",
q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr));
@@ -3937,28 +4111,32 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
}
#if TARGET_OS_EMBEDDED
- if ((AddRecord == QC_add) && Question_uDNS(q) && (!q->metrics.answered || (q->metrics.querySendCount > 0)))
+ if ((AddRecord == QC_add) && Question_uDNS(q) && !followcname)
{
- uDNSMetrics * metrics;
const domainname * queryName;
mDNSu32 responseLatencyMs;
mDNSBool isForCellular;
- metrics = &q->metrics;
- queryName = metrics->originalQName ? metrics->originalQName : &q->qname;
- if (metrics->querySendCount > 0)
+ queryName = q->metrics.originalQName ? q->metrics.originalQName : &q->qname;
+ isForCellular = (q->qDNSServer && q->qDNSServer->cellIntf);
+ if (!q->metrics.answered)
{
- responseLatencyMs = ((m->timenow - metrics->firstQueryTime) * 1000) / mDNSPlatformOneSecond;
+ if (q->metrics.querySendCount > 0)
+ {
+ responseLatencyMs = ((m->timenow - q->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond;
+ }
+ else
+ {
+ responseLatencyMs = 0;
+ }
+
+ MetricsUpdateUDNSQueryStats(queryName, q->qtype, &rr->resrec, q->metrics.querySendCount, responseLatencyMs, isForCellular);
+ q->metrics.answered = mDNStrue;
}
- else
+ if (q->metrics.querySendCount > 0)
{
- responseLatencyMs = 0;
+ MetricsUpdateUDNSResolveStats(queryName, &rr->resrec, isForCellular);
}
- isForCellular = (q->qDNSServer && q->qDNSServer->cellIntf);
-
- MetricsUpdateUDNSStats(queryName, mDNStrue, metrics->querySendCount, responseLatencyMs, isForCellular);
- metrics->answered = mDNStrue;
- metrics->querySendCount = 0;
}
#endif
// Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
@@ -3991,6 +4169,30 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us
+#ifdef USE_LIBIDN
+ if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) // If negative answer, check if we need to try Punycode conversion
+ {
+ domainname newname;
+ if (PerformNextPunycodeConversion(q, &newname)) // Itertative Punycode conversion succeeded, so reissue question with new name
+ {
+ UDPSocket *const sock = q->LocalSocket; // Save old socket and transaction ID
+ const mDNSOpaque16 id = q->TargetQID;
+ q->LocalSocket = mDNSNULL;
+ mDNS_StopQuery_internal(m, q); // Stop old query
+ AssignDomainName(&q->qname, &newname); // Update qname
+ q->qnamehash = DomainNameHashValue(&q->qname); // and namehash
+ mDNS_StartQuery_internal(m, q); // Start new query
+
+ if (sock) // Transplant saved socket, if appropriate
+ {
+ if (q->DuplicateOf) mDNSPlatformUDPClose(sock);
+ else { q->LocalSocket = sock; q->TargetQID = id; }
+ }
+ return; // All done for now; wait until we get the next answer
+ }
+ }
+#endif // USE_LIBIDN
+
// Only deliver negative answers if client has explicitly requested them except when we are forcing a negative response
// for the purpose of retrying search domains/timeout OR the question is suppressed
if (rr->resrec.RecordType == kDNSRecordTypePacketNegative || (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype)))
@@ -4041,7 +4243,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
// If we get a CNAME back while we are validating the response (i.e., CNAME for DS, DNSKEY, RRSIG),
// don't follow them. If it is a ValidationRequired question, wait for the CNAME to be validated
// first before following it
- if (!ValidatingQuestion(q) && followcname && m->CurrentQuestion == q)
+ if ((m->CurrentQuestion == q) && followcname && !ValidatingQuestion(q))
AnswerQuestionByFollowingCNAME(m, q, &rr->resrec);
}
@@ -4082,7 +4284,7 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c
// deliver a RMV (for the current old entry) followed by ADD (for the new entry).
// It needs to schedule the timer for the next cache expiry (ScheduleNextCacheCheckTime),
// so that the cache entry can be purged (purging causes the RMV followed by ADD)
- //
+ //
// 2) A new question is about to be answered and the caller needs to know whether it's
// scheduling should be delayed so that the question is not answered with this record.
// Instead of delivering an ADD (old entry) followed by RMV (old entry) and another ADD
@@ -4317,7 +4519,7 @@ mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp)
if ((*cp)->rrcache_tail != &(*cp)->members)
LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
//if ((*cp)->name != (domainname*)((*cp)->namestorage))
- // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
+ // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name);
(*cp)->name = mDNSNULL;
*cp = (*cp)->next; // Cut record from list
@@ -4364,7 +4566,7 @@ mDNSexport void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
r->resrec.rdata = mDNSNULL;
cg = CacheGroupForRecord(m, slot, &r->resrec);
-
+
if (!cg)
{
// It is okay to have this printed for NSEC/NSEC3s
@@ -4417,7 +4619,7 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGrou
if (m->timenow - event >= 0) // If expired, delete it
{
*rp = rr->next; // Cut it from the list
-
+
verbosedebugf("CheckCacheExpiration: Deleting%7d %7d %p %s",
m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr));
if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away
@@ -4509,7 +4711,7 @@ mDNSlocal mDNSBool AnswerQuestionWithLORecord(mDNS *const m, DNSQuestion *q, mDN
// details on how we handle this case. For P2P we just handle "Interface_Any" questions. For LocalOnly
// we handle both mDNSInterface_Any and scoped questions.
- if (rr->ARType == AuthRecordLocalOnly || (rr->ARType == AuthRecordP2P && q->InterfaceID == mDNSInterface_Any))
+ if (rr->ARType == AuthRecordLocalOnly || (rr->ARType == AuthRecordP2P && (q->InterfaceID == mDNSInterface_Any || q->InterfaceID == mDNSInterface_BLE)))
if (LocalOnlyRecordAnswersQuestion(rr, q))
{
if (checkOnly)
@@ -4577,7 +4779,7 @@ mDNSlocal void AnswerSuppressedQuestion(mDNS *const m, DNSQuestion *q)
q->SuppressQuery = mDNSfalse;
q->DisallowPID = mDNSfalse;
- GenerateNegativeResponse(m, QC_suppressed);
+ GenerateNegativeResponse(m, mDNSInterface_Any, QC_suppressed);
q->SuppressQuery = SuppressQuery;
q->DisallowPID = DisallowPID;
@@ -4682,7 +4884,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
- else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
+ else if (mDNSOpaque16IsZero(q->TargetQID) && RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
ShouldQueryImmediately = mDNSfalse;
}
// We don't use LogInfo for this "Question deleted" message because it happens so routinely that
@@ -4696,7 +4898,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
if (!QuerySuppressed(q) && !AnsweredFromCache && q->RetryWithSearchDomains)
{
LogInfo("AnswerNewQuestion: Generating response for retrying with search domains %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- GenerateNegativeResponse(m, QC_forceresponse);
+ GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse);
}
if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving negative answer"); goto exit; }
@@ -4737,6 +4939,7 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
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;
debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
@@ -4762,6 +4965,7 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
m->CurrentRecord = rr->next;
if (LocalOnlyRecordAnswersQuestion(rr, q))
{
+ retEv = mDNStrue;
AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue);
if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
@@ -4778,12 +4982,18 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
m->CurrentRecord = rr->next;
if (ResourceRecordAnswersQuestion(&rr->resrec, q))
{
+ retEv = mDNStrue;
AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue);
if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
}
}
+ // The local host is the authoritative source for LocalOnly questions
+ // so if no records exist and client requested intermediates, then generate a negative response
+ if (!retEv && (m->CurrentQuestion == q) && q->ReturnIntermed)
+ GenerateNegativeResponse(m, mDNSInterface_LocalOnly, QC_forceresponse);
+
m->CurrentQuestion = mDNSNULL;
m->CurrentRecord = mDNSNULL;
}
@@ -4898,7 +5108,7 @@ mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const Res
cg->namehash = rr->namehash;
cg->members = mDNSNULL;
cg->rrcache_tail = &cg->members;
- if (namelen > sizeof(cg->namestorage))
+ if (namelen > sizeof(cg->namestorage))
cg->name = mDNSPlatformMemAllocate(namelen);
else
cg->name = (domainname*)cg->namestorage;
@@ -5029,7 +5239,7 @@ 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, QC_forceresponse);
+ GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse);
if (m->CurrentQuestion == q) q->StopTime = 0;
}
else
@@ -5135,10 +5345,26 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
mDNS_SendKeepalives(m);
}
+#if BONJOUR_ON_DEMAND
+ if (m->NextBonjourDisableTime && (m->timenow - m->NextBonjourDisableTime >= 0))
+ {
+ // Schedule immediate network change processing to leave the multicast group
+ // since the delay time has expired since the previous active registration or query.
+ m->NetworkChanged = m->timenow;
+ m->NextBonjourDisableTime = 0;
+ m->BonjourEnabled = 0;
+
+ LogInfo("mDNS_Execute: Scheduled network changed processing to leave multicast group.");
+ }
+#endif // BONJOUR_ON_DEMAND
+
// Clear AnnounceOwner if necessary. (Do this *before* SendQueries() and SendResponses().)
if (m->AnnounceOwner && m->timenow - m->AnnounceOwner >= 0)
{
m->AnnounceOwner = 0;
+
+ // This is a good time to reset the delay counter used to prevent spurious conflicts
+ m->DelayConflictProcessing = 0;
}
if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
@@ -5305,6 +5531,10 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
if (m->timenow - m->NextScheduledNATOp >= 0) CheckNATMappings(m);
if (m->timenow - m->NextuDNSEvent >= 0) uDNS_Tasks(m);
#endif
+#if APPLE_OSX_mDNSResponder
+ extern void serviceBLE();
+ if (m->NextBLEServiceTime && (m->timenow - m->NextBLEServiceTime >= 0)) serviceBLE();
+#endif // APPLE_OSX_mDNSResponder
}
// Note about multi-threaded systems:
@@ -5550,11 +5780,7 @@ mDNSexport void mDNSCoreRestartQuestion(mDNS *const m, DNSQuestion *q)
if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q))
{
q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question
-#if mDNS_REQUEST_UNICAST_RESPONSE
- q->RequestUnicast = SET_QU_IN_FIRST_FOUR_QUERIES;
-#else // mDNS_REQUEST_UNICAST_RESPONSE
- q->RequestUnicast = SET_QU_IN_FIRST_QUERY;
-#endif // mDNS_REQUEST_UNICAST_RESPONSE
+ q->RequestUnicast = kDefaultRequestUnicastCount;
q->LastQTime = m->timenow - q->ThisQInterval;
q->RecentAnswerPkts = 0;
ExpireDupSuppressInfo(q->DupSuppress, m->timenow);
@@ -5563,23 +5789,26 @@ mDNSexport void mDNSCoreRestartQuestion(mDNS *const m, DNSQuestion *q)
}
// restart the probe/announce cycle for multicast record
-mDNSexport void mDNSCoreRestartRegistration(mDNS *const m, AuthRecord *rr, int announceCount)
+mDNSexport void mDNSCoreRestartRegistration(mDNS *const m, AuthRecord *rr, int announceCount)
{
if (!AuthRecord_uDNS(rr))
{
if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
- // announceCount < 0 indicates default announce count should be used
- if (announceCount < 0)
- announceCount = InitialAnnounceCount;
- if (rr->AnnounceCount < announceCount)
- rr->AnnounceCount = announceCount;
-
if (mDNS_KeepaliveRecord(&rr->resrec))
- rr->AnnounceCount = 0; // Do not announce keepalive records
+ {
+ rr->AnnounceCount = 0; // Do not announce keepalive records
+ }
else
- rr->AnnounceCount = InitialAnnounceCount;
+ {
+ // announceCount < 0 indicates default announce count should be used
+ if (announceCount < 0)
+ announceCount = InitialAnnounceCount;
+ if (rr->AnnounceCount < (mDNSu8)announceCount)
+ rr->AnnounceCount = (mDNSu8)announceCount;
+ }
+
rr->SendNSECNow = mDNSNULL;
InitializeLastAPTime(m, rr);
}
@@ -5672,7 +5901,7 @@ mDNSlocal mDNSBool mDNSUpdateOkToSend(mDNS *const m, AuthRecord *rr, NetworkInte
// If it is not a uDNS record, check to see if the updateid is zero. "updateid" is cleared when we have
// sent the resource record on all the interfaces. If the update id is not zero, check to see if it is time
// to send.
- if (AuthRecord_uDNS(rr) || (rr->AuthFlags & AuthFlagsWakeOnly) || mDNSOpaque16IsZero(rr->updateid) ||
+ if (AuthRecord_uDNS(rr) || (rr->AuthFlags & AuthFlagsWakeOnly) || mDNSOpaque16IsZero(rr->updateid) ||
m->timenow - (rr->LastAPTime + rr->ThisAPInterval) < 0)
{
return mDNSfalse;
@@ -5693,53 +5922,56 @@ mDNSlocal mDNSBool mDNSUpdateOkToSend(mDNS *const m, AuthRecord *rr, NetworkInte
return mDNSfalse;
}
-mDNSexport void UpdateRMACCallback(mDNS *const m, void *context)
-{
- IPAddressMACMapping *addrmap = (IPAddressMACMapping *)context ;
- m->CurrentRecord = m->ResourceRecords;
-
- if (!addrmap)
- {
- LogMsg("UpdateRMACCallback: Address mapping is NULL");
- return;
- }
-
- while (m->CurrentRecord)
- {
- AuthRecord *rr = m->CurrentRecord;
- // If this is a non-sleep proxy keepalive record and the remote IP address matches, update the RData
- if (!rr->WakeUp.HMAC.l[0] && mDNS_KeepaliveRecord(&rr->resrec))
- {
- mDNSAddr raddr;
- getKeepaliveRaddr(m, rr, &raddr);
- if (mDNSSameAddress(&raddr, &addrmap->ipaddr))
- {
- // Update the MAC address only if it is not a zero MAC address
- mDNSEthAddr macAddr;
- mDNSu8 *ptr = GetValueForMACAddr((mDNSu8 *)(addrmap->ethaddr), (mDNSu8 *) (addrmap->ethaddr + sizeof(addrmap->ethaddr)), &macAddr);
- if (ptr != mDNSNULL && !mDNSEthAddressIsZero(macAddr))
- {
- UpdateKeepaliveRData(m, rr, mDNSNULL, mDNStrue, (char *)(addrmap->ethaddr));
- }
- }
- }
- m->CurrentRecord = rr->next;
- }
-
- if (addrmap)
- {
- mDNSPlatformMemFree(addrmap);
- }
+mDNSexport void UpdateRMAC(mDNS *const m, void *context)
+{
+ IPAddressMACMapping *addrmap = (IPAddressMACMapping *)context ;
+ m->CurrentRecord = m->ResourceRecords;
+
+ if (!addrmap)
+ {
+ LogMsg("UpdateRMAC: Address mapping is NULL");
+ return;
+ }
+
+ while (m->CurrentRecord)
+ {
+ AuthRecord *rr = m->CurrentRecord;
+ // If this is a non-sleep proxy keepalive record and the remote IP address matches, update the RData
+ if (!rr->WakeUp.HMAC.l[0] && mDNS_KeepaliveRecord(&rr->resrec))
+ {
+ mDNSAddr raddr;
+ getKeepaliveRaddr(m, rr, &raddr);
+ if (mDNSSameAddress(&raddr, &addrmap->ipaddr))
+ {
+ // Update the MAC address only if it is not a zero MAC address
+ mDNSEthAddr macAddr;
+ mDNSu8 *ptr = GetValueForMACAddr((mDNSu8 *)(addrmap->ethaddr), (mDNSu8 *) (addrmap->ethaddr + sizeof(addrmap->ethaddr)), &macAddr);
+ if (ptr != mDNSNULL && !mDNSEthAddressIsZero(macAddr))
+ {
+ UpdateKeepaliveRData(m, rr, mDNSNULL, mDNStrue, (char *)(addrmap->ethaddr));
+ }
+ }
+ }
+ m->CurrentRecord = rr->next;
+ }
+
+ if (addrmap)
+ mDNSPlatformMemFree(addrmap);
+
}
mDNSexport mStatus UpdateKeepaliveRData(mDNS *const m, AuthRecord *rr, NetworkInterfaceInfo *const intf, mDNSBool updateMac, char *ethAddr)
{
mDNSu16 newrdlength;
- mDNSAddr laddr, raddr;
- mDNSEthAddr eth;
- mDNSIPPort lport, rport;
- mDNSu32 timeout, seq, ack;
- mDNSu16 win;
+ mDNSAddr laddr = zeroAddr;
+ mDNSAddr raddr = zeroAddr;
+ mDNSEthAddr eth = zeroEthAddr;
+ mDNSIPPort lport = zeroIPPort;
+ mDNSIPPort rport = zeroIPPort;
+ mDNSu32 timeout = 0;
+ mDNSu32 seq = 0;
+ mDNSu32 ack = 0;
+ mDNSu16 win = 0;
UTF8str255 txt;
int rdsize;
RData *newrd;
@@ -5749,8 +5981,7 @@ mDNSexport mStatus UpdateKeepaliveRData(mDNS *const m, AuthRecord *rr, NetworkIn
// Note: If we fail to update the DNS NULL record with additional information in this function, it will be registered
// with the SPS like any other record. SPS will not send keepalives if it does not have additional information.
mDNS_ExtractKeepaliveInfo(rr, &timeout, &laddr, &raddr, &eth, &seq, &ack, &lport, &rport, &win);
- if (!timeout || mDNSAddressIsZero(&laddr) || mDNSAddressIsZero(&raddr) || mDNSIPPortIsZero(lport) ||
- mDNSIPPortIsZero(rport))
+ if (!timeout || mDNSAddressIsZero(&laddr) || mDNSAddressIsZero(&raddr) || mDNSIPPortIsZero(lport) || mDNSIPPortIsZero(rport))
{
LogMsg("UpdateKeepaliveRData: not a valid record %s for keepalive %#a:%d %#a:%d", ARDisplayString(m, rr), &laddr, lport.NotAnInteger, &raddr, rport.NotAnInteger);
return mStatus_UnknownErr;
@@ -5813,8 +6044,8 @@ mDNSexport mStatus UpdateKeepaliveRData(mDNS *const m, AuthRecord *rr, NetworkIn
// free that memory here before copying in the new data.
if ( rr->resrec.rdata != &rr->rdatastorage)
{
- mDNSPlatformMemFree(rr->resrec.rdata);
LogSPS("UpdateKeepaliveRData: Freed allocated memory for keep alive packet: %s ", ARDisplayString(m, rr));
+ mDNSPlatformMemFree(rr->resrec.rdata);
}
SetNewRData(&rr->resrec, newrd, newrdlength); // Update our rdata
@@ -5954,7 +6185,7 @@ mDNSlocal void SendSPSRegistrationForOwner(mDNS *const m, NetworkInterfaceInfo *
LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps,
mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps]));
- // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss
+ // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss
err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL, mDNSfalse);
if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err);
if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv4 && intf->NetWakeResolve[sps].ThisQInterval == -1)
@@ -6027,7 +6258,7 @@ mDNSlocal void SPSInitRecordsBeforeUpdate(mDNS *const m, mDNSOpaque64 updateIntI
{
AuthRecord *ar;
LogSPS("SPSInitRecordsBeforeUpdate: UpdateIntID 0x%x 0x%x", updateIntID.l[1], updateIntID.l[0]);
-
+
*WakeOnlyService = mDNSfalse;
// Before we store the A and AAAA records that we are going to register with the sleep proxy,
@@ -6144,7 +6375,7 @@ mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const Resour
if (!AddRecord) return; // Don't care about REMOVE events
if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs
- // if (answer->rrtype == kDNSType_AAAA && sps == 0) return; // To test failing to resolve sleep proxy's address
+ // if (answer->rrtype == kDNSType_AAAA && sps == 0) return; // To test failing to resolve sleep proxy's address
if (answer->rrtype == kDNSType_SRV)
{
@@ -6230,14 +6461,8 @@ mDNSlocal void SendGoodbyesForWakeOnlyService(mDNS *const m, mDNSBool *WakeOnlyS
{
return SendGoodbyesForSelectServices(m, WakeOnlyService, WAKE_ONLY_SERVICE);
}
-#endif // APPLE_OSx_mDNSResponder
+#endif // APPLE_OSX_mDNSResponder
-#ifdef APPLE_OSX_mDNSResponder
-mDNSlocal void SendGoodbyesForACOnlyServices(mDNS *const m, mDNSBool *acOnlyService)
-{
- return SendGoodbyesForSelectServices(m, acOnlyService, AC_ONLY_SERVICE);
-}
-#endif
mDNSlocal void SendSleepGoodbyes(mDNS *const m, mDNSBool AllInterfaces, mDNSBool unicast)
{
@@ -6334,11 +6559,10 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m)
{
mDNSBool SendGoodbyes = mDNStrue;
mDNSBool WakeOnlyService = mDNSfalse;
- mDNSBool ACOnlyService = mDNSfalse;
mDNSBool invokeKACallback = mDNStrue;
const CacheRecord *sps[3] = { mDNSNULL };
mDNSOpaque64 updateIntID = zeroOpaque64;
- mDNSInterfaceID registeredIntfIDS[128];
+ mDNSInterfaceID registeredIntfIDS[128] = { 0 };
mDNSu32 registeredCount = 0;
int skippedRegistrations = 0;
@@ -6351,7 +6575,7 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m)
NetworkInterfaceInfo *intf;
// Clear out the SCDynamic entry that stores the external SPS information
- mDNSPlatformClearSPSMACAddr();
+ mDNSPlatformClearSPSData();
for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
{
@@ -6395,10 +6619,10 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m)
if (ActivateLocalProxy(m, intf, &keepaliveOnly) == mStatus_NoError)
{
SendGoodbyesForWakeOnlyService(m, &WakeOnlyService);
- if (keepaliveOnly)
- SendGoodbyesForACOnlyServices(m, &ACOnlyService);
- SendGoodbyes = mDNSfalse;
- invokeKACallback = mDNSfalse;
+
+ // Send goodbyes for all advertised services if the only record offloaded was the keepalive record.
+ SendGoodbyes = (keepaliveOnly) ? mDNStrue: mDNSfalse;
+ invokeKACallback = mDNSfalse;
LogSPS("BeginSleepProcessing: %-6s using local proxy", intf->ifname);
// This will leave m->SleepState set to SleepState_Transferring,
// which is okay because with no outstanding resolves, or updates in flight,
@@ -6482,7 +6706,7 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m)
//
// - If there are no sleep proxy servers, then send goodbyes on all interfaces
// for both multicast and unicast.
- //
+ //
// - If we skipped registrations on some interfaces, then we have already marked
// them appropriately above. We don't need to send goodbyes for unicast as
// we have registered with at least one sleep proxy.
@@ -6502,10 +6726,10 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m)
LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server on all interfaces");
SendSleepGoodbyes(m, mDNSfalse, mDNSfalse);
}
- else if (WakeOnlyService || ACOnlyService)
+ else if (WakeOnlyService)
{
// If we saw WakeOnly service above, send the goodbyes now.
- LogSPS("BeginSleepProcessing: Sending goodbyes for %s", WakeOnlyService? "WakeOnlyService" : "AC Only Service");
+ LogSPS("BeginSleepProcessing: Sending goodbyes for WakeOnlyService");
SendResponses(m);
}
}
@@ -6531,7 +6755,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
#ifndef SPC_DISABLED
if (oldstate == 1) mDNS_DeregisterService(m, &m->SPSRecords);
#else
- (void)oldstate;
+ (void)oldstate;
#endif
mDNS_ReclaimLockAfterCallback();
}
@@ -6579,7 +6803,11 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
{
m->SleepState = SleepState_Awake;
m->SleepSeqNum++;
- m->DelaySleep = 0;
+ // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake)
+ // then we enforce a minimum delay of five seconds before we begin sleep processing.
+ // This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc.,
+ // before we make our determination of whether there's a Sleep Proxy out there we should register with.
+ m->DelaySleep = NonZeroTime(m->timenow + kDarkWakeDelaySleep);
}
if (m->SPSState == 3)
@@ -6588,7 +6816,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
mDNSCoreBeSleepProxyServer_internal(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower, m->SPSFeatureFlags);
}
m->mDNSStats.Wakes++;
-
+ m->DelayConflictProcessing = MAX_CONFLICT_PROCESSING_DELAYS;
// ... and the same for NextSPSAttempt
for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1;
@@ -6629,7 +6857,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
mDNSu32 uTTL = RRUnadjustedTTL(cr->resrec.rroriginalttl);
const mDNSs32 remain = uTTL - (m->timenow - cr->TimeRcvd) / mDNSPlatformOneSecond;
- // -if we have slept longer than the remaining TTL, purge and start fresh.
+ // -if we have slept longer than the remaining TTL, purge and start fresh.
// -if we have been sleeping for a long time, we could reduce TimeRcvd below by
// a sufficiently big value which could cause the value to go into the future
// because of the signed comparison of time. For this to happen, we should have been
@@ -7113,7 +7341,7 @@ mDNSlocal void DeregisterProxyRecord(mDNS *const m, AuthRecord *const rr)
mDNSlocal void ClearKeepaliveProxyRecords(mDNS *const m, const OwnerOptData *const owner, AuthRecord *const thelist, const mDNSInterfaceID InterfaceID)
{
if (m->CurrentRecord)
- LogMsg("ClearIdenticalProxyRecords ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+ LogMsg("ClearKeepaliveProxyRecords ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
m->CurrentRecord = thelist;
// Normally, the RDATA of the keepalive record will be different each time and hence we always
@@ -7247,9 +7475,9 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
}
- //
+ //
// Look in Authority Section for NSEC3 record
- //
+ //
mDNSParseNSEC3Records(m, query, end, InterfaceID, &McastNSEC3Records);
@@ -7583,7 +7811,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
{
SendLegacyResponse = mDNStrue;
}
-
if (SendMulticastResponse || SendUnicastResponse)
{
@@ -7690,15 +7917,17 @@ exit:
// For non-truncated queries, we can definitively say that we should expect
// to be seeing a response for any records still left in the ExpectedAnswers list
if (!(query->h.flags.b[0] & kDNSFlag0_TC))
- if (cr->UnansweredQueries == 0 || m->timenow - cr->LastUnansweredTime >= mDNSPlatformOneSecond)
+ if (cr->UnansweredQueries == 0 || m->timenow - cr->LastUnansweredTime >= mDNSPlatformOneSecond * 3/4)
{
cr->UnansweredQueries++;
cr->LastUnansweredTime = m->timenow;
-#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
if (cr->UnansweredQueries > 1)
- debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
+ #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));
-#endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING
+ #else
+ debugf("ProcessQuery: UnansweredQueries %lu %s", cr->UnansweredQueries, CRDisplayString(m, cr));
+ #endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING
SetNextCacheCheckTimeForRecord(m, cr);
}
@@ -7706,12 +7935,16 @@ exit:
// then mark it to expire in five seconds if we don't get a response by then.
if (cr->UnansweredQueries >= MaxUnansweredQueries)
{
-#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
// Only show debugging message if this record was not about to expire anyway
- if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond)
- debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
+ 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));
-#endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING
+ #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
+
m->mDNSStats.PoofCacheDeletions++;
mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
}
@@ -7777,15 +8010,16 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg,
mDNSBool QueryWasLocalUnicast = srcaddr && dstaddr &&
!mDNSAddrIsDNSMulticast(dstaddr) && mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
- if (!InterfaceID && dstaddr && mDNSAddrIsDNSMulticast(dstaddr))
+ if (!dstaddr || (!InterfaceID && mDNSAddrIsDNSMulticast(dstaddr)))
{
+ const char *const reason = !dstaddr ? "Received over TCP connection" : "Multicast, but no InterfaceID";
LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
- "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes (Multicast, but no InterfaceID)",
+ "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes (%s)",
srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
- msg->h.numAdditionals, msg->h.numAdditionals == 1 ? " " : "s", end - msg->data);
+ msg->h.numAdditionals, msg->h.numAdditionals == 1 ? " " : "s", end - msg->data, reason);
return;
}
@@ -7875,9 +8109,9 @@ mDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m,
}
if (mDNSSameIPPort(srcp, port)) return(q);
- // if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue);
- // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
- // if (TrustedSource(m, srcaddr)) return(mDNStrue);
+ // if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue);
+ // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
+ // if (TrustedSource(m, srcaddr)) return(mDNStrue);
LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s",
q->qname.c, DNSTypeName(q->qtype), &q->Target, mDNSVal16(srcp), srcaddr, mDNSVal16(port), CRDisplayString(m, rr));
return(mDNSNULL);
@@ -7915,7 +8149,7 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C
if (!m->rec.r.resrec.InterfaceID) debugf("CreateNewCacheEntry %s", CRDisplayString(m, &m->rec.r));
//if (RDLength > InlineCacheRDSize)
- // LogInfo("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r));
+ // LogInfo("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r));
if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec); // If we don't have a CacheGroup for this name, make one now
if (cg) rr = GetCacheRecord(m, cg, RDLength); // Make a cache record, being careful not to recycle cg
@@ -8254,7 +8488,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
// the application
if (qptr->ProxyQuestion)
qptr->responseFlags = response->h.flags;
- GenerateNegativeResponse(m, QC_forceresponse);
+ GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse);
m->CurrentQuestion = mDNSNULL;
}
else
@@ -8438,7 +8672,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
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
+ // 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);
}
}
@@ -8614,7 +8848,6 @@ mDNSlocal CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage
}
else
{
-
// If the packet TTL is zero, that means we're deleting this record.
// To give other hosts on the network a chance to protest, we push the deletion
// out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
@@ -8685,7 +8918,7 @@ mDNSlocal void mDNSCoreResetRecord(mDNS *const m)
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
if (m->rec.r.resrec.AnonInfo)
{
- FreeAnonInfo(m->rec.r.resrec.AnonInfo);
+ FreeAnonInfo(m->rec.r.resrec.AnonInfo);
m->rec.r.resrec.AnonInfo = mDNSNULL;
}
}
@@ -8722,6 +8955,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
mDNSBool rrsigsCreated = mDNSfalse;
mDNSBool DNSSECQuestion = mDNSfalse;
NetworkInterfaceInfo *llintf = FirstIPv4LLInterfaceForID(m, InterfaceID);
+ mDNSBool recordAcceptedInResponse = mDNSfalse; // Set if a record is accepted from a unicast mDNS response that answers an existing question.
// All records in a DNS response packet are treated as equally valid statements of truth. If we want
// to guard against spoof responses, then the only credible protection against that is cryptographic
@@ -8832,14 +9066,14 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// and hence retransmit without the EDNS0/DOK option.
if (DNSSECOptionalQuestion(qptr) && qptr->qDNSServer && !qptr->qDNSServer->DNSSECAware)
{
- LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to DNSSEC Query %##s (%s), clear DO flag",
+ LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to DNSSEC Query %##s (%s), clear DO flag",
qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
- qptr->qDNSServer->req_DO = mDNSfalse;
+ qptr->qDNSServer->req_DO = mDNSfalse;
}
// For Unicast DNS Queries, penalize the DNSServer
else
{
- LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to query %##s (%s)",
+ LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to query %##s (%s)",
qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
PenalizeDNSServer(m, qptr, response->h.flags);
}
@@ -8874,7 +9108,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
{
// All responses sent via LL multicast are acceptable for caching
// All responses received over our outbound TCP connections are acceptable for caching
- mDNSBool AcceptableResponse = ResponseMCast || !dstaddr || LLQType;
+ // We accept all records in a unicast response to a multicast query once we find one that
+ // answers an active question.
+ mDNSBool AcceptableResponse = ResponseMCast || !dstaddr || LLQType || recordAcceptedInResponse;
// (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer
// to any specific question -- any code reading records from the cache needs to make that determination for itself.)
@@ -8961,38 +9197,42 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// Even though it is AcceptableResponse, we still need a DNSServer pointer for the resource records that
// we create.
- DNSQuestion *q = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r, !dstaddr);
-
- // Initialize the DNS server on the resource record which will now filter what questions we answer with
- // this record.
- //
- // We could potentially lookup the DNS server based on the source address, but that may not work always
- // and that's why ExpectingUnicastResponseForRecord does not try to verify whether the response came
- // from the DNS server that queried. We follow the same logic here. If we can find a matching quetion based
- // on the "id" and "source port", then this response answers the question and assume the response
- // came from the same DNS server that we sent the query to.
-
- if (q != mDNSNULL)
- {
- AcceptableResponse = mDNStrue;
- if (!InterfaceID)
- {
- debugf("mDNSCoreReceiveResponse: InterfaceID %p %##s (%s)", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
- m->rec.r.resrec.rDNSServer = uDNSServer = q->qDNSServer;
- }
- else
- LogInfo("mDNSCoreReceiveResponse: InterfaceID %p %##s (%s)", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
- }
- else
- {
- // If we can't find a matching question, we need to see whether we have seen records earlier that matched
- // the question. The code below does that. So, make this record unacceptable for now
- if (!InterfaceID)
- {
- debugf("mDNSCoreReceiveResponse: Can't find question for record name %##s", m->rec.r.resrec.name->c);
- AcceptableResponse = mDNSfalse;
- }
- }
+ DNSQuestion *q = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r, !dstaddr);
+
+ // Initialize the DNS server on the resource record which will now filter what questions we answer with
+ // this record.
+ //
+ // We could potentially lookup the DNS server based on the source address, but that may not work always
+ // and that's why ExpectingUnicastResponseForRecord does not try to verify whether the response came
+ // from the DNS server that queried. We follow the same logic here. If we can find a matching quetion based
+ // on the "id" and "source port", then this response answers the question and assume the response
+ // came from the same DNS server that we sent the query to.
+
+ if (q != mDNSNULL)
+ {
+ AcceptableResponse = mDNStrue;
+ if (!InterfaceID)
+ {
+ debugf("mDNSCoreReceiveResponse: InterfaceID %p %##s (%s)", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
+ m->rec.r.resrec.rDNSServer = uDNSServer = q->qDNSServer;
+ }
+ else
+ {
+ // Accept all remaining records in this unicast response to an mDNS query.
+ recordAcceptedInResponse = mDNStrue;
+ LogInfo("mDNSCoreReceiveResponse: Accepting response for query: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ }
+ }
+ else
+ {
+ // If we can't find a matching question, we need to see whether we have seen records earlier that matched
+ // the question. The code below does that. So, make this record unacceptable for now
+ if (!InterfaceID)
+ {
+ debugf("mDNSCoreReceiveResponse: Can't find question for record name %##s", m->rec.r.resrec.name->c);
+ AcceptableResponse = mDNSfalse;
+ }
+ }
}
}
else if (llintf && llintf->IgnoreIPv4LL && m->rec.r.resrec.rrtype == kDNSType_A)
@@ -9016,7 +9256,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// This can cause some badly written applications to freeze for a long time if they
// attempt to connect to an IPv4 link-local destination address and then wait for
// that connection attempt to time out before trying other candidate addresses.
-
+
// To mask this client bug, we suppress acceptance of IPv4 link-local address
// records on interfaces where we know the OS will be unwilling even to attempt
// communication with those IPv4 link-local destination addresses.
@@ -9103,13 +9343,36 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// If we're probing for this record, we just failed
else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
{
+ // At this point in the code, we're probing for uniqueness.
+ // We've sent at least one probe (rr->ProbeCount < DefaultProbeCountForTypeUnique)
+ // but we haven't completed probing yet (rr->resrec.RecordType == kDNSRecordTypeUnique).
// Before we call deregister, check if this is a packet we registered with the sleep proxy.
if (!mDNSCoreRegisteredProxyRecord(m, rr))
{
- LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will deregister %s", rr->ProbeCount, ARDisplayString(m, rr));
-
- m->mDNSStats.NameConflicts++;
- mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+ // This may be a conflict due to stale packets on the network. Delay probing by a second.
+ // If there are conflicts after 3 such attempts, then it is a true conflict.
+ if (m->DelayConflictProcessing)
+ {
+ m->DelayConflictProcessing--;
+ LogMsg("Possible spurious conflict for %s. Attempt %d at suppressing probes for one second",
+ ARDisplayString(m, rr), (MAX_CONFLICT_PROCESSING_DELAYS - m->DelayConflictProcessing));
+ rr->ProbeCount = DefaultProbeCountForTypeUnique + 1;
+ rr->AnnounceCount = InitialAnnounceCount;
+ m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
+ InitializeLastAPTime(m, rr);
+ RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate
+ }
+ else
+ {
+ LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will deregister %s", rr->ProbeCount, ARDisplayString(m, rr));
+ m->mDNSStats.NameConflicts++;
+#if APPLE_OSX_mDNSResponder
+ // See if this record was also registered with any D2D plugins.
+ D2D_stop_advertising_record(rr);
+#endif
+ mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+ }
+
}
}
// We assumed this record must be unique, but we were wrong. (e.g. There are two mDNSResponders on the
@@ -9121,6 +9384,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
{
LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m, rr));
m->mDNSStats.KnownUniqueNameConflicts++;
+#if APPLE_OSX_mDNSResponder
+ D2D_stop_advertising_record(rr);
+#endif
mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
}
else
@@ -9289,7 +9555,7 @@ exit:
continue;
}
}
-
+
// For Unicast (null InterfaceID) the resolver IDs should also match
if ((r1->resrec.InterfaceID == r2->resrec.InterfaceID) &&
(r1->resrec.InterfaceID || (id1 == id2)) &&
@@ -9313,7 +9579,7 @@ exit:
// to give us an aged TTL to correct for how long it has held the record,
// so our received TTLs are expected to vary in that case
- // We also suppress log message in the case of SRV records that are recieved
+ // We also suppress log message in the case of SRV records that are received
// with a TTL of 4500 that are already cached with a TTL of 120 seconds, since
// this behavior was observed for a number of discoveryd based AppleTV's in iOS 8
// GM builds.
@@ -9388,7 +9654,7 @@ exit:
// Note: We need to do this before we call CacheRecordDeferredAdd as this
// might start the verification process which needs these NSEC records
if (!AddNSECSForCacheRecord(m, NSECRecords, NSECCachePtr, rcode))
- {
+ {
LogInfo("mDNSCoreReceiveResponse: AddNSECSForCacheRecord failed to add NSEC for %s", CRDisplayString(m, NSECCachePtr));
FreeNSECRecords(m, NSECRecords);
}
@@ -9408,7 +9674,7 @@ exit:
{
LogInfo("mDNSCoreReceieveResponse: Updating NSEC records in %s", CRDisplayString(m, NSECCachePtr));
if (!AddNSECSForCacheRecord(m, NSECRecords, NSECCachePtr, rcode))
- {
+ {
LogInfo("mDNSCoreReceiveResponse: AddNSECSForCacheRecord failed to add NSEC for %s", CRDisplayString(m, NSECCachePtr));
FreeNSECRecords(m, NSECRecords);
}
@@ -9488,8 +9754,8 @@ mDNSlocal void SPSRecordCallback(mDNS *const m, AuthRecord *const ar, mStatus re
LogMsg("%-7s Conflicting mDNS -- waking %.6a %s", InterfaceNameForID(m, ar->resrec.InterfaceID), &ar->WakeUp.HMAC, ARDisplayString(m, ar));
if (ar->WakeUp.HMAC.l[0])
{
- SendWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.IMAC, &ar->WakeUp.password); // Send one wakeup magic packet
- ScheduleWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.HMAC); // Schedule all other records with the same owner to be woken
+ SendWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.IMAC, &ar->WakeUp.password, mDNSfalse); // Send one wakeup magic packet
+ ScheduleWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.HMAC); // Schedule all other records with the same owner to be woken
}
mDNS_Unlock(m);
}
@@ -9519,7 +9785,7 @@ mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *et
}
else if (*ptr == ':')
{
- if (colons >=5 || val > 255)
+ if (colons >=5)
{
LogMsg("GetValueForMACAddr: Address malformed colons %d val %d", colons, val);
return mDNSNULL;
@@ -9704,32 +9970,33 @@ mDNSlocal mDNSu8 *GetValueForKeepalive(mDNSu8 *ptr, mDNSu8 *limit, mDNSu32 *valu
mDNSexport mDNSBool mDNSValidKeepAliveRecord(AuthRecord *rr)
{
- mDNSAddr laddr, raddr;
- mDNSEthAddr eth;
- mDNSIPPort lport, rport;
- mDNSu32 timeout, seq, ack;
- mDNSu16 win;
+ mDNSAddr laddr, raddr;
+ mDNSEthAddr eth;
+ mDNSIPPort lport, rport;
+ mDNSu32 timeout, seq, ack;
+ mDNSu16 win;
- if (!mDNS_KeepaliveRecord(&rr->resrec))
- {
- return mDNSfalse;
- }
+ if (!mDNS_KeepaliveRecord(&rr->resrec))
+ {
+ return mDNSfalse;
+ }
- timeout = seq = ack = 0;
- win = 0;
- laddr = raddr = zeroAddr;
- lport = rport = zeroIPPort;
+ timeout = seq = ack = 0;
+ win = 0;
+ laddr = raddr = zeroAddr;
+ lport = rport = zeroIPPort;
+ eth = zeroEthAddr;
- mDNS_ExtractKeepaliveInfo(rr, &timeout, &laddr, &raddr, &eth, &seq, &ack, &lport, &rport, &win);
+ mDNS_ExtractKeepaliveInfo(rr, &timeout, &laddr, &raddr, &eth, &seq, &ack, &lport, &rport, &win);
- if (mDNSAddressIsZero(&laddr) || mDNSIPPortIsZero(lport) ||
- mDNSAddressIsZero(&raddr) || mDNSIPPortIsZero(rport) ||
- mDNSEthAddressIsZero(eth))
- {
- return mDNSfalse;
- }
+ if (mDNSAddressIsZero(&laddr) || mDNSIPPortIsZero(lport) ||
+ mDNSAddressIsZero(&raddr) || mDNSIPPortIsZero(rport) ||
+ mDNSEthAddressIsZero(eth))
+ {
+ return mDNSfalse;
+ }
- return mDNStrue;
+ return mDNStrue;
}
@@ -9760,7 +10027,7 @@ mDNSlocal void mDNS_ExtractKeepaliveInfo(AuthRecord *ar, mDNSu32 *timeout, mDNSA
raddr->type = mDNSAddrType_IPv4;
ptr = GetValueForIPv4Addr(ptr, limit, &raddr->ip.v4);
}
- if (param == 'H')
+ else if (param == 'H')
{
laddr->type = mDNSAddrType_IPv6;
ptr = GetValueForIPv6Addr(ptr, limit, &laddr->ip.v6);
@@ -10106,6 +10373,35 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
mDNS_SendKeepalives(m);
}
+mDNSlocal mDNSu32 mDNSGenerateOwnerOptForInterface(mDNS *const m, const mDNSInterfaceID InterfaceID, DNSMessage *msg)
+{
+ mDNSu8 *ptr = msg->data;
+ mDNSu8 *end = mDNSNULL;
+ mDNSu32 length = 0;
+ AuthRecord opt;
+
+ 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);
+ SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]);
+
+ LogSPS("Generated OPT record : %s", ARDisplayString(m, &opt));
+ end = PutResourceRecord(msg, ptr, &msg->h.numAdditionals, &opt.resrec);
+ if (end != mDNSNULL)
+ {
+ // Put all the integer values in IETF byte-order (MSB first, LSB second)
+ SwapDNSHeaderBytes(msg);
+ length = (end - msg->data);
+ }
+ else
+ LogSPS("mDNSGenerateOwnerOptForInterface: Failed to generate owner OPT record");
+
+ return length;
+}
+
mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end, const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID)
{
if (InterfaceID)
@@ -10166,6 +10462,18 @@ mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg
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)
+ {
+ length += sizeof(DNSMessageHeader);
+ mDNSPlatformStoreOwnerOptRecord(ifname, &optMsg, length);
+ }
}
// If we were waiting to go to sleep, then this SPS registration or wide-area record deletion
// may have been the thing we were waiting for, so schedule another check to see if we can sleep now.
@@ -10309,17 +10617,21 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co
else if (QR_OP == UpdR) mDNSCoreReceiveUpdateR (m, msg, end, srcaddr, InterfaceID);
else
{
- LogMsg("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), end - (mDNSu8 *)pkt, InterfaceID);
if (mDNS_LoggingEnabled)
{
- int i = 0;
- while (i<end - (mDNSu8 *)pkt)
- {
- char buffer[128];
- char *p = buffer + mDNS_snprintf(buffer, sizeof(buffer), "%04X", i);
- do if (i<end - (mDNSu8 *)pkt) p += mDNS_snprintf(p, sizeof(buffer), " %02X", ((mDNSu8 *)pkt)[i]);while (++i & 15);
- LogInfo("%s", buffer);
+ static int msgCount = 0;
+ if (msgCount < 1000) {
+ msgCount++;
+ int i = 0;
+ 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), end - (mDNSu8 *)pkt, InterfaceID);
+ while (i<end - (mDNSu8 *)pkt)
+ {
+ char buffer[128];
+ char *p = buffer + mDNS_snprintf(buffer, sizeof(buffer), "%04X", i);
+ do if (i<end - (mDNSu8 *)pkt) p += mDNS_snprintf(p, sizeof(buffer), " %02X", ((mDNSu8 *)pkt)[i]);while (++i & 15);
+ LogInfo("%s", buffer);
+ }
}
}
}
@@ -10435,15 +10747,11 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
q->triedAllServersOnce = question->triedAllServersOnce;
q->TargetQID = question->TargetQID;
- if (q->LocalSocket)
- {
- mDNSPlatformUDPClose(q->LocalSocket);
- }
-
q->LocalSocket = question->LocalSocket;
+ // No need to close old q->LocalSocket first -- duplicate questions can't have their own sockets
q->state = question->state;
- // q->tcp = question->tcp;
+ // q->tcp = question->tcp;
q->ReqLease = question->ReqLease;
q->expire = question->expire;
q->ntries = question->ntries;
@@ -10451,7 +10759,7 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
question->LocalSocket = mDNSNULL;
question->nta = mDNSNULL; // If we've got a GetZoneData in progress, transfer it to the newly active question
- // question->tcp = mDNSNULL;
+ // question->tcp = mDNSNULL;
if (q->LocalSocket)
debugf("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
@@ -10657,7 +10965,7 @@ mDNSlocal mDNSBool DNSServerMatch(DNSServer *d, mDNSInterfaceID InterfaceID, mDN
//
// 3) Scoped questions (non-zero ServiceID) should consider *only* scoped DNSServers (DNSServer
// with "scoped" set to kScopeServiceID) and their ServiceIDs should match.
- //
+ //
// The first condition in the "if" statement checks to see if both the question and the DNSServer are
// unscoped. The question is unscoped only if InterfaceID is zero and ServiceID is -1.
//
@@ -10715,7 +11023,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
// match the scoped entries by mistake.
//
// Note: DNS configuration change will help pick the new dns servers but currently it does not affect the timeout
-
+
// Skip DNSServers that are InterfaceID Scoped but have no valid interfaceid set OR DNSServers that are ServiceID Scoped but have no valid serviceid set
if ((curr->scoped == kScopeInterfaceID && curr->interface == mDNSInterface_Any) || (curr->scoped == kScopeServiceID && curr->serviceID <= 0))
{
@@ -10724,7 +11032,8 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
}
currcount = CountLabels(&curr->domain);
- if ((!DEQuery || !curr->cellIntf) && DNSServerMatch(curr, question->InterfaceID, question->ServiceID))
+ if ((!curr->cellIntf || (!DEQuery && !(question->flags & kDNSServiceFlagsDenyCellular))) &&
+ DNSServerMatch(curr, question->InterfaceID, question->ServiceID))
{
bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen);
@@ -10963,7 +11272,7 @@ mDNSlocal mDNSBool ShouldSuppressUnicastQuery(mDNS *const m, DNSQuestion *q, DNS
LogInfo("ShouldSuppressUnicastQuery: Query suppressed for %##s, qtype %s, as the DNS server is NULL", q->qname.c, DNSTypeName(q->qtype));
return mDNStrue;
}
-
+
// Check if the DNS Configuration allows A/AAAA queries to be sent
if ((q->qtype == kDNSType_A) && (d->req_A))
{
@@ -11037,6 +11346,12 @@ mDNSlocal mDNSBool ShouldSuppressDotLocalQuery(mDNS *const m, DNSQuestion *q)
mDNSlocal mDNSBool ShouldSuppressQuery(mDNS *const m, DNSQuestion *q)
{
+ if (q->InterfaceID == mDNSInterface_LocalOnly)
+ {
+ LogInfo("ShouldSuppressQuery: LocalOnly query not suppressed for %##s, qtype %s", q->qname.c, DNSTypeName(q->qtype));
+ return mDNSfalse;
+ }
+
if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA)
{
LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, not A/AAAA type", q->qname.c, DNSTypeName(q->qtype));
@@ -11310,7 +11625,7 @@ mDNSlocal void RestartUnicastQuestions(mDNS *const m)
{
if (mDNSOpaque16IsZero(q->TargetQID))
LogMsg("RestartUnicastQuestions: ERROR!! Restart set for multicast question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-
+
q->Restart = 0;
SuppressStatusChanged(m, q, &restart);
}
@@ -11339,7 +11654,7 @@ mDNSlocal mStatus ValidateParameters(mDNS *const m, DNSQuestion *const question)
}
// If no question->Target specified, clear TargetPort
- if (!question->Target.type)
+ if (!question->Target.type)
question->TargetPort = zeroIPPort;
if (!ValidateDomainName(&question->qname))
@@ -11349,14 +11664,14 @@ mDNSlocal mStatus ValidateParameters(mDNS *const m, DNSQuestion *const question)
}
// If this question is referencing a specific interface, verify it exists
- if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_Unicast && question->InterfaceID != mDNSInterface_P2P)
+ if (question->InterfaceID && !LocalOnlyOrP2PInterface(question->InterfaceID) && question->InterfaceID != mDNSInterface_Unicast)
{
NetworkInterfaceInfo *intf = FirstInterfaceForID(m, question->InterfaceID);
if (!intf)
LogInfo("ValidateParameters: Note: InterfaceID %d for question %##s (%s) not currently found in active interface list",
(uint32_t)question->InterfaceID, question->qname.c, DNSTypeName(question->qtype));
}
-
+
return(mStatus_NoError);
}
@@ -11367,19 +11682,19 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question)
// First reset all DNS Configuration
question->qDNSServer = mDNSNULL;
question->validDNSServers = zeroOpaque64;
- question->triedAllServersOnce = 0;
- question->noServerResponse = 0;
+ question->triedAllServersOnce = 0;
+ question->noServerResponse = 0;
question->StopTime = 0;
#if TARGET_OS_EMBEDDED
mDNSPlatformMemZero(&question->metrics, sizeof(question->metrics));
#endif
// Need not initialize the DNS Configuration for Local Only OR P2P Questions
- if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P)
+ if (LocalOnlyOrP2PInterface(question->InterfaceID))
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
@@ -11402,7 +11717,7 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question)
mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
}
else
- {
+ {
if (question->TimeoutQuestion)
question->StopTime = NonZeroTime(m->timenow + GetTimeoutForMcastQuestion(m, question) * mDNSPlatformOneSecond);
}
@@ -11411,7 +11726,7 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question)
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);
+ SetNextQueryTime(m,question);
}
// InitCommonState() is called by mDNS_StartQuery_internal() to initialize the common(uDNS/mDNS) internal
@@ -11420,7 +11735,7 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question)
{
mDNSBool purge;
int i;
- mDNSBool isCellBlocked = mDNSfalse;
+ mDNSBool isBlocked = mDNSfalse;
// Note: In the case where we already have the answer to this question in our cache, that may be all the client
// wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
@@ -11468,15 +11783,21 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question)
question->LOAddressAnswers = 0;
question->FlappingInterface1 = mDNSNULL;
question->FlappingInterface2 = mDNSNULL;
-
- // if kDNSServiceFlagsServiceIndex flag is SET by the client, then do NOT call mDNSPlatformGetDNSRoutePolicy()
- // since we would already have the question->ServiceID in that case.
- if (!(question->flags & kDNSServiceFlagsServiceIndex))
- mDNSPlatformGetDNSRoutePolicy(m, question, &isCellBlocked);
- else
- LogInfo("InitCommonState: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] is already set by client", question->qname.c,
+
+ // if kDNSServiceFlagsServiceIndex flag is SET by the client, then do NOT call mDNSPlatformGetDNSRoutePolicy()
+ // since we would already have the question->ServiceID in that case.
+ if (!(question->flags & kDNSServiceFlagsServiceIndex))
+ {
+#if APPLE_OSX_mDNSResponder
+ mDNSPlatformGetDNSRoutePolicy(m, question, &isBlocked);
+#else
+ question->ServiceID = -1;
+#endif
+ }
+ else
+ LogInfo("InitCommonState: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] is already set by client", question->qname.c,
DNSTypeName(question->qtype), question->pid, question->euid, question->ServiceID);
-
+
InitDNSConfig(m, question);
question->AuthInfo = GetAuthInfoForQuestion(m, question);
@@ -11486,7 +11807,7 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question)
// If ServiceID is 0 or the policy disallows making DNS requests,
// set DisallowPID
- question->DisallowPID = (question->ServiceID == 0 || (isCellBlocked && question->qDNSServer && question->qDNSServer->cellIntf));
+ question->DisallowPID = (question->ServiceID == 0 || isBlocked);
if (question->DisallowPID)
LogInfo("InitCommonState: Query suppressed for %##s (%s), PID %d/ServiceID %d not allowed", question->qname.c,
DNSTypeName(question->qtype), question->pid, question->ServiceID);
@@ -11494,47 +11815,27 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question)
question->NextInDQList = mDNSNULL;
question->SendQNow = mDNSNULL;
question->SendOnAll = mDNSfalse;
-
-#if mDNS_REQUEST_UNICAST_RESPONSE
- question->RequestUnicast = SET_QU_IN_FIRST_FOUR_QUERIES;
-#else // mDNS_REQUEST_UNICAST_RESPONSE
- question->RequestUnicast = SET_QU_IN_FIRST_QUERY;
-#endif // mDNS_REQUEST_UNICAST_RESPONSE
+ question->RequestUnicast = kDefaultRequestUnicastCount;
#if APPLE_OSX_mDNSResponder
- // Request unicast response for first 4 queries to increase
- // reliability in an environment with high multicast packet loss.
- // Must set to one more than the number of unicast queries you want, since SendQueries()
- // decrements it before calling BuildQuestion() which acts on it.
- if (question->flags & kDNSServiceFlagsUnicastResponse)
+ // Set the QU bit in the first query for the following options.
+ if ((question->flags & kDNSServiceFlagsUnicastResponse) || (question->flags & kDNSServiceFlagsThresholdFinder))
{
- question->RequestUnicast = SET_QU_IN_FIRST_FOUR_QUERIES;
+ question->RequestUnicast = SET_QU_IN_FIRST_QUERY;
LogInfo("InitCommonState: setting RequestUnicast = %d for %##s (%s)", question->RequestUnicast, question->qname.c,
DNSTypeName(question->qtype));
- }
- else if (question->flags & kDNSServiceFlagsThresholdFinder)
- {
- // always send one request with QU bit set when kDNSServiceFlagsThresholdFinder is set
-#if mDNS_REQUEST_UNICAST_RESPONSE
- question->RequestUnicast = SET_QU_IN_FIRST_FOUR_QUERIES;
-#else // mDNS_REQUEST_UNICAST_RESPONSE
- question->RequestUnicast = SET_QU_IN_FIRST_QUERY;
-#endif // mDNS_REQUEST_UNICAST_RESPONSE
-
- LogInfo("InitCommonState: kDNSServiceFlagsThresholdFinder set, setting RequestUnicast = %d for %##s (%s)",
- question->RequestUnicast, question->qname.c, DNSTypeName(question->qtype));
}
#endif // APPLE_OSX_mDNSResponder
question->LastQTxTime = m->timenow;
- question->CNAMEReferrals = 0;
+ question->CNAMEReferrals = 0;
question->WakeOnResolveCount = 0;
if (question->WakeOnResolve)
- {
+ {
question->WakeOnResolveCount = InitialWakeOnResolveCount;
purge = mDNStrue;
- }
+ }
for (i=0; i<DupSuppressInfoSize; i++)
question->DupSuppress[i].InterfaceID = mDNSNULL;
@@ -11561,7 +11862,7 @@ mDNSlocal void InitWABState(DNSQuestion *const question)
// We won't need one for duplicate questions, or from questions answered immediately out of the cache.
// We also don't need one for LLQs because (when we're using NAT) we want them all to share a single
// NAT mapping for receiving inbound add/remove events.
- question->LocalSocket = mDNSNULL;
+ question->LocalSocket = mDNSNULL;
question->unansweredQueries = 0;
question->nta = mDNSNULL;
question->servAddr = zeroAddr;
@@ -11593,6 +11894,11 @@ mDNSlocal void InitLLQState(DNSQuestion *const question)
question->id = zeroOpaque64;
}
+mDNSlocal void InitDNSPNState(DNSQuestion *const question)
+{
+ question->dnsPushState = DNSPUSH_INIT;
+}
+
// InitDNSSECProxyState() is called by mDNS_StartQuery_internal() to initialize
// DNSSEC & DNS Proxy fields of the DNS Question.
mDNSlocal void InitDNSSECProxyState(mDNS *const m, DNSQuestion *const question)
@@ -11680,19 +11986,30 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
vStatus = ValidateParameters(m, question);
if (vStatus)
return(vStatus);
-
+
+#ifdef USE_LIBIDN
+ // If the TLD includes high-ascii bytes, assume it will need to be converted to Punycode.
+ // (In the future the root name servers may answer UTF-8 queries directly, but for now they do not.)
+ if (IsHighASCIILabel(LastLabel(&question->qname)))
+ {
+ domainname newname;
+ if (PerformNextPunycodeConversion(question, &newname))
+ AssignDomainName(&question->qname, &newname);
+ }
+#endif // USE_LIBIDN
+
question->TargetQID =
#ifndef UNICAST_DISABLED
(question->Target.type || Question_uDNS(question)) ? mDNS_NewMessageID(m) :
#endif // UNICAST_DISABLED
zeroID;
- debugf("mDNS_StartQuery_internal: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
-
+ debugf("mDNS_StartQuery_internal: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
+
// Note: It important that new questions are appended at the *end* of the list, not prepended at the start
q = &m->Questions;
- if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P)
+ if (LocalOnlyOrP2PInterface(question->InterfaceID))
q = &m->LocalOnlyQuestions;
- while (*q && *q != question)
+ while (*q && *q != question)
q=&(*q)->next;
if (*q)
@@ -11702,7 +12019,6 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
return(mStatus_AlreadyRegistered);
}
*q = question;
-
// Intialize the question. The only ordering constraint we have today is that
// InitDNSSECProxyState should be called after the DNS server is selected (in
@@ -11712,23 +12028,24 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
purge = InitCommonState(m, question);
InitWABState(question);
InitLLQState(question);
+ InitDNSPNState(question);
InitDNSSECProxyState(m, question);
// FindDuplicateQuestion should be called last after all the intialization
// as the duplicate logic could be potentially based on any field in the
// question.
question->DuplicateOf = FindDuplicateQuestion(m, question);
- if (question->DuplicateOf)
- question->AuthInfo = question->DuplicateOf->AuthInfo;
+ if (question->DuplicateOf)
+ question->AuthInfo = question->DuplicateOf->AuthInfo;
- if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P)
+ if (LocalOnlyOrP2PInterface(question->InterfaceID))
{
- if (!m->NewLocalOnlyQuestions)
+ if (!m->NewLocalOnlyQuestions)
m->NewLocalOnlyQuestions = question;
}
else
{
- if (!m->NewQuestions)
+ if (!m->NewQuestions)
m->NewQuestions = question;
// If the question's id is non-zero, then it's Wide Area
@@ -11743,13 +12060,22 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
}
else
{
-#if TARGET_OS_WATCH
- m->NumAllInterfaceQuestions++;
- LogInfo("mDNS_StartQuery_internal: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)",
- m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype));
- if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
- m->NetworkChanged = m->timenow;
-#endif
+#if BONJOUR_ON_DEMAND
+ m->NumAllInterfaceQuestions++;
+ LogInfo("mDNS_StartQuery_internal: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)",
+ m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype));
+ if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
+ {
+ m->NextBonjourDisableTime = 0;
+ if (m->BonjourEnabled == 0)
+ {
+ // Enable Bonjour immediately by scheduling network changed processing where
+ // we will join the multicast group on each active interface.
+ m->BonjourEnabled = 1;
+ m->NetworkChanged = m->timenow;
+ }
+ }
+#endif // BONJOUR_ON_DEMAND
if (purge)
{
LogInfo("mDNS_StartQuery_internal: Purging for %##s", question->qname.c);
@@ -11786,7 +12112,8 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
//LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P) qp = &m->LocalOnlyQuestions;
+ if (LocalOnlyOrP2PInterface(question->InterfaceID))
+ qp = &m->LocalOnlyQuestions;
while (*qp && *qp != question) qp=&(*qp)->next;
if (*qp) *qp = (*qp)->next;
else
@@ -11798,29 +12125,36 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
return(mStatus_BadReferenceErr);
}
-#if TARGET_OS_WATCH
- if (question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_P2P && mDNSOpaque16IsZero(question->TargetQID))
+#if BONJOUR_ON_DEMAND
+ if (!LocalOnlyOrP2PInterface(question->InterfaceID) && mDNSOpaque16IsZero(question->TargetQID))
{
- if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
- m->NetworkChanged = m->timenow;
- m->NumAllInterfaceQuestions--;
- LogInfo("mDNS_StopQuery_internal: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)",
- m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype));
+ if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
+ m->NextBonjourDisableTime = NonZeroTime(m->timenow + (BONJOUR_DISABLE_DELAY * mDNSPlatformOneSecond));
+ m->NumAllInterfaceQuestions--;
+ LogInfo("mDNS_StopQuery_internal: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)",
+ m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype));
}
-#endif
+#endif // BONJOUR_ON_DEMAND
#if TARGET_OS_EMBEDDED
- if (Question_uDNS(question) && !question->metrics.answered)
+ if (Question_uDNS(question) && !question->metrics.answered && (question->metrics.querySendCount > 0))
{
- uDNSMetrics * metrics;
const domainname * queryName;
- mDNSBool isForCellular;
+ mDNSBool isForCell;
+ mDNSu32 durationMs;
- metrics = &question->metrics;
- queryName = metrics->originalQName ? metrics->originalQName : &question->qname;
- isForCellular = (question->qDNSServer && question->qDNSServer->cellIntf);
+ queryName = question->metrics.originalQName ? question->metrics.originalQName : &question->qname;
+ isForCell = (question->qDNSServer && question->qDNSServer->cellIntf);
- MetricsUpdateUDNSStats(queryName, mDNSfalse, metrics->querySendCount, 0, isForCellular);
+ if (question->metrics.querySendCount > 0)
+ {
+ durationMs = ((m->timenow - question->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond;
+ }
+ else
+ {
+ durationMs = 0;
+ }
+ MetricsUpdateUDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, durationMs, isForCell);
}
#endif
// Take care to cut question from list *before* calling UpdateQuestionDuplicates
@@ -11835,16 +12169,31 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
if (rr->CRActiveQuestion == question)
{
DNSQuestion *q;
- // Checking for ActiveQuestion filters questions that are suppressed also
- // as suppressed questions are not active
- for (q = m->Questions; q; q=q->next) // Scan our list of questions
- if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
- break;
- if (q)
+ DNSQuestion *replacement = mDNSNULL;
+ // If we find an active question that is answered by this cached record, use it as the cache record's
+ // CRActiveQuestion replacement. If there are no such questions, but there's at least one unsuppressed inactive
+ // question that is answered by this cache record, then use an inactive one to not forgo generating RMV events
+ // via CacheRecordRmv() when the cache record expires.
+ for (q = m->Questions; q && (q != m->NewQuestions); q = q->next)
+ {
+ if (!q->DuplicateOf && !QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
+ {
+ if (q->ThisQInterval > 0)
+ {
+ replacement = q;
+ break;
+ }
+ else if (!replacement)
+ {
+ replacement = q;
+ }
+ }
+ }
+ if (replacement)
debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s, Original question CurrentAnswers %d, new question "
- "CurrentAnswers %d, SuppressQuery %d", q, CRDisplayString(m,rr), question->CurrentAnswers, q->CurrentAnswers, q->SuppressQuery);
- rr->CRActiveQuestion = q; // Question used to be active; new value may or may not be null
- if (!q) m->rrcache_active--; // If no longer active, decrement rrcache_active count
+ "CurrentAnswers %d, SuppressQuery %d", replacement, CRDisplayString(m,rr), question->CurrentAnswers, replacement->CurrentAnswers, replacement->SuppressQuery);
+ rr->CRActiveQuestion = replacement; // Question used to be active; new value may or may not be null
+ if (!replacement) m->rrcache_active--; // If no longer active, decrement rrcache_active count
}
}
@@ -11927,6 +12276,15 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
question->tcp = mDNSNULL;
}
}
+ else if (question->dnsPushState == DNSPUSH_ESTABLISHED)
+ {
+ if (question->tcp)
+ {
+ UnSubscribeToDNSPushNotificationServer(m, q);
+ question->tcp->question = mDNSNULL;
+ question->tcp = mDNSNULL;
+ }
+ }
#if APPLE_OSX_mDNSResponder
UpdateAutoTunnelDomainStatuses(m);
#endif
@@ -12043,10 +12401,8 @@ mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const qu
question->LongLived = mDNStrue;
question->ExpectUnique = mDNSfalse;
question->ForceMCast = ForceMCast;
- question->ReturnIntermed = mDNSfalse;
+ question->ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
question->SuppressUnusable = mDNSfalse;
- question->DenyOnCellInterface = mDNSfalse;
- question->DenyOnExpInterface = mDNSfalse;
question->SearchListIndex = 0;
question->AppendSearchDomains = 0;
question->RetryWithSearchDomains = mDNSfalse;
@@ -12087,295 +12443,6 @@ mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
return(status);
}
-mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m)
-{
- NetworkInterfaceInfo *intf;
- for (intf = m->HostInterfaces; intf; intf = intf->next)
- if (intf->ip.type == mDNSAddrType_IPv6) return(mDNStrue);
- return(mDNSfalse);
-}
-
-mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
-{
- ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
- mDNSBool PortChanged = !mDNSSameIPPort(query->info->port, answer->rdata->u.srv.port);
- if (!AddRecord) return;
- if (answer->rrtype != kDNSType_SRV) return;
-
- query->info->port = answer->rdata->u.srv.port;
-
- // If this is our first answer, then set the GotSRV flag and start the address query
- if (!query->GotSRV)
- {
- query->GotSRV = mDNStrue;
- query->qAv4.InterfaceID = answer->InterfaceID;
- AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
- query->qAv6.InterfaceID = answer->InterfaceID;
- AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
- mDNS_StartQuery(m, &query->qAv4);
- // Only do the AAAA query if this machine actually has IPv6 active
- if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
- }
- // If this is not our first answer, only re-issue the address query if the target host name has changed
- else if ((query->qAv4.InterfaceID != query->qSRV.InterfaceID && query->qAv4.InterfaceID != answer->InterfaceID) ||
- !SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target))
- {
- mDNS_StopQuery(m, &query->qAv4);
- if (query->qAv6.ThisQInterval >= 0) mDNS_StopQuery(m, &query->qAv6);
- if (SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target) && !PortChanged)
- {
- // If we get here, it means:
- // 1. This is not our first SRV answer
- // 2. The interface ID is different, but the target host and port are the same
- // This implies that we're seeing the exact same SRV record on more than one interface, so we should
- // make our address queries at least as broad as the original SRV query so that we catch all the answers.
- query->qAv4.InterfaceID = query->qSRV.InterfaceID; // Will be mDNSInterface_Any, or a specific interface
- query->qAv6.InterfaceID = query->qSRV.InterfaceID;
- }
- else
- {
- query->qAv4.InterfaceID = answer->InterfaceID;
- AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
- query->qAv6.InterfaceID = answer->InterfaceID;
- AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
- }
- debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query->qAv4.qname.c, DNSTypeName(query->qAv4.qtype));
- mDNS_StartQuery(m, &query->qAv4);
- // Only do the AAAA query if this machine actually has IPv6 active
- if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
- }
- else if (query->ServiceInfoQueryCallback && query->GotADD && query->GotTXT && PortChanged)
- {
- if (++query->Answers >= 100)
- debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u",
- query->Answers, query->qSRV.qname.c, answer->rdata->u.srv.target.c,
- mDNSVal16(answer->rdata->u.srv.port));
- query->ServiceInfoQueryCallback(m, query);
- }
- // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
- // callback function is allowed to do anything, including deleting this query and freeing its memory.
-}
-
-mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
-{
- ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
- if (!AddRecord) return;
- if (answer->rrtype != kDNSType_TXT) return;
- if (answer->rdlength > sizeof(query->info->TXTinfo)) return;
-
- query->GotTXT = mDNStrue;
- query->info->TXTlen = answer->rdlength;
- query->info->TXTinfo[0] = 0; // In case answer->rdlength is zero
- mDNSPlatformMemCopy(query->info->TXTinfo, answer->rdata->u.txt.c, answer->rdlength);
-
- verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD);
-
- // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
- // callback function is allowed to do anything, including deleting this query and freeing its memory.
- if (query->ServiceInfoQueryCallback && query->GotADD)
- {
- if (++query->Answers >= 100)
- debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...",
- query->Answers, query->qSRV.qname.c, answer->rdata->u.txt.c);
- query->ServiceInfoQueryCallback(m, query);
- }
-}
-
-mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
-{
- ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
- //LogInfo("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
- if (!AddRecord) return;
-
- if (answer->rrtype == kDNSType_A)
- {
- query->info->ip.type = mDNSAddrType_IPv4;
- query->info->ip.ip.v4 = answer->rdata->u.ipv4;
- }
- else if (answer->rrtype == kDNSType_AAAA)
- {
- query->info->ip.type = mDNSAddrType_IPv6;
- query->info->ip.ip.v6 = answer->rdata->u.ipv6;
- }
- else
- {
- debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer->name->c, answer->rrtype, DNSTypeName(answer->rrtype));
- return;
- }
-
- query->GotADD = mDNStrue;
- query->info->InterfaceID = answer->InterfaceID;
-
- verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query->info->ip.type, query->info->name.c, query->GotTXT);
-
- // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
- // callback function is allowed to do anything, including deleting this query and freeing its memory.
- if (query->ServiceInfoQueryCallback && query->GotTXT)
- {
- if (++query->Answers >= 100)
- debugf(answer->rrtype == kDNSType_A ?
- "**** WARNING **** have given %lu answers for %##s (A) %.4a" :
- "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a",
- query->Answers, query->qSRV.qname.c, &answer->rdata->u.data);
- query->ServiceInfoQueryCallback(m, query);
- }
-}
-
-// On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure
-// If the query is not interface-specific, then InterfaceID may be zero
-// Each time the Callback is invoked, the remainder of the fields will have been filled in
-// In addition, InterfaceID will be updated to give the interface identifier corresponding to that response
-mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
- ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context)
-{
- mStatus status;
- mDNS_Lock(m);
-
- query->qSRV.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
- query->qSRV.InterfaceID = info->InterfaceID;
- query->qSRV.flags = 0;
- query->qSRV.Target = zeroAddr;
- AssignDomainName(&query->qSRV.qname, &info->name);
- query->qSRV.qtype = kDNSType_SRV;
- query->qSRV.qclass = kDNSClass_IN;
- query->qSRV.LongLived = mDNSfalse;
- query->qSRV.ExpectUnique = mDNStrue;
- query->qSRV.ForceMCast = mDNSfalse;
- query->qSRV.ReturnIntermed = mDNSfalse;
- query->qSRV.SuppressUnusable = mDNSfalse;
- query->qSRV.DenyOnCellInterface = mDNSfalse;
- query->qSRV.DenyOnExpInterface = mDNSfalse;
- query->qSRV.SearchListIndex = 0;
- query->qSRV.AppendSearchDomains = 0;
- query->qSRV.RetryWithSearchDomains = mDNSfalse;
- query->qSRV.TimeoutQuestion = 0;
- query->qSRV.WakeOnResolve = 0;
- query->qSRV.UseBackgroundTrafficClass = mDNSfalse;
- query->qSRV.ValidationRequired = 0;
- query->qSRV.ValidatingResponse = 0;
- query->qSRV.ProxyQuestion = 0;
- query->qSRV.qnameOrig = mDNSNULL;
- query->qSRV.AnonInfo = mDNSNULL;
- query->qSRV.QuestionCallback = FoundServiceInfoSRV;
- query->qSRV.QuestionContext = query;
-
- query->qTXT.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
- query->qTXT.InterfaceID = info->InterfaceID;
- query->qTXT.flags = 0;
- query->qTXT.Target = zeroAddr;
- AssignDomainName(&query->qTXT.qname, &info->name);
- query->qTXT.qtype = kDNSType_TXT;
- query->qTXT.qclass = kDNSClass_IN;
- query->qTXT.LongLived = mDNSfalse;
- query->qTXT.ExpectUnique = mDNStrue;
- query->qTXT.ForceMCast = mDNSfalse;
- query->qTXT.ReturnIntermed = mDNSfalse;
- query->qTXT.SuppressUnusable = mDNSfalse;
- query->qTXT.DenyOnCellInterface = mDNSfalse;
- query->qTXT.DenyOnExpInterface = mDNSfalse;
- query->qTXT.SearchListIndex = 0;
- query->qTXT.AppendSearchDomains = 0;
- query->qTXT.RetryWithSearchDomains = mDNSfalse;
- query->qTXT.TimeoutQuestion = 0;
- query->qTXT.WakeOnResolve = 0;
- query->qTXT.UseBackgroundTrafficClass = mDNSfalse;
- query->qTXT.ValidationRequired = 0;
- query->qTXT.ValidatingResponse = 0;
- query->qTXT.ProxyQuestion = 0;
- query->qTXT.qnameOrig = mDNSNULL;
- query->qTXT.AnonInfo = mDNSNULL;
- query->qTXT.QuestionCallback = FoundServiceInfoTXT;
- query->qTXT.QuestionContext = query;
-
- query->qAv4.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
- query->qAv4.InterfaceID = info->InterfaceID;
- query->qAv4.flags = 0;
- query->qAv4.Target = zeroAddr;
- query->qAv4.qname.c[0] = 0;
- query->qAv4.qtype = kDNSType_A;
- query->qAv4.qclass = kDNSClass_IN;
- query->qAv4.LongLived = mDNSfalse;
- query->qAv4.ExpectUnique = mDNStrue;
- query->qAv4.ForceMCast = mDNSfalse;
- query->qAv4.ReturnIntermed = mDNSfalse;
- query->qAv4.SuppressUnusable = mDNSfalse;
- query->qAv4.DenyOnCellInterface = mDNSfalse;
- query->qAv4.DenyOnExpInterface = mDNSfalse;
- query->qAv4.SearchListIndex = 0;
- query->qAv4.AppendSearchDomains = 0;
- query->qAv4.RetryWithSearchDomains = mDNSfalse;
- query->qAv4.TimeoutQuestion = 0;
- query->qAv4.WakeOnResolve = 0;
- query->qAv4.UseBackgroundTrafficClass = mDNSfalse;
- query->qAv4.ValidationRequired = 0;
- query->qAv4.ValidatingResponse = 0;
- query->qAv4.ProxyQuestion = 0;
- query->qAv4.qnameOrig = mDNSNULL;
- query->qAv4.AnonInfo = mDNSNULL;
- query->qAv4.QuestionCallback = FoundServiceInfo;
- query->qAv4.QuestionContext = query;
-
- query->qAv6.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
- query->qAv6.InterfaceID = info->InterfaceID;
- query->qAv6.flags = 0;
- query->qAv6.Target = zeroAddr;
- query->qAv6.qname.c[0] = 0;
- query->qAv6.qtype = kDNSType_AAAA;
- query->qAv6.qclass = kDNSClass_IN;
- query->qAv6.LongLived = mDNSfalse;
- query->qAv6.ExpectUnique = mDNStrue;
- query->qAv6.ForceMCast = mDNSfalse;
- query->qAv6.ReturnIntermed = mDNSfalse;
- query->qAv6.SuppressUnusable = mDNSfalse;
- query->qAv6.DenyOnCellInterface = mDNSfalse;
- query->qAv6.DenyOnExpInterface = mDNSfalse;
- query->qAv6.SearchListIndex = 0;
- query->qAv6.AppendSearchDomains = 0;
- query->qAv6.RetryWithSearchDomains = mDNSfalse;
- query->qAv6.TimeoutQuestion = 0;
- query->qAv6.UseBackgroundTrafficClass = mDNSfalse;
- query->qAv6.ValidationRequired = 0;
- query->qAv6.ValidatingResponse = 0;
- query->qAv6.ProxyQuestion = 0;
- query->qAv6.qnameOrig = mDNSNULL;
- query->qAv6.AnonInfo = mDNSNULL;
- query->qAv6.QuestionCallback = FoundServiceInfo;
- query->qAv6.QuestionContext = query;
-
- query->GotSRV = mDNSfalse;
- query->GotTXT = mDNSfalse;
- query->GotADD = mDNSfalse;
- query->Answers = 0;
-
- query->info = info;
- query->ServiceInfoQueryCallback = Callback;
- query->ServiceInfoQueryContext = Context;
-
-// info->name = Must already be set up by client
-// info->interface = Must already be set up by client
- info->ip = zeroAddr;
- info->port = zeroIPPort;
- info->TXTlen = 0;
-
- // We use mDNS_StartQuery_internal here because we're already holding the lock
- status = mDNS_StartQuery_internal(m, &query->qSRV);
- if (status == mStatus_NoError) status = mDNS_StartQuery_internal(m, &query->qTXT);
- if (status != mStatus_NoError) mDNS_StopResolveService(m, query);
-
- mDNS_Unlock(m);
- return(status);
-}
-
-mDNSexport void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q)
-{
- mDNS_Lock(m);
- // We use mDNS_StopQuery_internal here because we're already holding the lock
- if (q->qSRV.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qSRV);
- if (q->qTXT.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qTXT);
- if (q->qAv4.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv4);
- if (q->qAv6.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv6);
- mDNS_Unlock(m);
-}
mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
@@ -12390,8 +12457,6 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m
question->ForceMCast = mDNSfalse;
question->ReturnIntermed = mDNSfalse;
question->SuppressUnusable = mDNSfalse;
- question->DenyOnCellInterface = mDNSfalse;
- question->DenyOnExpInterface = mDNSfalse;
question->SearchListIndex = 0;
question->AppendSearchDomains = 0;
question->RetryWithSearchDomains = mDNSfalse;
@@ -12404,7 +12469,7 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m
question->qnameOrig = mDNSNULL;
question->AnonInfo = mDNSNULL;
question->pid = mDNSPlatformGetPID();
- question->euid = 0;
+ question->euid = 0;
question->QuestionCallback = Callback;
question->QuestionContext = Context;
if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr);
@@ -12615,6 +12680,10 @@ mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
return;
}
+#if APPLE_OSX_mDNSResponder
+ D2D_stop_advertising_interface(set);
+#endif // APPLE_OSX_mDNSResponder
+
// Unregister these records.
// When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform
// support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
@@ -12623,11 +12692,6 @@ mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
if (set->RR_A .resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A, mDNS_Dereg_normal);
if (set->RR_PTR .resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR, mDNS_Dereg_normal);
if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal);
-
-#if APPLE_OSX_mDNSResponder
- D2D_stop_advertising_interface(set);
-#endif // APPLE_OSX_mDNSResponder
-
}
mDNSlocal void AdvertiseAllInterfaceRecords(mDNS *const m)
@@ -12656,6 +12720,23 @@ mDNSlocal void DeadvertiseAllInterfaceRecords(mDNS *const m)
}
}
+// Change target host name for record.
+mDNSlocal void UpdateTargetHostName(mDNS *const m, AuthRecord *const rr)
+{
+#if APPLE_OSX_mDNSResponder
+ // If this record was also registered with any D2D plugins, stop advertising
+ // the version with the old host name.
+ D2D_stop_advertising_record(rr);
+#endif
+
+ SetTargetToHostName(m, rr);
+
+#if APPLE_OSX_mDNSResponder
+ // Advertise the record with the updated host name with the D2D plugins if appropriate.
+ D2D_start_advertising_record(rr);
+#endif
+}
+
mDNSexport void mDNS_SetFQDN(mDNS *const m)
{
domainname newmname;
@@ -12676,8 +12757,8 @@ mDNSexport void mDNS_SetFQDN(mDNS *const m)
}
// 3. Make sure that any AutoTarget SRV records (and the like) get updated
- for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr);
- for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr);
+ for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->AutoTarget) UpdateTargetHostName(m, rr);
+ for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->AutoTarget) UpdateTargetHostName(m, rr);
mDNS_Unlock(m);
}
@@ -12766,7 +12847,7 @@ mDNSlocal void InitializeNetWakeState(mDNS *const m, NetworkInterfaceInfo *set)
// be stopped during interface deregistration. We can't sanity check to see if the
// question has been stopped or not before initializing it to -1 because we need to
// initialize it to -1 the very first time.
-
+
set->NetWakeBrowse.ThisQInterval = -1;
for (i=0; i<3; i++)
{
@@ -12916,6 +12997,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
}
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);
@@ -12942,14 +13024,8 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
if (!q->ThisQInterval || q->ThisQInterval > initial)
{
- q->ThisQInterval = initial;
-
-#if mDNS_REQUEST_UNICAST_RESPONSE
- q->RequestUnicast = SET_QU_IN_FIRST_FOUR_QUERIES;
-#else // mDNS_REQUEST_UNICAST_RESPONSE
- q->RequestUnicast = SET_QU_IN_FIRST_QUERY;
-#endif // mDNS_REQUEST_UNICAST_RESPONSE
-
+ q->ThisQInterval = initial;
+ q->RequestUnicast = kDefaultRequestUnicastCount;
}
q->LastQTime = m->timenow - q->ThisQInterval + qdelay;
q->RecentAnswerPkts = 0;
@@ -13235,13 +13311,17 @@ 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.
mDNSlocal AuthRecType setAuthRecType(mDNSInterfaceID InterfaceID, mDNSu32 flags)
{
AuthRecType artype;
if (InterfaceID == mDNSInterface_LocalOnly)
artype = AuthRecordLocalOnly;
- else if (InterfaceID == mDNSInterface_P2P)
+ else if (InterfaceID == mDNSInterface_P2P || InterfaceID == mDNSInterface_BLE)
artype = AuthRecordP2P;
else if ((InterfaceID == mDNSInterface_Any) && (flags & coreFlagIncludeP2P)
&& (flags & coreFlagIncludeAWDL))
@@ -13256,6 +13336,18 @@ mDNSlocal AuthRecType setAuthRecType(mDNSInterfaceID InterfaceID, mDNSu32 flags)
return artype;
}
+// Used to derive the original D2D specific flags specified by the client in the registration
+// when we don't have access to the original flag (kDNSServiceFlags*) values.
+mDNSexport mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType)
+{
+ mDNSu32 flags = 0;
+ if ((authRecType == AuthRecordAnyIncludeP2P) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
+ flags |= kDNSServiceFlagsIncludeP2P;
+ else if ((authRecType == AuthRecordAnyIncludeAWDL) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
+ flags |= kDNSServiceFlagsIncludeAWDL;
+ return flags;
+}
+
// Note:
// Name is first label of domain name (any dots in the name are actual dots, not label separators)
// Type is service type (e.g. "_ipp._tcp.")
@@ -13310,8 +13402,8 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
if (mDNSIPPortIsZero(port))
return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, InterfaceID, NSSCallback, sr, flags));
- // If the client is registering an oversized TXT record,
- // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
+ // If the caller is registering an oversized TXT record,
+ // it is the caller's responsibility to allocate a ServiceRecordSet structure that is large enough for it
if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen)
sr->RR_TXT.resrec.rdata->MaxRDLength = txtlen;
@@ -13349,7 +13441,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
sr->SubTypes[i].Additional1 = &sr->RR_SRV;
sr->SubTypes[i].Additional2 = &sr->RR_TXT;
}
-
+
SetAnonInfoSRS(sr, NumSubTypes);
// 3. Set up the SRV record rdata.
@@ -13409,6 +13501,7 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
mStatus status;
AuthRecType artype;
mDNSInterfaceID InterfaceID = sr->RR_PTR.resrec.InterfaceID;
+ ResourceRecord *rr;
artype = setAuthRecType(InterfaceID, flags);
@@ -13418,6 +13511,37 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
AssignDomainName(&extra->r.namestorage, sr->RR_SRV.resrec.name);
mDNS_Lock(m);
+ rr = mDNSNULL;
+ if (extra->r.resrec.rrtype == kDNSType_TXT)
+ {
+ if (sr->RR_TXT.resrec.RecordType & kDNSRecordTypeUniqueMask) rr = &sr->RR_TXT.resrec;
+ }
+ else if (extra->r.resrec.rrtype == kDNSType_SRV)
+ {
+ if (sr->RR_SRV.resrec.RecordType & kDNSRecordTypeUniqueMask) rr = &sr->RR_SRV.resrec;
+ }
+
+ if (!rr)
+ {
+ ExtraResourceRecord *srExtra;
+
+ for (srExtra = sr->Extras; srExtra; srExtra = srExtra->next)
+ {
+ if ((srExtra->r.resrec.rrtype == extra->r.resrec.rrtype) && (srExtra->r.resrec.RecordType & kDNSRecordTypeUniqueMask))
+ {
+ rr = &srExtra->r.resrec;
+ break;
+ }
+ }
+ }
+
+ if (rr && (extra->r.resrec.rroriginalttl != rr->rroriginalttl))
+ {
+ LogMsg("mDNS_AddRecordToService: Correcting TTL from %4d to %4d for %s",
+ extra->r.resrec.rroriginalttl, rr->rroriginalttl, RRDisplayString(m, &extra->r.resrec));
+ extra->r.resrec.rroriginalttl = rr->rroriginalttl;
+ }
+
e = &sr->Extras;
while (*e) e = &(*e)->next;
@@ -13593,7 +13717,7 @@ mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
if (InterfaceID == mDNSInterface_LocalOnly)
artype = AuthRecordLocalOnly;
- else if (InterfaceID == mDNSInterface_P2P)
+ else if (InterfaceID == mDNSInterface_P2P || InterfaceID == mDNSInterface_BLE)
artype = AuthRecordP2P;
else
artype = AuthRecordAny;
@@ -13820,9 +13944,9 @@ mDNSlocal void mDNSCoreReceiveRawND(mDNS *const m, const mDNSEthAddr *const sha,
}
else if (msg == msg3)
mDNSPlatformSetLocalAddressCacheEntry(m, &rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID);
- else if (msg == msg4)
+ else if (msg == msg4)
SendNDP(m, NDP_Adv, NDP_Solicited, rr, &ndp->target, mDNSNULL, spa, sha);
- else if (msg == msg5)
+ else if (msg == msg5)
SendNDP(m, NDP_Adv, 0, rr, &ndp->target, mDNSNULL, &AllHosts_v6, &AllHosts_v6_Eth);
}
}
@@ -14250,6 +14374,14 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
m->NextScheduledSPS = timenow + 0x78000000;
m->NextScheduledKA = timenow + 0x78000000;
m->NextScheduledStopTime = timenow + 0x78000000;
+ m->NextBLEServiceTime = 0; // zero indicates inactive
+
+#if BONJOUR_ON_DEMAND
+ m->NextBonjourDisableTime = 0; // Timer active when non zero.
+ m->BonjourEnabled = 0; // Set when Bonjour on Demand is enabled and Bonjour is currently enabled.
+#endif // BONJOUR_ON_DEMAND
+
+ m->DelayConflictProcessing = MAX_CONFLICT_PROCESSING_DELAYS;
m->RandomQueryDelay = 0;
m->RandomReconfirmDelay = 0;
m->PktNum = 0;
@@ -14334,19 +14466,11 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
m->WABBrowseQueriesCount = 0;
m->WABLBrowseQueriesCount = 0;
m->WABRegQueriesCount = 0;
-#if TARGET_OS_EMBEDDED || TARGET_OS_WATCH
m->AutoTargetServices = 0;
-#else
- m->AutoTargetServices = 1;
-#endif
-#if TARGET_OS_WATCH
+
+#if BONJOUR_ON_DEMAND
m->NumAllInterfaceRecords = 0;
m->NumAllInterfaceQuestions = 0;
-#else
- // Initialize to 1 for these targets to prevent not joining multicast group for interfaces when
- // both of these values are zero.
- m->NumAllInterfaceRecords = 1;
- m->NumAllInterfaceQuestions = 1;
#endif
// NAT traversal fields
m->LLQNAT.clientCallback = mDNSNULL;
@@ -14386,6 +14510,8 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
m->SPSBrowseCallback = mDNSNULL;
m->ProxyRecords = 0;
+ m->DNSPushServers = mDNSNULL;
+ m->DNSPushZones = mDNSNULL;
#endif
#if APPLE_OSX_mDNSResponder
@@ -14612,6 +14738,23 @@ mDNSlocal void SetConfigState(mDNS *const m, mDNSBool delete)
}
}
+mDNSlocal void SetDynDNSHostNameIfChanged(mDNS *const m, domainname *const fqdn)
+{
+ // Did our FQDN change?
+ if (!SameDomainName(fqdn, &m->FQDN))
+ {
+ if (m->FQDN.c[0]) mDNS_RemoveDynDNSHostName(m, &m->FQDN);
+
+ AssignDomainName(&m->FQDN, fqdn);
+
+ if (m->FQDN.c[0])
+ {
+ mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
+ mDNS_AddDynDNSHostName(m, &m->FQDN, DynDNSHostNameCallback, mDNSNULL);
+ }
+ }
+}
+
mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
{
mDNSu32 slot;
@@ -14642,6 +14785,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
SetConfigState(m, mDNStrue);
if (!mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL, mDNStrue))
{
+ SetDynDNSHostNameIfChanged(m, &fqdn);
SetConfigState(m, mDNSfalse);
mDNS_Unlock(m);
LogInfo("uDNS_SetupDNSConfig: No configuration change");
@@ -14818,6 +14962,14 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse);
}
}
+
+ // If a cache record's DNSServer pointer is NULL, but its active question got a DNSServer in this DNS configuration
+ // update, then use its DNSServer. This way, the active question and its duplicates don't miss out on RMV events.
+ if (!cr->resrec.rDNSServer && cr->CRActiveQuestion && cr->CRActiveQuestion->qDNSServer)
+ {
+ cr->resrec.rDNSServer = cr->CRActiveQuestion->qDNSServer;
+ LogInfo("uDNS_SetupDNSConfig: Using active question's DNS server %#a for cache record %s", &cr->resrec.rDNSServer->addr, CRDisplayString(m, cr));
+ }
}
while (*p)
@@ -14848,7 +15000,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
if (qptr->qDNSServer == ptr)
{
- LogMsg("uDNS_SetupDNSConfig: ERROR!! Cache Record %s Active question %##s (%s) (scope:%p) poining to DNSServer Address %#a"
+ 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->qDNSServer = mDNSNULL;
@@ -14858,7 +15010,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
{
LogInfo("uDNS_SetupDNSConfig: Cache Record %s, Active question %##s (%s) (scope:%p), pointing to DNSServer %#a (to be deleted),"
" resetting to question's DNSServer Address %#a", CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype),
- qptr->InterfaceID, &ptr->addr, (qptr->qDNSServer ? &qptr->qDNSServer->addr : mDNSNULL));
+ qptr->InterfaceID, &ptr->addr, (qptr->qDNSServer) ? &qptr->qDNSServer->addr : mDNSNULL);
cr->resrec.rDNSServer = qptr->qDNSServer;
}
}
@@ -14905,19 +15057,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
RestartRecordGetZoneData(m);
}
- // Did our FQDN change?
- if (!SameDomainName(&fqdn, &m->FQDN))
- {
- if (m->FQDN.c[0]) mDNS_RemoveDynDNSHostName(m, &m->FQDN);
-
- AssignDomainName(&m->FQDN, &fqdn);
-
- if (m->FQDN.c[0])
- {
- mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
- mDNS_AddDynDNSHostName(m, &m->FQDN, DynDNSHostNameCallback, mDNSNULL);
- }
- }
+ SetDynDNSHostNameIfChanged(m, &fqdn);
mDNS_Unlock(m);