summaryrefslogtreecommitdiffstats
path: root/mDNSResponder/mDNSCore
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-09-19 08:53:26 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-09-20 11:23:32 +0200
commitf01edf10244ccd53e098abdc1773c1aa0e4c5f8d (patch)
tree958a1ee323520629c4f027de1d4c56715949aa5c /mDNSResponder/mDNSCore
parentmDNSResponder: Update to v625.41.2 (diff)
downloadrtems-libbsd-f01edf10244ccd53e098abdc1773c1aa0e4c5f8d.tar.bz2
mDNSResponder: Update to v765.1.2
The sources can be obtained via: https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-765.1.2.tar.gz Move mDNS_StartResolveService() and mDNS_StopResolveService() to an RTEMS-specific file (rtemsbsd/mdns/mDNSResolveService.c) using the v576.30.4 implementation. Apple removed these functions without explanation. Update #3522.
Diffstat (limited to 'mDNSResponder/mDNSCore')
-rw-r--r--mDNSResponder/mDNSCore/DNSCommon.c59
-rw-r--r--mDNSResponder/mDNSCore/DNSCommon.h25
-rw-r--r--mDNSResponder/mDNSCore/anonymous.c7
-rw-r--r--mDNSResponder/mDNSCore/dnsproxy.c28
-rw-r--r--mDNSResponder/mDNSCore/dnssec.c7
-rwxr-xr-xmDNSResponder/mDNSCore/mDNS.c1826
-rwxr-xr-xmDNSResponder/mDNSCore/mDNSEmbeddedAPI.h247
-rw-r--r--mDNSResponder/mDNSCore/nsec3.c4
-rwxr-xr-xmDNSResponder/mDNSCore/uDNS.c801
-rwxr-xr-xmDNSResponder/mDNSCore/uDNS.h14
10 files changed, 1734 insertions, 1284 deletions
diff --git a/mDNSResponder/mDNSCore/DNSCommon.c b/mDNSResponder/mDNSCore/DNSCommon.c
index d364ee02..a2b703f7 100644
--- a/mDNSResponder/mDNSCore/DNSCommon.c
+++ b/mDNSResponder/mDNSCore/DNSCommon.c
@@ -43,6 +43,7 @@ mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)-2;
mDNSexport const mDNSInterfaceID mDNSInterface_Unicast = (mDNSInterfaceID)-3;
mDNSexport const mDNSInterfaceID mDNSInterface_P2P = (mDNSInterfaceID)-4;
mDNSexport const mDNSInterfaceID uDNSInterfaceMark = (mDNSInterfaceID)-5;
+mDNSexport const mDNSInterfaceID mDNSInterface_BLE = (mDNSInterfaceID)-6;
// Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of
// Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP
@@ -107,6 +108,8 @@ mDNSexport const mDNSOpaque16 DNSSecQFlags = { { kDNSFlag0_QR_Query | kDNS
mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } };
mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } };
+mDNSexport const mDNSOpaque16 SubscribeFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Subscribe, 0 } };
+mDNSexport const mDNSOpaque16 UnSubscribeFlags= { { kDNSFlag0_QR_Query | kDNSFlag0_OP_UnSubscribe, 0 } };
mDNSexport const mDNSOpaque64 zeroOpaque64 = { { 0 } };
@@ -541,7 +544,7 @@ mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RD
}
break;
- default: mDNS_snprintf(buffer+length, RemSpc, "RDLen %d: %s", rr->rdlength, rd->data);
+ default: mDNS_snprintf(buffer+length, RemSpc, "RDLen %d: %.*s", rr->rdlength, rr->rdlength, rd->data);
// Really should scan buffer to check if text is valid UTF-8 and only replace with dots if not
for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr = '.';
break;
@@ -803,6 +806,7 @@ mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstri
mDNSu8 c = (mDNSu8)*cstr++; // Read the character
if (c == '\\') // If escape character, check next character
{
+ if (*cstr == '\0') break; // If this is the end of the string, then break
c = (mDNSu8)*cstr++; // Assume we'll just take the next character
if (mDNSIsDigit(cstr[-1]) && mDNSIsDigit(cstr[0]) && mDNSIsDigit(cstr[1]))
{ // If three decimal digits,
@@ -815,7 +819,7 @@ mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstri
}
*ptr++ = c; // Write the character
}
- if (*cstr) cstr++; // Skip over the trailing dot (if present)
+ if (*cstr == '.') cstr++; // Skip over the trailing dot (if present)
if (ptr - lengthbyte - 1 > MAX_DOMAIN_LABEL) // If illegal label, abort
return(mDNSNULL);
*lengthbyte = (mDNSu8)(ptr - lengthbyte - 1); // Fill in the length byte
@@ -1165,7 +1169,8 @@ mDNSexport const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3
const mDNSu8 hash[NSEC3_MAX_HASH_LEN], int *dlen)
{
AlgContext *ctx;
- int i;
+ unsigned int i;
+ unsigned int iterations;
domainname lname;
mDNSu8 *p = (mDNSu8 *)&nsec3->salt;
const mDNSu8 *digest;
@@ -1183,7 +1188,8 @@ mDNSexport const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3
// Note that it is "i <=". The first iteration is for digesting the name and salt.
// The iteration count does not include that.
- for (i = 0; i <= swap16(nsec3->iterations); i++)
+ iterations = swap16(nsec3->iterations);
+ for (i = 0; i <= iterations; i++)
{
ctx = AlgCreate(DIGEST_ALG, nsec3->alg);
if (!ctx)
@@ -1367,17 +1373,14 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD
if (InterfaceID == mDNSInterface_LocalOnly && artype != AuthRecordLocalOnly)
{
LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch LocalOnly record InterfaceID %p called with artype %d", InterfaceID, artype);
- return;
}
else if (InterfaceID == mDNSInterface_P2P && artype != AuthRecordP2P)
{
LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch P2P record InterfaceID %p called with artype %d", InterfaceID, artype);
- return;
}
else if (!InterfaceID && (artype == AuthRecordP2P || artype == AuthRecordLocalOnly))
{
LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch InterfaceAny record InterfaceID %p called with artype %d", InterfaceID, artype);
- return;
}
// Don't try to store a TTL bigger than we can represent in platform time units
@@ -1467,8 +1470,6 @@ mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID I
q->ForceMCast = mDNSfalse;
q->ReturnIntermed = mDNSfalse;
q->SuppressUnusable = mDNSfalse;
- q->DenyOnCellInterface = mDNSfalse;
- q->DenyOnExpInterface = mDNSfalse;
q->SearchListIndex = 0;
q->AppendSearchDomains = 0;
q->RetryWithSearchDomains = mDNSfalse;
@@ -1779,7 +1780,7 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr
// LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
// are handled in LocalOnlyRecordAnswersQuestion
- if ((rr->InterfaceID == mDNSInterface_LocalOnly) || (rr->InterfaceID == mDNSInterface_P2P))
+ if (LocalOnlyOrP2PInterface(rr->InterfaceID))
{
LogMsg("SameNameRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
return mDNSfalse;
@@ -1914,7 +1915,7 @@ mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr,
{
// LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
// are handled in LocalOnlyRecordAnswersQuestion
- if ((rr->InterfaceID == mDNSInterface_LocalOnly) || (rr->InterfaceID == mDNSInterface_P2P))
+ if (LocalOnlyOrP2PInterface(rr->InterfaceID))
{
LogMsg("AnyTypeRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
return mDNSfalse;
@@ -2142,7 +2143,6 @@ mDNSexport const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const
return(mDNSNULL);
}
-// Put a string of dot-separated labels as length-prefixed labels
// domainname is a fully-qualified name (i.e. assumed to be ending in a dot, even if it doesn't)
// msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers)
// end points to the end of the message so far
@@ -2843,7 +2843,7 @@ mDNSlocal mDNSu8 *SanityCheckBitMap(const mDNSu8 *bmap, const mDNSu8 *end, int l
// (domainnames are expanded to 255 bytes) when stored in memory.
//
// This function can also be called with "NULL" msg to parse a single resource record pointed to by ptr.
-// The caller can do this only if the names in the resource records are compressed and validity of the
+// The caller can do this only if the names in the resource records are not compressed and validity of the
// resource record has already been done before. DNSSEC currently uses it this way.
mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end,
LargeCacheRecord *const largecr, mDNSu16 rdlength)
@@ -3348,6 +3348,12 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
dlen = DomainNameLength(&name);
rlen = end - ptr;
rr->resrec.rdlength = dlen + rlen;
+ if (rr->resrec.rdlength > MaximumRDSize)
+ {
+ LogInfo("SetRData: Malformed TSIG/TKEY rdlength %d, rr->resrec.rdlength %d, "
+ "bmaplen %d, name %##s", rdlength, rr->resrec.rdlength, name.c);
+ goto fail;
+ }
AssignDomainName((domainname *)rdb->data, &name);
mDNSPlatformMemCopy(rdb->data + dlen, ptr, rlen);
break;
@@ -3626,7 +3632,7 @@ mDNSexport mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end)
mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, int count, char *label)
{
int i;
- LogMsg("%2d %s", count, label);
+ LogInfo("%2d %s", count, label);
for (i = 0; i < count && ptr; i++)
{
// This puts a LargeCacheRecord on the stack instead of using the shared m->rec storage,
@@ -3634,9 +3640,11 @@ mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg,
// embedded systems) putting a 9kB object on the stack isn't a big problem.
LargeCacheRecord largecr;
ptr = GetLargeResourceRecord(m, msg, ptr, end, mDNSInterface_Any, kDNSRecordTypePacketAns, &largecr);
- if (ptr) LogMsg("%2d TTL%8d %s", i, largecr.r.resrec.rroriginalttl, CRDisplayString(m, &largecr.r));
+ if (ptr)
+ LogInfo("%2d TTL%8d %s", i, largecr.r.resrec.rroriginalttl, CRDisplayString(m, &largecr.r));
}
- if (!ptr) LogMsg("DumpRecords: ERROR: Premature end of packet data");
+ if (!ptr)
+ LogInfo("DumpRecords: ERROR: Premature end of packet data");
return(ptr);
}
@@ -3646,7 +3654,9 @@ mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg,
(X) == kDNSFlag0_OP_Status ? "Status " : \
(X) == kDNSFlag0_OP_Unused3 ? "Unused3 " : \
(X) == kDNSFlag0_OP_Notify ? "Notify " : \
- (X) == kDNSFlag0_OP_Update ? "Update " : "?? " )
+ (X) == kDNSFlag0_OP_Update ? "Update " : \
+ (X) == kDNSFlag0_OP_Subscribe? "Subscribe": \
+ (X) == kDNSFlag0_OP_UnSubscribe? "UnSubscribe" : "?? " )
#define DNS_RC_Name(X) ( \
(X) == kDNSFlag1_RC_NoErr ? "NoErr" : \
@@ -3678,7 +3688,7 @@ mDNSexport void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *t
if (dstaddr || !mDNSIPPortIsZero(dstport))
dbuffer[mDNS_snprintf(dbuffer, sizeof(dbuffer), " to %#a:%d", dstaddr, mDNSVal16(dstport))] = 0;
- LogMsg("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes from %s%d%s%s --",
+ LogInfo("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes from %s%d%s%s --",
tbuffer, transport,
DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
msg->h.flags.b[0] & kDNSFlag0_QR_Response ? "Response" : "Query",
@@ -3697,16 +3707,16 @@ mDNSexport void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *t
(msg->h.flags.b[0] & kDNSFlag0_TC) ? " (truncated)" : ""
);
- LogMsg("%2d %s", msg->h.numQuestions, IsUpdate ? "Zone" : "Questions");
+ LogInfo("%2d %s", msg->h.numQuestions, IsUpdate ? "Zone" : "Questions");
for (i = 0; i < msg->h.numQuestions && ptr; i++)
{
ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q);
- if (ptr) LogMsg("%2d %##s %s", i, q.qname.c, DNSTypeName(q.qtype));
+ if (ptr) LogInfo("%2d %##s %s", i, q.qname.c, DNSTypeName(q.qtype));
}
ptr = DumpRecords(m, msg, ptr, end, msg->h.numAnswers, IsUpdate ? "Prerequisites" : "Answers");
ptr = DumpRecords(m, msg, ptr, end, msg->h.numAuthorities, IsUpdate ? "Updates" : "Authorities");
DumpRecords(m, msg, ptr, end, msg->h.numAdditionals, "Additionals");
- LogMsg("--------------");
+ LogInfo("--------------");
}
// ***************************************************************************
@@ -3896,6 +3906,10 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
if (e - m->NextScheduledSPS > 0) e = m->NextScheduledSPS;
if (e - m->NextScheduledKA > 0) e = m->NextScheduledKA;
+#if BONJOUR_ON_DEMAND
+ if (m->NextBonjourDisableTime && (e - m->NextBonjourDisableTime > 0)) e = m->NextBonjourDisableTime;
+#endif // BONJOUR_ON_DEMAND
+
// NextScheduledSPRetry only valid when DelaySleep not set
if (!m->DelaySleep && m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry;
if (m->DelaySleep && e - m->DelaySleep > 0) e = m->DelaySleep;
@@ -3911,6 +3925,9 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
}
if (e - m->NextScheduledStopTime > 0) e = m->NextScheduledStopTime;
+
+ if (m->NextBLEServiceTime && (e - m->NextBLEServiceTime > 0)) e = m->NextBLEServiceTime;
+
return(e);
}
diff --git a/mDNSResponder/mDNSCore/DNSCommon.h b/mDNSResponder/mDNSCore/DNSCommon.h
index e51b06dd..2da19700 100644
--- a/mDNSResponder/mDNSCore/DNSCommon.h
+++ b/mDNSResponder/mDNSCore/DNSCommon.h
@@ -40,17 +40,19 @@ extern "C" {
typedef enum
{
- kDNSFlag0_QR_Mask = 0x80, // Query or response?
- kDNSFlag0_QR_Query = 0x00,
- kDNSFlag0_QR_Response = 0x80,
-
- kDNSFlag0_OP_Mask = 0x78, // Operation type
- kDNSFlag0_OP_StdQuery = 0x00,
- kDNSFlag0_OP_Iquery = 0x08,
- kDNSFlag0_OP_Status = 0x10,
- kDNSFlag0_OP_Unused3 = 0x18,
- kDNSFlag0_OP_Notify = 0x20,
- kDNSFlag0_OP_Update = 0x28,
+ kDNSFlag0_QR_Mask = 0x80, // Query or response?
+ kDNSFlag0_QR_Query = 0x00,
+ kDNSFlag0_QR_Response = 0x80,
+
+ kDNSFlag0_OP_Mask = 0x78, // Operation type
+ kDNSFlag0_OP_StdQuery = 0x00,
+ kDNSFlag0_OP_Subscribe = 0x06,
+ kDNSFlag0_OP_UnSubscribe = 0x07,
+ kDNSFlag0_OP_Iquery = 0x08,
+ kDNSFlag0_OP_Status = 0x10,
+ kDNSFlag0_OP_Unused3 = 0x18,
+ kDNSFlag0_OP_Notify = 0x20,
+ kDNSFlag0_OP_Update = 0x28,
kDNSFlag0_QROP_Mask = kDNSFlag0_QR_Mask | kDNSFlag0_OP_Mask,
@@ -84,6 +86,7 @@ typedef enum
TSIG_ErrBadTime = 18
} TSIG_ErrorCode;
+
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
diff --git a/mDNSResponder/mDNSCore/anonymous.c b/mDNSResponder/mDNSCore/anonymous.c
index 779e4ea6..aaaebc27 100644
--- a/mDNSResponder/mDNSCore/anonymous.c
+++ b/mDNSResponder/mDNSCore/anonymous.c
@@ -71,7 +71,7 @@ mDNSlocal mDNSBool InitializeNSEC3Record(ResourceRecord *rr, const mDNSu8 *AnonD
// Hash the base service name + salt + AnonData
if (!NSEC3HashName(rr->name, nsec3, AnonData, len, hashName, &hlen))
{
- LogMsg("InitializeNSEC3Record: NSEC3HashName failed for ##s", rr->name->c);
+ LogMsg("InitializeNSEC3Record: NSEC3HashName failed for %##s", rr->name->c);
return mDNSfalse;
}
if (hlen != SHA1_HASH_LENGTH)
@@ -280,9 +280,10 @@ mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNS
int AnonDataLen;
rdataNSEC3 *nsec3;
int hlen;
- const mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
int nxtLength;
mDNSu8 *nxtName;
+ mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
+ mDNSPlatformMemZero(hashName, sizeof(hashName));
debugf("AnonInfoAnswersQuestion: question qname %##s", q->qname.c);
@@ -403,7 +404,7 @@ mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNS
if (!NSEC3HashName(nsec3RR->name, nsec3, AnonData, AnonDataLen, hashName, &hlen))
{
- LogMsg("AnonInfoAnswersQuestion: NSEC3HashName failed for ##s", nsec3RR->name->c);
+ LogMsg("AnonInfoAnswersQuestion: NSEC3HashName failed for %##s", nsec3RR->name->c);
return mDNSfalse;
}
if (hlen != SHA1_HASH_LENGTH)
diff --git a/mDNSResponder/mDNSCore/dnsproxy.c b/mDNSResponder/mDNSCore/dnsproxy.c
index 5b358864..05b70dd9 100644
--- a/mDNSResponder/mDNSCore/dnsproxy.c
+++ b/mDNSResponder/mDNSCore/dnsproxy.c
@@ -553,14 +553,21 @@ mDNSlocal mDNSBool CheckDNSProxyIpIntf(const mDNS *const m, mDNSInterfaceID Inte
int i;
mDNSu32 ip_ifindex = (mDNSu32)(unsigned long)InterfaceID;
- LogInfo("CheckDNSProxyIpIntf: Stored Input Interface List: [%d] [%d] [%d] [%d] [%d]", m->dp_ipintf[0], m->dp_ipintf[1], m->dp_ipintf[2],
- m->dp_ipintf[3], m->dp_ipintf[4]);
+ LogInfo("CheckDNSProxyIpIntf: Check for ifindex[%d] in stored input interface list: [%d] [%d] [%d] [%d] [%d]",
+ ip_ifindex, m->dp_ipintf[0], m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4]);
- for (i = 0; i < MaxIp; i++)
+ if (ip_ifindex > 0)
{
- if (ip_ifindex == m->dp_ipintf[i])
- return mDNStrue;
+ for (i = 0; i < MaxIp; i++)
+ {
+ if (ip_ifindex == m->dp_ipintf[i])
+ return mDNStrue;
+ }
}
+
+ LogMsg("CheckDNSProxyIpIntf: ifindex[%d] not in stored input interface list: [%d] [%d] [%d] [%d] [%d]",
+ ip_ifindex, m->dp_ipintf[0], m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4]);
+
return mDNSfalse;
}
@@ -583,7 +590,10 @@ mDNSlocal void ProxyCallbackCommon(mDNS *const m, void *socket, void *const pkt,
debugf("ProxyCallbackCommon: DNS Query coming from InterfaceID %p", InterfaceID);
// Ignore if the DNS Query is not from a Valid Input InterfaceID
if (!CheckDNSProxyIpIntf(m, InterfaceID))
+ {
+ LogMsg("ProxyCallbackCommon: Rejecting DNS Query coming from InterfaceID %p", InterfaceID);
return;
+ }
if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader))
{
@@ -691,8 +701,7 @@ mDNSlocal void ProxyCallbackCommon(mDNS *const m, void *socket, void *const pkt,
debugf("ProxyCallbackCommon: DNS Query forwarding to interface index %d", m->dp_opintf);
mDNS_SetupQuestion(&pc->q, (mDNSInterfaceID)(unsigned long)m->dp_opintf, &q.qname, q.qtype, ProxyClientCallback, pc);
pc->q.TimeoutQuestion = 1;
- // Even though we don't care about intermediate responses, set ReturnIntermed so that
- // we get the negative responses
+ // Set ReturnIntermed so that we get the negative responses
pc->q.ReturnIntermed = mDNStrue;
pc->q.ProxyQuestion = mDNStrue;
pc->q.ProxyDNSSECOK = pc->DNSSECOK;
@@ -735,9 +744,10 @@ mDNSexport void ProxyTCPCallback(mDNS *const m, void *socket, void *const pkt, c
const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context)
{
LogInfo("ProxyTCPCallback: DNS Message from %#a:%d to %#a:%d length %d", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt);
- // If the connection was closed from the other side, locate the client
+
+ // If the connection was closed from the other side or incoming packet does not match stored input interface list, locate the client
// state and free it.
- if ((end - (mDNSu8 *)pkt) == 0)
+ if (((end - (mDNSu8 *)pkt) == 0) || (!CheckDNSProxyIpIntf(m, InterfaceID)))
{
DNSProxyClient **ppc = &DNSProxyClients;
DNSProxyClient **prevpc;
diff --git a/mDNSResponder/mDNSCore/dnssec.c b/mDNSResponder/mDNSCore/dnssec.c
index bf9acfe8..514a488c 100644
--- a/mDNSResponder/mDNSCore/dnssec.c
+++ b/mDNSResponder/mDNSCore/dnssec.c
@@ -87,6 +87,7 @@ mDNSlocal mDNSBool TrustedKeyPresent(mDNS *const m, DNSSECVerifier *dv);
mDNSlocal mStatus ValidateDS(DNSSECVerifier *dv);
mDNSlocal void DNSSECNegativeValidationCB(mDNS *const m, DNSSECVerifier *dv, CacheGroup *cg, ResourceRecord *answer, DNSSECStatus status);
mDNSlocal RRVerifier* CopyRRVerifier(RRVerifier *from);
+mDNSlocal void FreeDNSSECAuthChainInfo(AuthChain *ac);
// Currently we use this to convert a RRVerifier to resource record so that we can
// use the standard DNS utility functions
@@ -300,6 +301,8 @@ mDNSlocal AuthChain *AuthChainCopy(AuthChain *ae)
if (!ac)
{
LogMsg("AuthChainCopy: AuthChain alloc failure");
+ if (retac)
+ FreeDNSSECAuthChainInfo(retac);
return mDNSfalse;
}
@@ -2523,7 +2526,9 @@ mDNSlocal void FinishDNSSECVerification(mDNS *const m, DNSSECVerifier *dv)
LogDNSSEC("FinishDNSSECVerification: all rdata sets available for sig verification for %##s (%s)",
dv->origName.c, DNSTypeName(dv->origType));
- mDNS_StopQuery(m, &dv->q);
+ // Stop outstanding query if one exists
+ if (dv->q.ThisQInterval != -1)
+ mDNS_StopQuery(m, &dv->q);
if (ValidateSignature(dv, &resultKey, &resultRRSig) == mStatus_NoError)
{
rdataDNSKey *key;
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);
diff --git a/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h b/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
index 48f8280d..3fd654eb 100755
--- a/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
+++ b/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
@@ -96,9 +96,9 @@ extern "C" {
#ifdef LIMITED_RESOURCES_TARGET
// Don't support jumbo frames
// 40 (IPv6 header) + 8 (UDP header) + 12 (DNS message header) + 1440 (DNS message body) = 1500 total
-#define AbsoluteMaxDNSMessageData 1440
+#define AbsoluteMaxDNSMessageData 1440
// StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record (6 + 256 bytes)
-#define MaximumRDSize 264
+#define MaximumRDSize 264
#endif
// ***************************************************************************
@@ -297,20 +297,20 @@ typedef mDNSOpaque48 mDNSEthAddr; // An Ethernet address is a six-byte opa
#define bit_clr_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] &= ~(1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
#define bit_get_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] & (1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
-enum
+typedef enum
{
mDNSAddrType_None = 0,
mDNSAddrType_IPv4 = 4,
mDNSAddrType_IPv6 = 6,
mDNSAddrType_Unknown = ~0 // Special marker value used in known answer list recording
-};
+} mDNSAddr_Type;
-enum
+typedef enum
{
mDNSTransport_None = 0,
mDNSTransport_UDP = 1,
mDNSTransport_TCP = 2
-};
+} mDNSTransport_Type;
typedef struct
{
@@ -364,7 +364,8 @@ enum
mStatus_NoRouter = -65566,
mStatus_PollingMode = -65567,
mStatus_Timeout = -65568,
- // -65568 to -65786 currently unused; available for allocation
+ mStatus_HostUnreachErr = -65569,
+ // -65570 to -65786 currently unused; available for allocation
// tcp connection status
mStatus_ConnPending = -65787,
@@ -808,7 +809,7 @@ typedef struct TrustAnchor
struct TrustAnchor *next;
int digestLen;
mDNSu32 validFrom;
- mDNSu32 validUntil;
+ mDNSu32 validUntil;
domainname zone;
rdataDS rds;
} TrustAnchor;
@@ -875,10 +876,10 @@ typedef packedstruct
// For example, SHA-1 hash of 20 bytes will be encoded as 20/5 * 8 = 32 base32
// bytes. For a max domain name size of 255 bytes of base32 encoding : (255/8)*5
// is the max hash length possible.
-#define NSEC3_MAX_HASH_LEN 155
+#define NSEC3_MAX_HASH_LEN 155
// In NSEC3, the names are hashed and stored in the first label and hence cannot exceed label
// size.
-#define NSEC3_MAX_B32_LEN MAX_DOMAIN_LABEL
+#define NSEC3_MAX_B32_LEN MAX_DOMAIN_LABEL
// We define it here instead of dnssec.h so that these values can be used
// in files without bringing in all of dnssec.h unnecessarily.
@@ -1307,14 +1308,6 @@ struct NATTraversalInfo_struct
enum
{
- DNSServer_Untested = 0,
- DNSServer_Passed = 1,
- DNSServer_Failed = 2,
- DNSServer_Disabled = 3
-};
-
-enum
-{
DNSServer_FlagDelete = 0x1,
DNSServer_FlagNew = 0x2,
#if APPLE_OSX_mDNSResponder
@@ -1342,8 +1335,9 @@ enum
{
kScopeNone = 0, // DNS server used by unscoped questions
kScopeInterfaceID = 1, // Scoped DNS server used only by scoped questions
- kScopeServiceID = 2 // Service specific DNS server used only by questions
+ kScopeServiceID = 2, // Service specific DNS server used only by questions
// have a matching serviceID
+ kScopesMaxCount = 3 // Max count for scopes enum
};
// Note: DNSSECAware is set if we are able to get a valid response to
@@ -1360,10 +1354,7 @@ typedef struct DNSServer
mDNSs32 serviceID;
mDNSAddr addr;
mDNSIPPort port;
- mDNSOpaque16 testid;
mDNSu32 flags; // Set when we're planning to delete this from the list
- mDNSu32 teststate; // Have we sent bug-detection query to this server?
- mDNSs32 lasttest; // Time we sent last bug-detection query to this server
domainname domain; // name->server matching for "split dns"
mDNSs32 penaltyTime; // amount of time this server is penalized
mDNSu32 scoped; // See the scoped enum above
@@ -1606,8 +1597,11 @@ struct AuthRecord_struct
#define Question_uDNS(Q) ((Q)->InterfaceID == mDNSInterface_Unicast || (Q)->ProxyQuestion || \
((Q)->InterfaceID != mDNSInterface_LocalOnly && (Q)->InterfaceID != mDNSInterface_P2P && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname)))
+// AuthRecordLocalOnly records are registered using mDNSInterface_LocalOnly and
+// AuthRecordP2P records are created by D2DServiceFound events. Both record types are kept on the same list.
#define RRLocalOnly(rr) ((rr)->ARType == AuthRecordLocalOnly || (rr)->ARType == AuthRecordP2P)
+// All other auth records, not including those defined as RRLocalOnly().
#define RRAny(rr) ((rr)->ARType == AuthRecordAny || (rr)->ARType == AuthRecordAnyIncludeP2P || (rr)->ARType == AuthRecordAnyIncludeAWDL || (rr)->ARType == AuthRecordAnyIncludeAWDLandP2P)
// Question (A or AAAA) that is suppressed currently because IPv4 or IPv6 address
@@ -1802,6 +1796,25 @@ enum
enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 };
+// DNS Push Notification
+typedef enum
+{
+ DNSPUSH_NOERROR = 0,
+ DNSPUSH_FORMERR = 1,
+ DNSPUSH_SERVFAIL = 2,
+ DNSPUSH_NOTIMP = 4,
+ DNSPUSH_REFUSED = 5
+} DNSPUSH_ErrorCode;
+
+typedef enum {
+ DNSPUSH_INIT = 1,
+ DNSPUSH_NOSERVER = 2,
+ DNSPUSH_SERVERFOUND = 3,
+ DNSPUSH_ESTABLISHED = 4
+} DNSPush_State;
+
+
+
#define HMAC_LEN 64
#define HMAC_IPAD 0x36
#define HMAC_OPAD 0x5c
@@ -1893,6 +1906,10 @@ typedef struct
mDNSBool answered; // Has this question been answered?
} uDNSMetrics;
+
+extern mDNSu32 curr_num_regservices; // tracks the current number of services registered
+extern mDNSu32 max_num_regservices; // tracks the max number of simultaneous services registered by the device
+
#endif
struct DNSQuestion_struct
@@ -1969,6 +1986,12 @@ struct DNSQuestion_struct
// for TCP: there is some ambiguity in the use of this variable, but in general, it is
// the number of TCP/TLS connection attempts for this LLQ state, or
// the number of packets sent for this TCP/TLS connection
+
+ // DNS Push Notification fields. These fields are only meaningful when LongLived flag is set
+ DNSPush_State dnsPushState; // The state of the DNS push notification negotiation
+ mDNSAddr dnsPushServerAddr; // Address of the system acting as the DNS Push Server
+ mDNSIPPort dnsPushServerPort; // Port on which the DNS Push Server is being advertised.
+
mDNSOpaque64 id;
// DNS Proxy fields
@@ -1976,7 +1999,7 @@ struct DNSQuestion_struct
// till we populate in the cache
mDNSBool DisallowPID; // Is the query allowed for the "PID" that we are sending on behalf of ?
mDNSs32 ServiceID; // Service identifier to match against the DNS server
-
+
// Client API fields: The client must set up these fields *before* calling mDNS_StartQuery()
mDNSInterfaceID InterfaceID; // Non-zero if you want to issue queries only on a single specific IP interface
mDNSu32 flags; // flags from original DNSService*() API request.
@@ -1991,8 +2014,6 @@ struct DNSQuestion_struct
mDNSBool ForceMCast; // Set by client to force mDNS query, even for apparently uDNS names
mDNSBool ReturnIntermed; // Set by client to request callbacks for intermediate CNAME/NXDOMAIN results
mDNSBool SuppressUnusable; // Set by client to suppress unusable queries to be sent on the wire
- mDNSBool DenyOnCellInterface; // Set by client to suppress uDNS queries on cellular interface
- mDNSBool DenyOnExpInterface; // Set by client to suppress uDNS queries on expensive interface
mDNSu8 RetryWithSearchDomains; // Retry with search domains if there is no entry in the cache or AuthRecords
mDNSu8 TimeoutQuestion; // Timeout this question if there is no reply in configured time
mDNSu8 WakeOnResolve; // Send wakeup on resolve
@@ -2014,43 +2035,7 @@ struct DNSQuestion_struct
#endif
};
-typedef struct
-{
- // Client API fields: The client must set up name and InterfaceID *before* calling mDNS_StartResolveService()
- // When the callback is invoked, ip, port, TXTlen and TXTinfo will have been filled in with the results learned from the network.
- domainname name;
- mDNSInterfaceID InterfaceID; // ID of the interface the response was received on
- mDNSAddr ip; // Remote (destination) IP address where this service can be accessed
- mDNSIPPort port; // Port where this service can be accessed
- mDNSu16 TXTlen;
- mDNSu8 TXTinfo[2048]; // Additional demultiplexing information (e.g. LPR queue name)
-} ServiceInfo;
-
-// Note: Within an mDNSServiceInfoQueryCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
-typedef struct ServiceInfoQuery_struct ServiceInfoQuery;
-typedef void mDNSServiceInfoQueryCallback (mDNS *const m, ServiceInfoQuery *query);
-struct ServiceInfoQuery_struct
-{
- // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
- // No fields need to be set up by the client prior to calling mDNS_StartResolveService();
- // all required data is passed as parameters to that function.
- // The ServiceInfoQuery structure memory is working storage for mDNSCore to discover the requested information
- // and place it in the ServiceInfo structure. After the client has called mDNS_StopResolveService(), it may
- // dispose of the ServiceInfoQuery structure while retaining the results in the ServiceInfo structure.
- DNSQuestion qSRV;
- DNSQuestion qTXT;
- DNSQuestion qAv4;
- DNSQuestion qAv6;
- mDNSu8 GotSRV;
- mDNSu8 GotTXT;
- mDNSu8 GotADD;
- mDNSu32 Answers;
- ServiceInfo *info;
- mDNSServiceInfoQueryCallback *ServiceInfoQueryCallback;
- void *ServiceInfoQueryContext;
-};
-
-typedef enum { ZoneServiceUpdate, ZoneServiceQuery, ZoneServiceLLQ } ZoneService;
+typedef enum { ZoneServiceUpdate, ZoneServiceQuery, ZoneServiceLLQ, ZoneServiceDNSPush } ZoneService;
typedef void ZoneDataCallback (mDNS *const m, mStatus err, const ZoneData *result);
@@ -2276,6 +2261,26 @@ typedef struct
extern void LogMDNSStatistics(mDNS *const m);
+typedef struct mDNS_DNSPushNotificationServer DNSPushNotificationServer;
+typedef struct mDNS_DNSPushNotificationZone DNSPushNotificationZone;
+
+struct mDNS_DNSPushNotificationServer
+{
+ mDNSAddr serverAddr; // Server Address
+ tcpInfo_t *connection; // TCP Connection pointer
+ mDNSu32 numberOfQuestions; // Number of questions for this server
+ DNSPushNotificationServer *next;
+} ;
+
+struct mDNS_DNSPushNotificationZone
+{
+ domainname zoneName;
+ DNSPushNotificationServer *servers; // DNS Push Notification Servers for this zone
+ mDNSu32 numberOfQuestions; // Number of questions for this zone
+ DNSPushNotificationZone *next;
+} ;
+
+
struct mDNS_struct
{
// Internal state fields. These hold the main internal state of mDNSCore;
@@ -2320,6 +2325,11 @@ struct mDNS_struct
mDNSs32 NextScheduledNATOp; // Next time to send NAT-traversal packets
mDNSs32 NextScheduledSPS; // Next time to purge expiring Sleep Proxy records
mDNSs32 NextScheduledKA; // Next time to send Keepalive packets (SPS)
+#if BONJOUR_ON_DEMAND
+ mDNSs32 NextBonjourDisableTime; // Next time to leave multicast group if Bonjour on Demand is enabled
+ mDNSu8 BonjourEnabled; // Non zero if Bonjour is currently enabled by the Bonjour on Demand logic
+#endif // BONJOUR_ON_DEMAND
+ mDNSs32 DelayConflictProcessing; // To prevent spurious confilcts due to stale packets on the wire/air.
mDNSs32 RandomQueryDelay; // For de-synchronization of query packets on the wire
mDNSu32 RandomReconfirmDelay; // For de-synchronization of reconfirmation queries on the wire
mDNSs32 PktNum; // Unique sequence number assigned to each received packet
@@ -2348,6 +2358,7 @@ struct mDNS_struct
mDNSs32 NextScheduledStopTime; // Next time to stop a question
+ mDNSs32 NextBLEServiceTime; // Next time to call the BLE discovery management layer. Non zero when active.
// These fields only required for mDNS Searcher...
DNSQuestion *Questions; // List of all registered questions, active and inactive
@@ -2384,7 +2395,7 @@ struct mDNS_struct
mDNSs32 ProbeFailTime;
mDNSu32 NumFailedProbes;
mDNSs32 SuppressProbes;
- Platform_t mDNS_plat; // Why is this here in the “only required for mDNS Responder” section? -- SC
+ Platform_t mDNS_plat; // Why is this here in the “only required for mDNS Responder” section? -- SC
// Unicast-specific data
mDNSs32 NextuDNSEvent; // uDNS next event
@@ -2440,6 +2451,10 @@ struct mDNS_struct
mDNSu8 *UPnPRouterAddressString; // holds both the router's address and port
mDNSu8 *UPnPSOAPAddressString; // holds both address and port for SOAP messages
+ // DNS Push Notification fields
+ DNSPushNotificationServer *DNSPushServers; // DNS Push Notification Servers
+ DNSPushNotificationZone *DNSPushZones;
+
// Sleep Proxy client fields
AuthRecord *SPSRRSet; // To help the client keep track of the records registered with the sleep proxy
@@ -2472,8 +2487,13 @@ struct mDNS_struct
int notifyToken;
int uds_listener_skt; // Listening socket for incoming UDS clients. This should not be here -- it's private to uds_daemon.c and nothing to do with mDNSCore -- SC
mDNSu32 AutoTargetServices; // # of services that have AutoTarget set
- mDNSu32 NumAllInterfaceRecords; // Right now we count *all* multicast records here. Later we may want to change to count interface-specific records separately. (This count includes records on the DuplicateRecords list too.)
- mDNSu32 NumAllInterfaceQuestions; // Right now we count *all* multicast questions here. Later we may want to change to count interface-specific questions separately.
+
+#if BONJOUR_ON_DEMAND
+ // Counters used in Bonjour on Demand logic.
+ mDNSu32 NumAllInterfaceRecords; // Right now we count *all* multicast records here. Later we may want to change to count interface-specific records separately. (This count includes records on the DuplicateRecords list too.)
+ mDNSu32 NumAllInterfaceQuestions; // Right now we count *all* multicast questions here. Later we may want to change to count interface-specific questions separately.
+#endif // BONJOUR_ON_DEMAND
+
DNSSECStatistics DNSSECStats;
mDNSStatistics mDNSStats;
@@ -2501,6 +2521,9 @@ extern const mDNSInterfaceID mDNSInterface_Unicast; // Special value
extern const mDNSInterfaceID mDNSInterfaceMark; // Special value
extern const mDNSInterfaceID mDNSInterface_P2P; // Special value
extern const mDNSInterfaceID uDNSInterfaceMark; // Special value
+extern const mDNSInterfaceID mDNSInterface_BLE; // Special value
+
+#define LocalOnlyOrP2PInterface(INTERFACE) ((INTERFACE == mDNSInterface_LocalOnly) || (INTERFACE == mDNSInterface_P2P) || (INTERFACE == mDNSInterface_BLE))
extern const mDNSIPPort DiscardPort;
extern const mDNSIPPort SSHPort;
@@ -2542,6 +2565,8 @@ extern const mDNSOpaque16 DNSSecQFlags;
extern const mDNSOpaque16 ResponseFlags;
extern const mDNSOpaque16 UpdateReqFlags;
extern const mDNSOpaque16 UpdateRespFlags;
+extern const mDNSOpaque16 SubscribeFlags;
+extern const mDNSOpaque16 UnSubscribeFlags;
extern const mDNSOpaque64 zeroOpaque64;
@@ -2606,7 +2631,7 @@ mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v)
// Every client should call mDNS_Init, passing in storage for the mDNS object and the mDNS_PlatformSupport object.
//
// Clients that are only advertising services should use mDNS_Init_NoCache and mDNS_Init_ZeroCacheSize.
-// Clients that plan to perform queries (mDNS_StartQuery, mDNS_StartBrowse, mDNS_StartResolveService, etc.)
+// Clients that plan to perform queries (mDNS_StartQuery, mDNS_StartBrowse, etc.)
// need to provide storage for the resource record cache, or the query calls will return 'mStatus_NoCache'.
// The rrcachestorage parameter is the address of memory for the resource record cache, and
// the rrcachesize parameter is the number of entries in the CacheRecord array passed in.
@@ -2719,11 +2744,6 @@ typedef enum { mDNS_Dereg_normal, mDNS_Dereg_rapid, mDNS_Dereg_conflict, mDNS_De
// mDNS_RegisterService is a single call to register the set of resource records associated with a given named service.
//
-// mDNS_StartResolveService is single call which is equivalent to multiple calls to mDNS_StartQuery,
-// to find the IP address, port number, and demultiplexing information for a given named service.
-// As with mDNS_StartQuery, it executes asynchronously, and calls the ServiceInfoQueryCallback when the answer is
-// found. After the service is resolved, the client should call mDNS_StopResolveService to complete the transaction.
-// The client can also call mDNS_StopResolveService at any time to abort the transaction.
//
// mDNS_AddRecordToService adds an additional record to a Service Record Set. This record may be deregistered
// via mDNS_RemoveRecordFromService, or by deregistering the service. mDNS_RemoveRecordFromService is passed a
@@ -2753,6 +2773,7 @@ enum
coreFlagWakeOnly = 0x8 // Service won't be registered with sleep proxy
};
+extern mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType);
extern mStatus mDNS_RegisterService (mDNS *const m, ServiceRecordSet *sr,
const domainlabel *const name, const domainname *const type, const domainname *const domain,
const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
@@ -2780,8 +2801,6 @@ extern mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
mDNSQuestionCallback *Callback, void *Context);
#define mDNS_StopBrowse mDNS_StopQuery
-extern mStatus mDNS_StartResolveService(mDNS *const m, ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context);
-extern void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *query);
typedef enum
{
@@ -2824,7 +2843,7 @@ extern mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question);
// because that object is defined to be 256 bytes long, but not all domainname objects are truly the full size.
// This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid.
#define AssignDomainName(DST, SRC) do { mDNSu16 len__ = DomainNameLength((SRC)); \
- if (len__ <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len__);else (DST)->c[0] = 0;} while(0)
+ if (len__ <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len__); else (DST)->c[0] = 0; } while(0)
// Comparison functions
#define SameDomainLabelCS(A,B) ((A)[0] == (B)[0] && mDNSPlatformMemSame((A)+1, (B)+1, (A)[0]))
@@ -2906,7 +2925,7 @@ extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel
// then the output will be truncated by one character to allow space for the terminating null.
// Unlike standard C vsnprintf/snprintf, they return the number of characters *actually* written,
// not the number of characters that *would* have been printed were buflen unlimited.
-extern mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg);
+extern mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg) IS_A_PRINTF_STYLE_FUNCTION(3,0);
extern mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4);
extern mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id);
extern char *DNSTypeName(mDNSu16 rrtype);
@@ -3095,14 +3114,14 @@ extern mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCache
extern mStatus mDNSPlatformInit (mDNS *const m);
extern void mDNSPlatformClose (mDNS *const m);
extern mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
- mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
+ mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
mDNSIPPort dstport, mDNSBool useBackgroundTrafficClass);
-extern mDNSBool mDNSPlatformPeekUDP (mDNS *const m, UDPSocket *src);
extern void mDNSPlatformLock (const mDNS *const m);
extern void mDNSPlatformUnlock (const mDNS *const m);
extern void mDNSPlatformStrCopy ( void *dst, const void *src);
+extern mDNSu32 mDNSPlatformStrLCopy ( void *dst, const void *src, mDNSu32 len);
extern mDNSu32 mDNSPlatformStrLen ( const void *src);
extern void mDNSPlatformMemCopy ( void *dst, const void *src, mDNSu32 len);
extern mDNSBool mDNSPlatformMemSame (const void *dst, const void *src, mDNSu32 len);
@@ -3199,7 +3218,8 @@ extern void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNS
extern mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti);
extern mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr);
extern mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname);
-extern mStatus mDNSPlatformClearSPSMACAddr(void);
+extern mStatus mDNSPlatformClearSPSData(void);
+extern mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage *msg, int length);
// mDNSPlatformTLSSetupCerts/mDNSPlatformTLSTearDownCerts used by dnsextd
extern mStatus mDNSPlatformTLSSetupCerts(void);
@@ -3220,7 +3240,7 @@ extern void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID In
extern mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID);
extern mDNSBool mDNSPlatformInterfaceIsAWDL(const NetworkInterfaceInfo *intf);
extern mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
-extern mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf);
+extern mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID);
extern mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf);
extern void mDNSPlatformFormatTime(unsigned long t, mDNSu8 *buf, int bufsize);
@@ -3315,7 +3335,7 @@ extern void RetrySearchDomainQuestions(mDNS *const m);
extern mDNSBool DomainEnumQuery(const domainname *qname);
extern mStatus UpdateKeepaliveRData(mDNS *const m, AuthRecord *rr, NetworkInterfaceInfo *const intf, mDNSBool updateMac, char *ethAddr);
extern void UpdateKeepaliveRMACAsync(mDNS *const m, void *context);
-extern void UpdateRMACCallback(mDNS *const m, void *context);
+extern void UpdateRMAC(mDNS *const m, void *context);
// Used only in logging to restrict the number of /etc/hosts entries printed
extern void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result);
@@ -3353,16 +3373,13 @@ extern void mDNSPlatformCloseDNSProxySkts(mDNS *const m);
extern void mDNSPlatformDisposeProxyContext(void *context);
extern mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *start, mDNSu8 *limit);
-// Sleep Assertions are specific to Mac OS X
#if APPLE_OSX_mDNSResponder
-extern void mDNSPlatformSleepAssertion(mDNS *const m, double timeout);
-#endif
-
extern void mDNSPlatformGetDNSRoutePolicy(mDNS *const m, DNSQuestion *q, mDNSBool *isBlocked);
-extern void mDNSPlatformSetuDNSSocktOpt(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q);
+#endif
+extern void mDNSPlatformSetSocktOpt(void *sock, mDNSTransport_Type transType, mDNSAddr_Type addrType, DNSQuestion *q);
extern mDNSs32 mDNSPlatformGetPID(void);
extern mDNSBool mDNSValidKeepAliveRecord(AuthRecord *rr);
-
+
// ***************************************************************************
#if 0
#pragma mark -
@@ -3578,18 +3595,17 @@ struct CompileTimeAssertionChecks_mDNS
char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1208) ? 1 : -1];
char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 232) ? 1 : -1];
char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 232) ? 1 : -1];
- char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 864) ? 1 : -1];
+ char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 894) ? 1 : -1];
- char sizecheck_ZoneData [(sizeof(ZoneData) <= 1700) ? 1 : -1];
+ char sizecheck_ZoneData [(sizeof(ZoneData) <= 1730) ? 1 : -1];
char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 200) ? 1 : -1];
char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3050) ? 1 : -1];
- char sizecheck_DNSServer [(sizeof(DNSServer) <= 340) ? 1 : -1];
- char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 7184) ? 1 : -1];
+ char sizecheck_DNSServer [(sizeof(DNSServer) <= 330) ? 1 : -1];
+ char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 7272) ? 1 : -1];
char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5540) ? 1 : -1];
char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7888) ? 1 : -1];
- char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 3488) ? 1 : -1];
#if APPLE_OSX_mDNSResponder
- char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1208) ? 1 : -1];
+ char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1230) ? 1 : -1];
#endif
};
@@ -3599,10 +3615,57 @@ mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr);
#if APPLE_OSX_mDNSResponder
extern void D2D_start_advertising_interface(NetworkInterfaceInfo *interface);
extern void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface);
+extern void D2D_start_advertising_record(AuthRecord *ar);
+extern void D2D_stop_advertising_record(AuthRecord *ar);
+#else
+#define D2D_start_advertising_interface(X)
+#define D2D_stop_advertising_interface(X)
+#define D2D_start_advertising_record(X)
+#define D2D_stop_advertising_record(X)
#endif
// ***************************************************************************
+#ifdef __rtems__
+typedef struct
+{
+ // Client API fields: The client must set up name and InterfaceID *before* calling mDNS_StartResolveService()
+ // When the callback is invoked, ip, port, TXTlen and TXTinfo will have been filled in with the results learned from the network.
+ domainname name;
+ mDNSInterfaceID InterfaceID; // ID of the interface the response was received on
+ mDNSAddr ip; // Remote (destination) IP address where this service can be accessed
+ mDNSIPPort port; // Port where this service can be accessed
+ mDNSu16 TXTlen;
+ mDNSu8 TXTinfo[2048]; // Additional demultiplexing information (e.g. LPR queue name)
+} ServiceInfo;
+
+// Note: Within an mDNSServiceInfoQueryCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
+typedef struct ServiceInfoQuery_struct ServiceInfoQuery;
+typedef void mDNSServiceInfoQueryCallback (mDNS *const m, ServiceInfoQuery *query);
+struct ServiceInfoQuery_struct
+{
+ // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
+ // No fields need to be set up by the client prior to calling mDNS_StartResolveService();
+ // all required data is passed as parameters to that function.
+ // The ServiceInfoQuery structure memory is working storage for mDNSCore to discover the requested information
+ // and place it in the ServiceInfo structure. After the client has called mDNS_StopResolveService(), it may
+ // dispose of the ServiceInfoQuery structure while retaining the results in the ServiceInfo structure.
+ DNSQuestion qSRV;
+ DNSQuestion qTXT;
+ DNSQuestion qAv4;
+ DNSQuestion qAv6;
+ mDNSu8 GotSRV;
+ mDNSu8 GotTXT;
+ mDNSu8 GotADD;
+ mDNSu32 Answers;
+ ServiceInfo *info;
+ mDNSServiceInfoQueryCallback *ServiceInfoQueryCallback;
+ void *ServiceInfoQueryContext;
+};
+
+extern mStatus mDNS_StartResolveService(mDNS *const m, ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context);
+extern void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *query);
+#endif /* __rtems__ */
#ifdef __cplusplus
}
#endif
diff --git a/mDNSResponder/mDNSCore/nsec3.c b/mDNSResponder/mDNSCore/nsec3.c
index c16a42d5..4e9e8c82 100644
--- a/mDNSResponder/mDNSCore/nsec3.c
+++ b/mDNSResponder/mDNSCore/nsec3.c
@@ -238,7 +238,7 @@ mDNSlocal mDNSBool NSEC3Find(mDNS *const m, NSEC3FindValues val, CacheRecord *nc
name = SkipLeadingLabels(origName, i);
if (!NSEC3HashName(name, nsec3, mDNSNULL, 0, hashName, &hlen))
{
- LogMsg("NSEC3Find: NSEC3HashName failed for ##s", name->c);
+ LogMsg("NSEC3Find: NSEC3HashName failed for %##s", name->c);
continue;
}
@@ -708,7 +708,7 @@ mDNSexport CacheRecord *NSEC3RecordIsDelegation(mDNS *const m, domainname *name,
if (!NSEC3HashName(name, nsec3, mDNSNULL, 0, hashName, &hlen))
{
- LogMsg("NSEC3RecordIsDelegation: NSEC3HashName failed for ##s", name->c);
+ LogMsg("NSEC3RecordIsDelegation: NSEC3HashName failed for %##s", name->c);
return mDNSNULL;
}
diff --git a/mDNSResponder/mDNSCore/uDNS.c b/mDNSResponder/mDNSCore/uDNS.c
index 3ba88b5c..694c745c 100755
--- a/mDNSResponder/mDNSCore/uDNS.c
+++ b/mDNSResponder/mDNSCore/uDNS.c
@@ -124,7 +124,7 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
return mDNSNULL;
}
- if (!d)
+ if (!d)
d = (const domainname *)"";
LogInfo("mDNS_AddDNSServer(%d): Adding %#a for %##s, InterfaceID %p, serviceID %u, scoped %d, resGroupID %d req_A is %s req_AAAA is %s cell %s req_DO is %s",
@@ -135,11 +135,11 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
while (*p) // Check if we already have this {interface,address,port,domain} tuple registered + reqA/reqAAAA bits
{
- if ((*p)->scoped == scoped && (*p)->interface == interface && (*p)->serviceID == serviceID && (*p)->teststate != DNSServer_Disabled &&
- mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d) &&
+ if ((*p)->scoped == scoped && (*p)->interface == interface && (*p)->serviceID == serviceID &&
+ mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d) &&
(*p)->req_A == reqA && (*p)->req_AAAA == reqAAAA)
{
- if (!((*p)->flags & DNSServer_FlagDelete))
+ if (!((*p)->flags & DNSServer_FlagDelete))
debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr, mDNSVal16(port), d->c, interface);
tmp = *p;
*p = tmp->next;
@@ -192,8 +192,6 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
(*p)->addr = *addr;
(*p)->port = port;
(*p)->flags = DNSServer_FlagNew;
- (*p)->teststate = /* DNSServer_Untested */ DNSServer_Passed;
- (*p)->lasttest = m->timenow - INIT_UCAST_POLL_INTERVAL;
(*p)->timeout = timeout;
(*p)->cellIntf = cellIntf;
(*p)->req_A = reqA;
@@ -208,11 +206,13 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
(*p)->next = mDNSNULL;
}
}
- (*p)->penaltyTime = 0;
- // We always update the ID (not just when we allocate a new instance) because we could
- // be adding a new non-scoped resolver with a new ID and we want all the non-scoped
- // resolvers belong to the same group.
- (*p)->resGroupID = resGroupID;
+ if (*p) {
+ (*p)->penaltyTime = 0;
+ // We always update the ID (not just when we allocate a new instance) because we could
+ // be adding a new non-scoped resolver with a new ID and we want all the non-scoped
+ // resolvers belong to the same group.
+ (*p)->resGroupID = resGroupID;
+ }
return(*p);
}
@@ -224,7 +224,7 @@ mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 re
DNSServer *new;
DNSServer *orig = q->qDNSServer;
mDNSu8 rcode = '\0';
-
+
mDNS_CheckLock(m);
LogInfo("PenalizeDNSServer: Penalizing DNS server %#a question for question %p %##s (%s) SuppressUnusable %d",
@@ -234,11 +234,11 @@ mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 re
// return the error, then return the first error.
if (mDNSOpaque16IsZero(q->responseFlags))
q->responseFlags = responseFlags;
-
+
rcode = (mDNSu8)(responseFlags.b[1] & kDNSFlag1_RC_Mask);
// After we reset the qDNSServer to NULL, we could get more SERV_FAILS that might end up
- // peanlizing again.
+ // penalizing again.
if (!q->qDNSServer)
goto end;
@@ -482,7 +482,7 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
mDNSlocal mStatus uDNS_RequestAddress(mDNS *m)
{
mStatus err = mStatus_NoError;
-
+
if (!m->NATTraversals)
{
m->retryGetAddr = NonZeroTime(m->timenow + 0x78000000);
@@ -497,7 +497,7 @@ mDNSlocal mStatus uDNS_RequestAddress(mDNS *m)
mDNSu8* end = start + sizeof(NATAddrRequest);
err = mDNSPlatformSendUDP(m, start, end, 0, mDNSNULL, &m->Router, NATPMPPort, mDNSfalse);
debugf("uDNS_RequestAddress: Sent NAT-PMP external address request %d", err);
-
+
#ifdef _LEGACY_NAT_TRAVERSAL_
if (mDNSIPPortIsZero(m->UPnPRouterPort) || mDNSIPPortIsZero(m->UPnPSOAPPort))
{
@@ -509,7 +509,7 @@ mDNSlocal mStatus uDNS_RequestAddress(mDNS *m)
mStatus lnterr = LNT_GetExternalAddress(m);
if (lnterr)
LogMsg("uDNS_RequestAddress: LNT_GetExternalAddress returned error %d", lnterr);
-
+
err = err ? err : lnterr; // NAT-PMP error takes precedence
}
#endif // _LEGACY_NAT_TRAVERSAL_
@@ -554,7 +554,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP
LogMsg("uDNS_SendNATMsg called unexpectedly with NULL info");
return mStatus_BadParamErr;
}
-
+
// send msg if the router's address is private (which means it's non-zero)
if (mDNSv4AddrIsRFC1918(&m->Router.ip.v4))
{
@@ -567,7 +567,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP
static NATPortMapRequest NATPortReq;
static const mDNSu8* end = (mDNSu8 *)&NATPortReq + sizeof(NATPortMapRequest);
mDNSu8 *p = (mDNSu8 *)&NATPortReq.NATReq_lease;
-
+
NATPortReq.vers = NATMAP_VERS;
NATPortReq.opcode = info->Protocol;
NATPortReq.unused = zeroID;
@@ -577,7 +577,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP
p[1] = (mDNSu8)((info->NATLease >> 16) & 0xFF);
p[2] = (mDNSu8)((info->NATLease >> 8) & 0xFF);
p[3] = (mDNSu8)( info->NATLease & 0xFF);
-
+
err = mDNSPlatformSendUDP(m, (mDNSu8 *)&NATPortReq, end, 0, mDNSNULL, &m->Router, NATPMPPort, mDNSfalse);
debugf("uDNS_SendNATMsg: Sent NAT-PMP mapping request %d", err);
}
@@ -604,31 +604,31 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP
mDNSu8* start = (mDNSu8*)&req;
mDNSu8* end = start + sizeof(req);
mDNSu8* p = (mDNSu8*)&req.lifetime;
-
+
req.version = PCP_VERS;
req.opCode = PCPOp_Map;
req.reserved = zeroID;
-
+
p[0] = (mDNSu8)((info->NATLease >> 24) & 0xFF);
p[1] = (mDNSu8)((info->NATLease >> 16) & 0xFF);
p[2] = (mDNSu8)((info->NATLease >> 8) & 0xFF);
p[3] = (mDNSu8)( info->NATLease & 0xFF);
-
+
mDNSAddrMapIPv4toIPv6(&m->AdvertisedV4.ip.v4, &req.clientAddr);
-
+
req.nonce[0] = m->PCPNonce[0];
req.nonce[1] = m->PCPNonce[1];
req.nonce[2] = m->PCPNonce[2];
-
+
req.protocol = (info->Protocol == NATOp_MapUDP ? PCPProto_UDP : PCPProto_TCP);
-
+
req.reservedMapOp[0] = 0;
req.reservedMapOp[1] = 0;
req.reservedMapOp[2] = 0;
-
+
req.intPort = info->Protocol ? info->IntPort : DiscardPort;
req.extPort = info->RequestedPort;
-
+
// Since we only support IPv4, even if using the all-zeros address, map it, so
// the PCP gateway will give us an IPv4 address & not an IPv6 address.
mDNSAddrMapIPv4toIPv6(&info->NewAddress, &req.extAddress);
@@ -654,7 +654,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP
mStatus lnterr = LNT_MapPort(m, info);
if (lnterr)
LogMsg("uDNS_SendNATMsg: LNT_MapPort returned error %d", lnterr);
-
+
err = err ? err : lnterr; // PCP error takes precedence
}
#endif // _LEGACY_NAT_TRAVERSAL_
@@ -727,7 +727,7 @@ mDNSexport void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv
m->NextScheduledNATOp = m->retryGetAddr;
last_err = err;
-
+
for (n = m->NATTraversals; n; n=n->next)
{
// We should change n->NewAddress only when n is one of:
@@ -924,7 +924,7 @@ mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *tra
{
traversal->NATLease = 0;
traversal->retryInterval = 0;
-
+
// In case we most recently sent NAT-PMP, we need to set sentNATPMP to false so
// that we'll send a NAT-PMP request to destroy the mapping. We do this because
// the NATTraversal struct has already been cut from the list, and the client
@@ -940,7 +940,7 @@ mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *tra
// would have requested an IPv4 address.
traversal->RequestedPort = zeroIPPort;
traversal->NewAddress = zerov4Addr;
-
+
uDNS_SendNATMsg(m, traversal, traversal->lastSuccessfulProtocol != NATTProtocolNATPMP);
}
@@ -1573,6 +1573,7 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
}
if (!info->sock) { LogMsg("MakeTCPConn: unable to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
+ mDNSPlatformSetSocktOpt(info->sock, mDNSTransport_TCP, Addr->type, question);
err = mDNSPlatformTCPConnect(info->sock, Addr, Port, hostname, (question ? question->InterfaceID : mDNSNULL), tcpCallback, info);
// Probably suboptimal here.
@@ -1703,6 +1704,7 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
}
}
+
// forward declaration so GetServiceTarget can do reverse lookup if needed
mDNSlocal void GetStaticHostname(mDNS *m);
@@ -1754,11 +1756,13 @@ mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE = (const domainname*)"\x
mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp";
mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE = (const domainname*)"\x0E_dns-query-tls" "\x04_tcp";
mDNSlocal const domainname *PRIVATE_LLQ_SERVICE_TYPE = (const domainname*)"\x0C_dns-llq-tls" "\x04_tcp";
+mDNSlocal const domainname *DNS_PUSH_NOTIFICATION_SERVICE_TYPE = (const domainname*)"\x0C_dns-push-tls" "\x04_tcp";
#define ZoneDataSRV(X) ( \
- (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
- (X)->ZoneService == ZoneServiceQuery ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE : (const domainname*)"" ) : \
- (X)->ZoneService == ZoneServiceLLQ ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE : PUBLIC_LLQ_SERVICE_TYPE ) : (const domainname*)"")
+ (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
+ (X)->ZoneService == ZoneServiceQuery ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE : (const domainname*)"" ) : \
+ (X)->ZoneService == ZoneServiceLLQ ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE : PUBLIC_LLQ_SERVICE_TYPE ) : \
+ (X)->ZoneService == ZoneServiceDNSPush ? DNS_PUSH_NOTIFICATION_SERVICE_TYPE : (const domainname*)"")
// Forward reference: GetZoneData_StartQuery references GetZoneData_QuestionCallback, and
// GetZoneData_QuestionCallback calls GetZoneData_StartQuery
@@ -1886,7 +1890,7 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt
zd->question.InterfaceID = mDNSInterface_Any;
zd->question.flags = 0;
zd->question.Target = zeroAddr;
- //zd->question.qname.c[0] = 0; // Already set
+ //zd->question.qname.c[0] = 0; // Already set
zd->question.qtype = qtype;
zd->question.qclass = kDNSClass_IN;
zd->question.LongLived = mDNSfalse;
@@ -1894,8 +1898,6 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt
zd->question.ForceMCast = mDNSfalse;
zd->question.ReturnIntermed = mDNStrue;
zd->question.SuppressUnusable = mDNSfalse;
- zd->question.DenyOnCellInterface = mDNSfalse;
- zd->question.DenyOnExpInterface = mDNSfalse;
zd->question.SearchListIndex = 0;
zd->question.AppendSearchDomains = 0;
zd->question.RetryWithSearchDomains = mDNSfalse;
@@ -2171,7 +2173,7 @@ mDNSlocal void StartRecordNatMap(mDNS *m, AuthRecord *rr)
else { LogMsg("StartRecordNatMap: could not determine transport protocol of service %##s", rr->resrec.name->c); return; }
//LogMsg("StartRecordNatMap: clientContext %p IntPort %d srv.port %d %s",
- // rr->NATinfo.clientContext, mDNSVal16(rr->NATinfo.IntPort), mDNSVal16(rr->resrec.rdata->u.srv.port), ARDisplayString(m, rr));
+ // rr->NATinfo.clientContext, mDNSVal16(rr->NATinfo.IntPort), mDNSVal16(rr->resrec.rdata->u.srv.port), ARDisplayString(m, rr));
if (rr->NATinfo.clientContext) mDNS_StopNATOperation_internal(m, &rr->NATinfo);
rr->NATinfo.Protocol = protocol;
@@ -2584,8 +2586,6 @@ mDNSlocal void GetStaticHostname(mDNS *m)
q->ForceMCast = mDNSfalse;
q->ReturnIntermed = mDNStrue;
q->SuppressUnusable = mDNSfalse;
- q->DenyOnCellInterface = mDNSfalse;
- q->DenyOnExpInterface = mDNSfalse;
q->SearchListIndex = 0;
q->AppendSearchDomains = 0;
q->RetryWithSearchDomains = mDNSfalse;
@@ -2645,12 +2645,30 @@ mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
// below could free the memory, and we have to make sure we don't touch hi fields after that.
mDNSBool f4 = hi->arv4.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv4.state != regState_Unregistered;
mDNSBool f6 = hi->arv6.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv6.state != regState_Unregistered;
- if (f4) LogInfo("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn);
- if (f6) LogInfo("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn);
*ptr = (*ptr)->next; // unlink
- if (f4) mDNS_Deregister_internal(m, &hi->arv4, mDNS_Dereg_normal);
- if (f6) mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal);
- // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback
+ if (f4 || f6)
+ {
+ if (f4)
+ {
+ LogInfo("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn);
+ mDNS_Deregister_internal(m, &hi->arv4, mDNS_Dereg_normal);
+ }
+ if (f6)
+ {
+ LogInfo("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn);
+ mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal);
+ }
+ // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback
+ }
+ else
+ {
+ if (hi->natinfo.clientContext)
+ {
+ mDNS_StopNATOperation_internal(m, &hi->natinfo);
+ hi->natinfo.clientContext = mDNSNULL;
+ }
+ mDNSPlatformMemFree(hi);
+ }
}
mDNS_CheckLock(m);
m->NextSRVUpdate = NonZeroTime(m->timenow);
@@ -3621,13 +3639,13 @@ mDNSlocal void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interface
// Minimum NAT-PMP packet is vers (1) opcode (1) + err (2) = 4 bytes
if (len < 4) { LogMsg("NAT-PMP message too short (%d bytes)", len); return; }
-
+
// Read multi-byte error value (field is identical in a NATPortMapReply)
AddrReply->err = (mDNSu16) ((mDNSu16)pkt[2] << 8 | pkt[3]);
-
+
if (AddrReply->err == NATErr_Vers)
{
- NATTraversalInfo *n;
+ NATTraversalInfo *n;
LogInfo("NAT-PMP version unsupported message received");
for (n = m->NATTraversals; n; n=n->next)
{
@@ -3635,7 +3653,7 @@ mDNSlocal void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interface
// and update the state variables
uDNS_SendNATMsg(m, n, mDNSfalse);
}
-
+
m->NextScheduledNATOp = m->timenow;
return;
@@ -3649,7 +3667,7 @@ mDNSlocal void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interface
LogMsg("NAT-PMP message too short (%d bytes) 0x%X 0x%X", len, AddrReply->opcode, AddrReply->err);
return;
}
-
+
// Read multi-byte upseconds value (field is identical in a NATPortMapReply)
AddrReply->upseconds = (mDNSs32) ((mDNSs32)pkt[4] << 24 | (mDNSs32)pkt[5] << 16 | (mDNSs32)pkt[6] << 8 | pkt[7]);
@@ -3726,16 +3744,16 @@ mDNSlocal void uDNS_ReceivePCPPacket(mDNS *m, const mDNSInterfaceID InterfaceID,
mDNSu8 protocol = 0;
mDNSIPPort intport = zeroIPPort;
mDNSIPPort extport = zeroIPPort;
-
+
// Minimum PCP packet is 24 bytes
if (len < 24)
{
LogMsg("uDNS_ReceivePCPPacket: message too short (%d bytes)", len);
return;
}
-
+
strippedOpCode = reply->opCode & 0x7f;
-
+
if ((reply->opCode & 0x80) == 0x00 || (strippedOpCode != PCPOp_Announce && strippedOpCode != PCPOp_Map))
{
LogMsg("uDNS_ReceivePCPPacket: unhandled opCode %u", reply->opCode);
@@ -3774,11 +3792,11 @@ mDNSlocal void uDNS_ReceivePCPPacket(mDNS *m, const mDNSInterfaceID InterfaceID,
if (strippedOpCode == PCPOp_Announce)
return;
-
+
// We globally keep track of the most recent error code for mappings.
// This seems bad to do with PCP, but best not change it now.
m->LastNATMapResultCode = reply->result;
-
+
if (!reply->result)
{
if (len < sizeof(PCPMapReply))
@@ -3786,7 +3804,7 @@ mDNSlocal void uDNS_ReceivePCPPacket(mDNS *m, const mDNSInterfaceID InterfaceID,
LogMsg("uDNS_ReceivePCPPacket: mapping response too short (%d bytes)", len);
return;
}
-
+
// Check the nonce
if (reply->nonce[0] != m->PCPNonce[0] || reply->nonce[1] != m->PCPNonce[1] || reply->nonce[2] != m->PCPNonce[2])
{
@@ -3825,7 +3843,7 @@ mDNSlocal void uDNS_ReceivePCPPacket(mDNS *m, const mDNSInterfaceID InterfaceID,
{
LogInfo("uDNS_ReceivePCPPacket: error received from server. opcode %X result %X lifetime %X epoch %X",
reply->opCode, reply->result, reply->lifetime, reply->epoch);
-
+
// If the packet is long enough, get the protocol & intport for matching to report
// the error
if (len >= sizeof(PCPMapReply))
@@ -3858,135 +3876,6 @@ mDNSexport void uDNS_ReceiveNATPacket(mDNS *m, const mDNSInterfaceID InterfaceID
LogMsg("uDNS_ReceiveNATPacket: packet with version %u (expected %u or %u)", pkt[0], PCP_VERS, NATMAP_VERS);
}
-// <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
-// <rdar://problem/4288449> Add check to avoid crashing NAT gateways that have buggy DNS relay code
-//
-// We know of bugs in home NAT gateways that cause them to crash if they receive certain DNS queries.
-// The DNS queries that make them crash are perfectly legal DNS queries, but even if they weren't,
-// the gateway shouldn't crash -- in today's world of viruses and network attacks, software has to
-// be written assuming that a malicious attacker could send them any packet, properly-formed or not.
-// Still, we don't want to be crashing people's home gateways, so we go out of our way to avoid
-// the queries that crash them.
-//
-// Some examples:
-//
-// 1. Any query where the name ends in ".in-addr.arpa." and the text before this is 32 or more bytes.
-// The query type does not need to be PTR -- the gateway will crash for any query type.
-// e.g. "ping long-name-crashes-the-buggy-router.in-addr.arpa" will crash one of these.
-//
-// 2. Any query that results in a large response with the TC bit set.
-//
-// 3. Any PTR query that doesn't begin with four decimal numbers.
-// These gateways appear to assume that the only possible PTR query is a reverse-mapping query
-// (e.g. "1.0.168.192.in-addr.arpa") and if they ever get a PTR query where the first four
-// labels are not all decimal numbers in the range 0-255, they handle that by crashing.
-// These gateways also ignore the remainder of the name following the four decimal numbers
-// -- whether or not it actually says in-addr.arpa, they just make up an answer anyway.
-//
-// The challenge therefore is to craft a query that will discern whether the DNS server
-// is one of these buggy ones, without crashing it. Furthermore we don't want our test
-// queries making it all the way to the root name servers, putting extra load on those
-// name servers and giving Apple a bad reputation. To this end we send this query:
-// dig -t ptr 1.0.0.127.dnsbugtest.1.0.0.127.in-addr.arpa.
-//
-// The text preceding the ".in-addr.arpa." is under 32 bytes, so it won't cause crash (1).
-// It will not yield a large response with the TC bit set, so it won't cause crash (2).
-// It starts with four decimal numbers, so it won't cause crash (3).
-// The name falls within the "1.0.0.127.in-addr.arpa." domain, the reverse-mapping name for the local
-// loopback address, and therefore the query will black-hole at the first properly-configured DNS server
-// it reaches, making it highly unlikely that this query will make it all the way to the root.
-//
-// Finally, the correct response to this query is NXDOMAIN or a similar error, but the
-// gateways that ignore the remainder of the name following the four decimal numbers
-// give themselves away by actually returning a result for this nonsense query.
-
-mDNSlocal const domainname *DNSRelayTestQuestion = (const domainname*)
- "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
- "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
-
-// See comments above for DNSRelayTestQuestion
-// If this is the kind of query that has the risk of crashing buggy DNS servers, we do a test question first
-mDNSlocal mDNSBool NoTestQuery(DNSQuestion *q)
-{
- int i;
- mDNSu8 *p = q->qname.c;
- if (q->AuthInfo) return(mDNStrue); // Don't need a test query for private queries sent directly to authoritative server over TLS/TCP
- if (q->qtype != kDNSType_PTR) return(mDNStrue); // Don't need a test query for any non-PTR queries
- for (i=0; i<4; i++) // If qname does not begin with num.num.num.num, can't skip the test query
- {
- if (p[0] < 1 || p[0] > 3) return(mDNSfalse);
- if ( p[1] < '0' || p[1] > '9' ) return(mDNSfalse);
- if (p[0] >= 2 && (p[2] < '0' || p[2] > '9')) return(mDNSfalse);
- if (p[0] >= 3 && (p[3] < '0' || p[3] > '9')) return(mDNSfalse);
- p += 1 + p[0];
- }
- // If remainder of qname is ".in-addr.arpa.", this is a vanilla reverse-mapping query and
- // we can safely do it without needing a test query first, otherwise we need the test query.
- return(SameDomainName((domainname*)p, (const domainname*)"\x7" "in-addr" "\x4" "arpa"));
-}
-
-// Returns mDNStrue if response was handled
-mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
- const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
-{
- const mDNSu8 *ptr = msg->data;
- DNSQuestion pktq;
- DNSServer *s;
- mDNSu32 result = 0;
-
- // 1. Find out if this is an answer to one of our test questions
- if (msg->h.numQuestions != 1) return(mDNSfalse);
- ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &pktq);
- if (!ptr) return(mDNSfalse);
- if (pktq.qtype != kDNSType_PTR || pktq.qclass != kDNSClass_IN) return(mDNSfalse);
- if (!SameDomainName(&pktq.qname, DNSRelayTestQuestion)) return(mDNSfalse);
-
- // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
- // else, if the DNS relay gave us an error or no-answer response, it passed our test
- if ((msg->h.flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0)
- result = DNSServer_Failed;
- else
- result = DNSServer_Passed;
-
- // 3. Find occurrences of this server in our list, and mark them appropriately
- for (s = m->DNSServers; s; s = s->next)
- {
- mDNSBool matchaddr = (s->teststate != result && mDNSSameAddress(srcaddr, &s->addr) && mDNSSameIPPort(srcport, s->port));
- mDNSBool matchid = (s->teststate == DNSServer_Untested && mDNSSameOpaque16(msg->h.id, s->testid));
- if (matchaddr || matchid)
- {
- DNSQuestion *q;
- s->teststate = result;
- if (result == DNSServer_Passed)
- {
- LogInfo("DNS Server %#a:%d (%#a:%d) %d passed%s",
- &s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid),
- matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent");
- }
- else
- {
- LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d (%#a:%d) %d%s",
- &s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid),
- matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent");
- }
-
- // If this server has just changed state from DNSServer_Untested to DNSServer_Passed, then retrigger any waiting questions.
- // We use the NoTestQuery() test so that we only retrigger questions that were actually blocked waiting for this test to complete.
- if (result == DNSServer_Passed) // Unblock any questions that were waiting for this result
- for (q = m->Questions; q; q=q->next)
- if (q->qDNSServer == s && !NoTestQuery(q))
- {
- q->ThisQInterval = INIT_UCAST_POLL_INTERVAL / QuestionIntervalStep;
- q->unansweredQueries = 0;
- q->LastQTime = m->timenow - q->ThisQInterval;
- m->NextScheduledQuery = m->timenow;
- }
- }
- }
-
- return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further
-}
-
// Called from mDNSCoreReceive with the lock held
mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
{
@@ -4015,7 +3904,6 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
if (QR_OP == StdR)
{
//if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport)) return;
- if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, srcport)) return;
for (qptr = m->Questions; qptr; qptr = qptr->next)
if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW)
{
@@ -4037,7 +3925,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
mDNSs32 expire = m->timenow + (mDNSs32)lease * mDNSPlatformOneSecond;
mDNSu32 random = mDNSRandom((mDNSs32)lease * mDNSPlatformOneSecond/10);
- //rcode = kDNSFlag1_RC_ServFail; // Simulate server failure (rcode 2)
+ //rcode = kDNSFlag1_RC_ServFail; // Simulate server failure (rcode 2)
// Walk through all the records that matches the messageID. There could be multiple
// records if we had sent them in a group
@@ -4200,6 +4088,40 @@ mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneI
mDNS_Unlock(m);
}
+mDNSexport void DNSPushNotificationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
+{
+ DNSQuestion *q = (DNSQuestion *)zoneInfo->ZoneDataContext;
+ mDNS_Lock(m);
+
+ // If we get here it means that the GetZoneData operation has completed.
+ // We hold on to the zone data if it is AutoTunnel as we use the hostname
+ // in zoneInfo during the TLS connection setup.
+ q->servAddr = zeroAddr;
+ q->servPort = zeroIPPort;
+ if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr) && zoneInfo->Host.c[0])
+ {
+ q->dnsPushState = DNSPUSH_SERVERFOUND;
+ q->dnsPushServerAddr = zoneInfo->Addr;
+ q->dnsPushServerPort = zoneInfo->Port;
+ q->ntries = 0;
+ LogInfo("DNSPushNotificationGotZoneData %#a:%d", &q->dnsPushServerAddr, mDNSVal16(q->dnsPushServerPort));
+ SubscribeToDNSPushNotificationServer(m,q);
+ }
+ else
+ {
+ StartLLQPolling(m,q);
+ if (err == mStatus_NoSuchNameErr)
+ {
+ // this actually failed, so mark it by setting address to all ones
+ q->servAddr.type = mDNSAddrType_IPv4;
+ q->servAddr.ip.v4 = onesIPv4Addr;
+ q->dnsPushState = DNSPUSH_NOSERVER;
+ }
+ }
+ mDNS_Unlock(m);
+}
+
+
// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
{
@@ -4467,7 +4389,7 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
if (!rr->nta) { LogMsg("SendRecordDeregistration:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; }
err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->nta->Addr, rr->nta->Port, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err);
- //if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); // Don't touch rr after this
+ //if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); // Don't touch rr after this
}
SetRecordRetry(m, rr, 0);
return;
@@ -4690,17 +4612,35 @@ mDNSlocal void handle_unanswered_query(mDNS *const m)
if (!q->qDNSServer->req_DO)
{
- q->ValidationState = DNSSECValNotRequired;
+ q->ValidationState = DNSSECValNotRequired;
q->ValidationRequired = DNSSEC_VALIDATION_NONE;
-
+
if (q->ProxyQuestion)
q->ProxyDNSSECOK = mDNSfalse;
- LogInfo("handle_unanswered_query: unanswered query for %##s (%s), so turned off validation for %#a",
+ LogInfo("handle_unanswered_query: unanswered query for %##s (%s), so turned off validation for %#a",
q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr);
}
}
}
+mDNSlocal void uDNS_HandleLLQState(mDNS *const m, DNSQuestion *q)
+{
+ // First attempt to use DNS Push Notification.
+ if (q->dnsPushState == DNSPUSH_INIT)
+ DiscoverDNSPushNotificationServer(m, q);
+ switch (q->state)
+ {
+ case LLQ_InitialRequest: startLLQHandshake(m, q); break;
+ case LLQ_SecondaryRequest:
+ // For PrivateQueries, we need to start the handshake again as we don't do the Challenge/Response step
+ if (PrivateQuery(q)) startLLQHandshake(m, q);
+ else sendChallengeResponse(m, q, mDNSNULL);
+ break;
+ case LLQ_Established: sendLLQRefresh(m, q); break;
+ case LLQ_Poll: break; // Do nothing (handled below)
+ }
+}
+
// The question to be checked is not passed in as an explicit parameter;
// instead it is implicit that the question to be checked is m->CurrentQuestion.
mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
@@ -4710,22 +4650,10 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
if (q->LongLived)
{
- switch (q->state)
- {
- case LLQ_InitialRequest: startLLQHandshake(m, q); break;
- case LLQ_SecondaryRequest:
- // For PrivateQueries, we need to start the handshake again as we don't do the Challenge/Response step
- if (PrivateQuery(q))
- startLLQHandshake(m, q);
- else
- sendChallengeResponse(m, q, mDNSNULL);
- break;
- case LLQ_Established: sendLLQRefresh(m, q); break;
- case LLQ_Poll: break; // Do nothing (handled below)
- }
+ uDNS_HandleLLQState(m,q);
}
- handle_unanswered_query(m);
+ handle_unanswered_query(m);
// We repeat the check above (rather than just making this the "else" case) because startLLQHandshake can change q->state to LLQ_Poll
if (!(q->LongLived && q->state != LLQ_Poll))
{
@@ -4773,36 +4701,25 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
for (qptr = q->next ; qptr; qptr = qptr->next)
if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
}
- if (q->qDNSServer && q->qDNSServer->teststate != DNSServer_Disabled)
+ if (q->qDNSServer)
{
- mDNSu8 *end = m->omsg.data;
+ mDNSu8 *end;
mStatus err = mStatus_NoError;
mDNSBool private = mDNSfalse;
InitializeDNSMessage(&m->omsg.h, q->TargetQID, (DNSSECQuestion(q) ? DNSSecQFlags : uQueryFlags));
- if (q->qDNSServer->teststate != DNSServer_Untested || NoTestQuery(q))
- {
- end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
- if (DNSSECQuestion(q) && !q->qDNSServer->cellIntf)
- {
- if (q->ProxyQuestion)
- end = DNSProxySetAttributes(q, &m->omsg.h, &m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData);
- else
- end = putDNSSECOption(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData);
- }
- private = PrivateQuery(q);
- }
- else if (m->timenow - q->qDNSServer->lasttest >= INIT_UCAST_POLL_INTERVAL) // Make sure at least three seconds has elapsed since last test query
+ end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
+ if (DNSSECQuestion(q) && !q->qDNSServer->cellIntf)
{
- LogInfo("Sending DNS test query to %#a:%d", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port));
- q->ThisQInterval = INIT_UCAST_POLL_INTERVAL / QuestionIntervalStep;
- q->qDNSServer->lasttest = m->timenow;
- end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN);
- q->qDNSServer->testid = m->omsg.h.id;
+ if (q->ProxyQuestion)
+ end = DNSProxySetAttributes(q, &m->omsg.h, &m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData);
+ else
+ end = putDNSSECOption(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData);
}
+ private = PrivateQuery(q);
- if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q)))
+ if (end > m->omsg.data)
{
//LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, NextQSendTime(q) - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
if (private)
@@ -4820,7 +4737,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
{
q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
if (q->LocalSocket)
- mDNSPlatformSetuDNSSocktOpt(q->LocalSocket, &q->qDNSServer->addr, q);
+ mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, q->qDNSServer->addr.type, q);
}
if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time
else
@@ -4829,6 +4746,11 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
#if TARGET_OS_EMBEDDED
if (!err)
{
+ if (q->metrics.answered)
+ {
+ q->metrics.querySendCount = 0;
+ q->metrics.answered = mDNSfalse;
+ }
if (q->metrics.querySendCount++ == 0)
{
q->metrics.firstQueryTime = m->timenow;
@@ -4839,32 +4761,68 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
}
}
- if (err != mStatus_TransientErr) // if it is not a transient error backoff and DO NOT flood queries unnecessarily
+ if (err == mStatus_HostUnreachErr)
{
- q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep; // Only increase interval if send succeeded
- q->unansweredQueries++;
- if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL)
- q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
- if (private && q->state != LLQ_Poll)
+ DNSServer *newServer;
+
+ LogInfo("uDNS_CheckCurrentQuestion: host unreachable error for DNS server %#a for question [%p] %##s (%s)",
+ &q->qDNSServer->addr, q, q->qname.c, DNSTypeName(q->qtype));
+
+ if (!StrictUnicastOrdering)
{
- // We don't want to retransmit too soon. Hence, we always schedule our first
- // retransmisson at 3 seconds rather than one second
- if (q->ThisQInterval < (3 * mDNSPlatformOneSecond))
- q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep;
- if (q->ThisQInterval > LLQ_POLL_INTERVAL)
- q->ThisQInterval = LLQ_POLL_INTERVAL;
- LogInfo("uDNS_CheckCurrentQuestion: private non polling question for %##s (%s) will be retried in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
+ q->qDNSServer->penaltyTime = NonZeroTime(m->timenow + DNSSERVER_PENALTY_TIME);
}
- if (q->qDNSServer->cellIntf)
+
+ newServer = GetServerForQuestion(m, q);
+ DNSServerChangeForQuestion(m, q, newServer);
+
+ if (q->triedAllServersOnce)
+ {
+ q->LastQTime = m->timenow;
+ }
+ else
{
- // We don't want to retransmit too soon. Schedule our first retransmisson at
- // MIN_UCAST_RETRANS_TIMEOUT seconds.
- if (q->ThisQInterval < MIN_UCAST_RETRANS_TIMEOUT)
- q->ThisQInterval = MIN_UCAST_RETRANS_TIMEOUT;
+ q->ThisQInterval = InitialQuestionInterval;
+ q->LastQTime = m->timenow - q->ThisQInterval;
}
- debugf("uDNS_CheckCurrentQuestion: Increased ThisQInterval to %d for %##s (%s), cell %d", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer->cellIntf);
+ q->unansweredQueries = 0;
+ q->noServerResponse = 1;
+ }
+ else
+ {
+ if (err != mStatus_TransientErr) // if it is not a transient error backoff and DO NOT flood queries unnecessarily
+ {
+ // If all DNS Servers are not responding, then we back-off using the multiplier UDNSBackOffMultiplier(*2).
+ // Only increase interval if send succeeded
+
+ q->ThisQInterval = q->ThisQInterval * UDNSBackOffMultiplier;
+ if ((q->ThisQInterval > 0) && (q->ThisQInterval < MinQuestionInterval)) // We do not want to retx within 1 sec
+ q->ThisQInterval = MinQuestionInterval;
+
+ q->unansweredQueries++;
+ if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL)
+ q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
+ if (private && q->state != LLQ_Poll)
+ {
+ // We don't want to retransmit too soon. Hence, we always schedule our first
+ // retransmisson at 3 seconds rather than one second
+ if (q->ThisQInterval < (3 * mDNSPlatformOneSecond))
+ q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep;
+ if (q->ThisQInterval > LLQ_POLL_INTERVAL)
+ q->ThisQInterval = LLQ_POLL_INTERVAL;
+ LogInfo("uDNS_CheckCurrentQuestion: private non polling question for %##s (%s) will be retried in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
+ }
+ if (q->qDNSServer->cellIntf)
+ {
+ // We don't want to retransmit too soon. Schedule our first retransmisson at
+ // MIN_UCAST_RETRANS_TIMEOUT seconds.
+ if (q->ThisQInterval < MIN_UCAST_RETRANS_TIMEOUT)
+ q->ThisQInterval = MIN_UCAST_RETRANS_TIMEOUT;
+ }
+ debugf("uDNS_CheckCurrentQuestion: Increased ThisQInterval to %d for %##s (%s), cell %d", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer->cellIntf);
+ }
+ q->LastQTime = m->timenow;
}
- q->LastQTime = m->timenow;
SetNextQueryTime(m, q);
}
else
@@ -4927,7 +4885,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
{
if (SameNameRecordAnswersQuestion(&rr->resrec, q))
{
- LogInfo("uDNS_CheckCurrentQuestion: Purged resourcerecord %s", CRDisplayString(m, rr));
+ LogInfo("uDNS_CheckCurrentQuestion: Purged resourcerecord %s", CRDisplayString(m, rr));
mDNS_PurgeCacheResourceRecord(m, rr);
}
}
@@ -5049,7 +5007,7 @@ mDNSexport void CheckNATMappings(mDNS *m)
const mStatus EffectiveResult = cur->NewResult ? cur->NewResult : mDNSv4AddrIsRFC1918(&EffectiveAddress) ? mStatus_DoubleNAT : mStatus_NoError;
const mDNSIPPort ExternalPort = HaveRoutable ? cur->IntPort :
!mDNSIPv4AddressIsZero(EffectiveAddress) && cur->ExpiryTime ? cur->RequestedPort : zeroIPPort;
-
+
if (!cur->Protocol || HaveRoutable || cur->ExpiryTime || cur->retryInterval > NATMAP_INIT_RETRY * 8)
{
if (!mDNSSameIPv4Address(cur->ExternalAddress, EffectiveAddress) ||
@@ -5337,8 +5295,8 @@ mDNSexport void udns_validatelists(void *const v)
DNSServer *d;
for (d = m->DNSServers; d; d=d->next)
- if (d->next == (DNSServer *)~0 || d->teststate > DNSServer_Disabled)
- LogMemCorruption("m->DNSServers: %p is garbage (%d)", d, d->teststate);
+ if (d->next == (DNSServer *)~0)
+ LogMemCorruption("m->DNSServers: %p is garbage", d);
DomainAuthInfo *info;
for (info = m->AuthInfoList; info; info = info->next)
@@ -5810,101 +5768,327 @@ struct CompileTimeAssertionChecks_uDNS
char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 5000) ? 1 : -1];
};
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - DNS Push Notification functions
+#endif
+
+mDNSlocal tcpInfo_t * GetTCPConnectionToPushServer(mDNS *m, DNSQuestion *q)
+{
+ // If we already have a question for this zone and if the server is the same, reuse it
+ DNSPushNotificationZone *zone = mDNSNULL;
+ for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
+ {
+ if (SameDomainName(&q->nta->ChildName, &zone->zoneName))
+ {
+ DNSPushNotificationServer *zoneServer = mDNSNULL;
+ for (zoneServer = zone->servers; zoneServer != mDNSNULL; zoneServer = zoneServer->next)
+ {
+ if (mDNSSameAddress(&q->dnsPushServerAddr, &zoneServer->serverAddr))
+ {
+ zone->numberOfQuestions++;
+ zoneServer->numberOfQuestions++;
+ return zoneServer->connection;
+ }
+ }
+ }
+ }
+
+ // If we have a connection to this server but it is for a differnt zone, create a new zone entry and reuse the connection
+ DNSPushNotificationServer *server = mDNSNULL;
+ for (server = m->DNSPushServers; server != mDNSNULL; server = server->next)
+ {
+ if (mDNSSameAddress(&q->dnsPushServerAddr, &server->serverAddr))
+ {
+ DNSPushNotificationZone *newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
+ newZone->numberOfQuestions = 1;
+ newZone->zoneName = q->nta->ChildName;
+ newZone->servers = server;
+
+ // Add the new zone to the begining of the list
+ newZone->next = m->DNSPushZones;
+ m->DNSPushZones = newZone;
+
+ server->numberOfQuestions++;
+ return server->connection;
+ }
+ }
+
+ // If we do not have any existing connections, create a new connection
+ DNSPushNotificationServer *newServer = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationServer));
+ DNSPushNotificationZone *newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
+
+ newServer->numberOfQuestions = 1;
+ newServer->serverAddr = q->dnsPushServerAddr;
+ newServer->connection = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->dnsPushServerAddr, q->dnsPushServerPort, &q->nta->Host, q, mDNSNULL);
+
+ newZone->numberOfQuestions = 1;
+ newZone->zoneName = q->nta->ChildName;
+ newZone->servers = newServer;
+
+ // Add the new zone to the begining of the list
+ newZone->next = m->DNSPushZones;
+ m->DNSPushZones = newZone;
+
+ newServer->next = m->DNSPushServers;
+ m->DNSPushServers = newServer;
+ return newServer->connection;
+}
+
+mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ /* Use the same NAT setup as in the LLQ case */
+ if (m->LLQNAT.clientContext != mDNSNULL) // LLQNAT just started, give it some time
+ {
+ LogInfo("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ return;
+ }
+
+ // Either we don't have {PCP, NAT-PMP, UPnP/IGD} support (ExternalPort is zero) or behind a Double NAT that may or
+ // may not have {PCP, NAT-PMP, UPnP/IGD} support (NATResult is non-zero)
+ if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort) || m->LLQNAT.Result)
+ {
+ LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s) External Port %d, NAT Result %d",
+ q->qname.c, DNSTypeName(q->qtype), mDNSVal16(m->LLQNAT.ExternalPort), m->LLQNAT.Result);
+ StartLLQPolling(m, q); // Actually sets up the NAT Auto Tunnel
+ return;
+ }
+
+ if (mDNSIPPortIsZero(q->dnsPushServerPort) && q->dnsPushState == DNSPUSH_INIT)
+ {
+ LogInfo("SubscribeToDNSPushNotificationServer: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ q->dnsPushServerAddr = zeroAddr;
+ // We know q->dnsPushServerPort is zero because of check above
+ if (q->nta) CancelGetZoneData(m, q->nta);
+ q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q);
+ return;
+ }
+
+ if (q->tcp)
+ {
+ LogInfo("SubscribeToDNSPushNotificationServer: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ DisposeTCPConn(q->tcp);
+ q->tcp = mDNSNULL;
+ }
+
+ if (!q->nta)
+ {
+ // Normally we lookup the zone data and then call this function. And we never free the zone data
+ // for "PrivateQuery". But sometimes this can happen due to some race conditions. When we
+ // switch networks, we might end up "Polling" the network e.g., we are behind a Double NAT.
+ // When we poll, we free the zone information as we send the query to the server (See
+ // PrivateQueryGotZoneData). The NAT callback (LLQNATCallback) may happen soon after that. If we
+ // are still behind Double NAT, we would have returned early in this function. But we could
+ // have switched to a network with no NATs and we should get the zone data again.
+ LogInfo("SubscribeToDNSPushNotificationServer: nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q);
+ return;
+ }
+ else if (!q->nta->Host.c[0])
+ {
+ // This should not happen. If it happens, we print a log and MakeTCPConn will fail if it can't find a hostname
+ LogMsg("SubscribeToDNSPushNotificationServer: ERROR!!: nta non NULL for %##s (%s) but HostName %d NULL, LongLived %d", q->qname.c, DNSTypeName(q->qtype), q->nta->Host.c[0], q->LongLived);
+ }
+ q->tcp = GetTCPConnectionToPushServer(m,q);
+ // If TCP failed (transient networking glitch) try again in five seconds
+ q->ThisQInterval = (q->tcp != mDNSNULL) ? q->ThisQInterval = 0 : (mDNSPlatformOneSecond * 5);
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+}
+
+
+mDNSexport void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ mDNSu8 *end = mDNSNULL;
+ InitializeDNSMessage(&m->omsg.h, zeroID, SubscribeFlags);
+ end = putQuestion(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
+ if (!end)
+ {
+ LogMsg("ERROR: SubscribeToDNSPushNotificationServer putQuestion failed");
+ return;
+ }
+
+ mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->dnsPushServerAddr, q->dnsPushServerPort, q->tcp->sock, mDNSNULL, mDNSfalse);
+
+ // update question state
+ q->dnsPushState = DNSPUSH_ESTABLISHED;
+ q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+
+}
+
+mDNSlocal void reconcileDNSPushConnection(mDNS *m, DNSQuestion *q)
+{
+ DNSPushNotificationZone *zone;
+ DNSPushNotificationServer *server;
+ // Update the counts
+ for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
+ {
+ if (SameDomainName(&zone->zoneName, &q->nta->ChildName))
+ {
+ zone->numberOfQuestions--;
+ for (server = zone->servers; server != mDNSNULL; server = server->next)
+ {
+ if (mDNSSameAddress(&server->serverAddr, &q->dnsPushServerAddr))
+ server->numberOfQuestions--;
+ }
+ }
+ }
+
+ // Now prune the lists
+ server = m->DNSPushServers;
+ DNSPushNotificationServer *nextServer = mDNSNULL;
+ while(server != mDNSNULL)
+ {
+ nextServer = server->next;
+ if (server->numberOfQuestions <= 0)
+ {
+ DisposeTCPConn(server->connection);
+ if (server == m->DNSPushServers)
+ m->DNSPushServers = nextServer;
+ mDNSPlatformMemFree(server);
+ server = nextServer;
+ }
+ else server = server->next;
+ }
+
+ zone = m->DNSPushZones;
+ DNSPushNotificationZone *nextZone = mDNSNULL;
+ while(zone != mDNSNULL)
+ {
+ nextZone = zone->next;
+ if (zone->numberOfQuestions <= 0)
+ {
+ if (zone == m->DNSPushZones)
+ m->DNSPushZones = nextZone;
+ mDNSPlatformMemFree(zone);
+ zone = nextZone;
+ }
+ else zone = zone->next;
+ }
+
+}
+
+mDNSexport void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ mDNSu8 *end = mDNSNULL;
+ InitializeDNSMessage(&m->omsg.h, q->TargetQID, UnSubscribeFlags);
+ end = putQuestion(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
+ if (!end)
+ {
+ LogMsg("ERROR: UnSubscribeToDNSPushNotificationServer - putQuestion failed");
+ return;
+ }
+
+ mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->dnsPushServerAddr, q->dnsPushServerPort, q->tcp->sock, mDNSNULL, mDNSfalse);
+
+ reconcileDNSPushConnection(m, q);
+}
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#endif
#else // !UNICAST_DISABLED
mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr)
{
- (void) m;
- (void) rr;
+ (void) m;
+ (void) rr;
- return mDNSNULL;
+ return mDNSNULL;
}
mDNSexport DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name)
{
- (void) m;
- (void) name;
+ (void) m;
+ (void) name;
- return mDNSNULL;
+ return mDNSNULL;
}
mDNSexport DomainAuthInfo *GetAuthInfoForQuestion(mDNS *m, const DNSQuestion *const q)
{
- (void) m;
- (void) q;
+ (void) m;
+ (void) q;
- return mDNSNULL;
+ return mDNSNULL;
}
mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
{
- (void) m;
- (void) q;
+ (void) m;
+ (void) q;
}
mDNSexport void DisposeTCPConn(struct tcpInfo_t *tcp)
{
- (void) tcp;
+ (void) tcp;
}
mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *m, NATTraversalInfo *traversal)
{
- (void) m;
- (void) traversal;
+ (void) m;
+ (void) traversal;
- return mStatus_UnsupportedErr;
+ return mStatus_UnsupportedErr;
}
mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal)
{
- (void) m;
- (void) traversal;
+ (void) m;
+ (void) traversal;
- return mStatus_UnsupportedErr;
+ return mStatus_UnsupportedErr;
}
mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q)
{
- (void) m;
- (void) q;
+ (void) m;
+ (void) q;
}
mDNSexport ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *ZoneDataContext)
{
- (void) m;
- (void) name;
- (void) target;
- (void) callback;
- (void) ZoneDataContext;
+ (void) m;
+ (void) name;
+ (void) target;
+ (void) callback;
+ (void) ZoneDataContext;
- return mDNSNULL;
+ return mDNSNULL;
}
mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData)
{
- (void) m;
- (void) err;
- (void) zoneData;
+ (void) m;
+ (void) err;
+ (void) zoneData;
}
mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
const mDNSAddr *const srcaddr, const mDNSIPPort srcport, DNSQuestion **matchQuestion)
{
- (void) m;
- (void) msg;
- (void) end;
- (void) srcaddr;
- (void) srcport;
- (void) matchQuestion;
+ (void) m;
+ (void) msg;
+ (void) end;
+ (void) srcaddr;
+ (void) srcport;
+ (void) matchQuestion;
- return uDNS_LLQ_Not;
+ return uDNS_LLQ_Not;
}
mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 responseFlags)
{
- (void) m;
- (void) q;
- (void) responseFlags;
+ (void) m;
+ (void) q;
+ (void) responseFlags;
}
mDNSexport void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID)
@@ -5928,7 +6112,7 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, const
(void) hostname;
(void) port;
(void) autoTunnel;
-
+
return mStatus_UnsupportedErr;
}
@@ -5938,7 +6122,7 @@ mDNSexport domainname *uDNS_GetNextSearchDomain(mDNS *const m, mDNSInterfaceID
(void) InterfaceID;
(void) searchIndex;
(void) ignoreDotLocal;
-
+
return mDNSNULL;
}
@@ -5946,7 +6130,7 @@ mDNSexport DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const n
{
(void) m;
(void) name;
-
+
return mDNSNULL;
}
@@ -5954,7 +6138,7 @@ mDNSexport mStatus mDNS_StartNATOperation(mDNS *const m, NATTraversalInfo *trave
{
(void) m;
(void) traversal;
-
+
return mStatus_UnsupportedErr;
}
@@ -5962,7 +6146,7 @@ mDNSexport mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traver
{
(void) m;
(void) traversal;
-
+
return mStatus_UnsupportedErr;
}
@@ -5983,7 +6167,7 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
(void) reqA;
(void) reqAAAA;
(void) reqDO;
-
+
return mDNSNULL;
}
@@ -6034,8 +6218,27 @@ mDNSexport void RecreateNATMappings(mDNS *const m, const mDNSu32 waitTicks)
mDNSexport mDNSBool IsGetZoneDataQuestion(DNSQuestion *q)
{
(void)q;
-
+
return mDNSfalse;
}
+mDNSexport void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ (void)m;
+ (void)q;
+}
+
+mDNSexport void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ (void)m;
+ (void)q;
+}
+
+mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ (void)m;
+ (void)q;
+}
+
#endif // !UNICAST_DISABLED
+
diff --git a/mDNSResponder/mDNSCore/uDNS.h b/mDNSResponder/mDNSCore/uDNS.h
index eca8b701..910449f1 100755
--- a/mDNSResponder/mDNSCore/uDNS.h
+++ b/mDNSResponder/mDNSCore/uDNS.h
@@ -47,9 +47,8 @@ extern "C" {
#define QuestionIntervalStep3 (QuestionIntervalStep*QuestionIntervalStep*QuestionIntervalStep)
#define InitialQuestionInterval ((mDNSPlatformOneSecond + QuestionIntervalStep-1) / QuestionIntervalStep)
#define MaxQuestionInterval (3600 * mDNSPlatformOneSecond)
-
-// just move to MaxQuestionInterval once over this threshold
-#define QuestionIntervalThreshold (QuestionIntervalStep3 * mDNSPlatformOneSecond)
+#define UDNSBackOffMultiplier 2
+#define MinQuestionInterval (1 * mDNSPlatformOneSecond)
// For Unicast record registrations, we initialize the interval to 1 second. When we send any query for
// the record registration e.g., GetZoneData, we always back off by QuestionIntervalStep
@@ -82,6 +81,11 @@ extern void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
extern void startLLQHandshake(mDNS *m, DNSQuestion *q);
extern void sendLLQRefresh(mDNS *m, DNSQuestion *q);
+extern void DNSPushNotificationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo);
+extern void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
+extern void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
+extern void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
+
extern void SleepRecordRegistrations(mDNS *m);
// uDNS_UpdateRecord
@@ -144,6 +148,10 @@ extern void uDNS_ReceiveNATPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mD
extern void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr);
extern void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease, NATTProtocol protocol);
+// DNS Push Notification
+extern void SubscribeToDNSPushNotification(mDNS *m, DNSQuestion *q);
+
+
#ifdef __cplusplus
}
#endif