]> git.saurik.com Git - apple/mdnsresponder.git/commitdiff
mDNSResponder-214.3.tar.gz mac-os-x-1063 v214.3
authorApple <opensource@apple.com>
Tue, 15 Dec 2009 22:21:22 +0000 (22:21 +0000)
committerApple <opensource@apple.com>
Tue, 15 Dec 2009 22:21:22 +0000 (22:21 +0000)
20 files changed:
Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
Clients/PrinterSetupWizard/ThirdPage.cpp
Clients/dns-sd.c
Makefile
mDNSCore/DNSCommon.c
mDNSCore/DNSCommon.h
mDNSCore/mDNS.c
mDNSCore/mDNSEmbeddedAPI.h
mDNSCore/uDNS.c
mDNSCore/uDNS.h
mDNSMacOSX/LaunchDaemonInfo-Tiger.helper.plist [new file with mode: 0644]
mDNSMacOSX/LaunchDaemonInfo-Tiger.plist [new file with mode: 0644]
mDNSMacOSX/daemon.c
mDNSMacOSX/helper-main.c
mDNSMacOSX/helper.c
mDNSMacOSX/mDNSMacOSX.c
mDNSMacOSX/mDNSMacOSX.h
mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
mDNSShared/dns_sd.h
mDNSShared/uds_daemon.c

index 65f5324cd1bd88e354bebf0af197808d037e82f2..da149696b81ac0f7108af34ec583387d8153c47b 100644 (file)
                                RelativePath="stdafx.cpp"\r
                                >\r
                        </File>\r
-                       <File\r
-                               RelativePath=".\StdioFileEx.cpp"\r
-                               >\r
-                       </File>\r
                        <File\r
                                RelativePath="ThirdPage.cpp"\r
                                >\r
                                RelativePath="stdafx.h"\r
                                >\r
                        </File>\r
-                       <File\r
-                               RelativePath=".\StdioFileEx.h"\r
-                               >\r
-                       </File>\r
                        <File\r
                                RelativePath="ThirdPage.h"\r
                                >\r
index 8981bd4d3acf7051345b457796f94da95d6bd2a6..deca4dfc53536b0539aa915d142f2907980bb101 100644 (file)
@@ -162,7 +162,6 @@ First checked in
 #include "PrinterSetupWizardApp.h"
 #include "PrinterSetupWizardSheet.h"
 #include "ThirdPage.h"
-#include "StdioFileEx.h"
 #include <dns_sd.h>
 #include <tcpxcv.h>
 #include <winspool.h>
index 993632d713e8030120af0a8cb2524daa9d5d53c2..b9455525d4e931f189da15115b615bb768ec7ce2 100644 (file)
@@ -70,6 +70,14 @@ cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Rele
 // aren't in the system's /usr/lib/libSystem.dylib.
 //#define TEST_NEW_CLIENTSTUB 1
 
+// When building mDNSResponder for Mac OS X 10.4 and earlier, /usr/lib/libSystem.dylib is built using its own private
+// copy of dnssd_clientstub.c, which is old and doesn't have all the entry points defined in the latest version, so
+// when we're building dns-sd.c on Mac OS X 10.4 or earlier, we automatically set TEST_NEW_CLIENTSTUB so that we'll
+// embed a copy of the latest dnssd_clientstub.c instead of trying to link to the incomplete version in libSystem.dylib
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 1040
+#define TEST_NEW_CLIENTSTUB 1
+#endif
+
 #include <ctype.h>
 #include <stdio.h>                     // For stdout, stderr
 #include <stdlib.h>                    // For exit()
index aaf7bc6d6b53565a52eb0059859fab650a590b1b..93d4c3285009637768eb89c3c8a3850e58f2ca0d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 
 include /Developer/Makefiles/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-214"
+MVERS = "mDNSResponder-214.3"
 
 DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
 
index bf57929d5ce5a3e26162994dda85db08830d862e..a866aa60669030e29c84838d822ee7cc161f0044 100644 (file)
@@ -592,8 +592,9 @@ mDNSexport const mDNSEthAddr     onesEthAddr       = { { 255, 255, 255, 255, 255
 mDNSexport const OwnerOptData    zeroOwner         = { 0, 0, { { 0 } }, { { 0 } }, { { 0 } } };
 
 mDNSexport const mDNSInterfaceID mDNSInterface_Any       = 0;
-mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)1;
-mDNSexport const mDNSInterfaceID mDNSInterface_Unicast   = (mDNSInterfaceID)2;
+mDNSexport const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)-1;
+mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)-2;
+mDNSexport const mDNSInterfaceID mDNSInterface_Unicast   = (mDNSInterfaceID)-3;
 
 // 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
index 95d4e3026ad5274fb69bd4c70ed51162890c1761..b097680de2609fa21145425e6d3dc9ad64216ba8 100644 (file)
     Change History (most recent first):
 
 $Log: DNSCommon.h,v $
+svn merge: Revision 1.75  2009/07/21 23:35:01  cheshire
+<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
+Added PutRR_OS macros to put a ResourceRecord while taking into account the space needed to add an OWNER option at the end
+
 Revision 1.73  2009/04/24 00:28:05  cheshire
 <rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
 Added definitions for RRTypeAnswersQuestionType/RRAssertsNonexistence/AnyTypeRecordAnswersQuestion
@@ -326,20 +330,31 @@ extern mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *
 
 // If we have a single large record to put in the packet, then we allow the packet to be up to 9K bytes,
 // but in the normal case we try to keep the packets below 1500 to avoid IP fragmentation on standard Ethernet
+
+#define AllowedRRSpace(msg) (((msg)->h.numAnswers || (msg)->h.numAuthorities || (msg)->h.numAdditionals) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData)
+
 extern mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit);
 
 #define PutResourceRecordTTL(msg, ptr, count, rr, ttl) \
-       PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), \
-       ((msg)->h.numAnswers || (msg)->h.numAuthorities || (msg)->h.numAdditionals) ? (msg)->data + NormalMaxDNSMessageData : (msg)->data + AbsoluteMaxDNSMessageData)
+       PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), (msg)->data + AllowedRRSpace(msg))
+
 #define PutResourceRecordTTLJumbo(msg, ptr, count, rr, ttl) \
        PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), (msg)->data + AbsoluteMaxDNSMessageData)
+
 #define PutResourceRecord(MSG, P, C, RR) PutResourceRecordTTL((MSG), (P), (C), (RR), (RR)->rroriginalttl)
 
+// The PutRR_OS variants assume a local variable 'm', put build the packet at m->omsg,
+// and assume a local variable 'OwnerRecordSpace' indicating how many bytes (if any) to reserve to add an OWNER option at the end
+#define PutRR_OS_TTL(ptr, count, rr, ttl) \
+       PutResourceRecordTTLWithLimit(&m->omsg, (ptr), (count), (rr), (ttl), m->omsg.data + AllowedRRSpace(&m->omsg) - OwnerRecordSpace)
+
+#define PutRR_OS(P, C, RR) PutRR_OS_TTL((P), (C), (RR), (RR)->rroriginalttl)
+
 extern mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass);
 extern mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass);
 extern mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end);
 extern mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr);
-extern  mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype);
+extern mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype);
 extern mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name);
 extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease);
 
index 8fe2a80971ab9bd0c59a3312991a415b37e046d8..8bf8a3278064e69a9177685e155c5720061bcd6d 100755 (executable)
     Change History (most recent first):
 
 $Log: mDNS.c,v $
+Revision 1.977  2009/07/23 23:30:01  cheshire
+<rdar://problem/7086623> Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity
+
+Revision 1.976  2009/07/23 09:15:06  cheshire
+<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
+Fixed silly mistake in checkin 1.974 that broke SendResponses
+
+Revision 1.975  2009/07/21 23:46:19  cheshire
+Improved "DNS Message too short" syslog debugging message
+
+Revision 1.974  2009/07/21 23:41:05  cheshire
+<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
+Fixed silly mistake in checkin 1.974 that broke SendResponses
+
+svn merge: Revision 1.974  2009/07/21 23:41:05  cheshire
+<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
+Another refinement: When building a response packet, if we're going to add an OWNER option at the end,
+reserve enough bytes to ensure that we'll be able to do that
+
+svn merge: Revision 1.973  2009/07/16 00:34:18  cheshire
+<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
+Additional refinement: If we didn't register with a Sleep Proxy when going to sleep,
+we don't need to include our OWNER option in our packets when we re-awaken
+
+svn merge: Revision 1.972  2009/07/16 00:12:23  cheshire
+<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
+Additional fixes: Only add and send OWNER option if we were already going to send a non-empty packet anyway
+
+svn merge: Revision 1.971  2009/07/15 23:35:40  cheshire
+<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
+
 Revision 1.970.2.1  2009/07/23 23:36:04  cheshire
 <rdar://problem/7086623> Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity
 
@@ -1522,7 +1553,6 @@ mDNSlocal void RetrySPSRegistrations(mDNS *const m);
 
 #define NO_HINFO 1
 
-mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0;
 
 // Any records bigger than this are considered 'large' records
 #define SmallRecordLimit 1024
@@ -1624,10 +1654,10 @@ mDNSlocal NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInt
        return(intf);
        }
 
-mDNSlocal char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
+mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
        {
        NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
-       return(intf ? intf->ifname : "<NULL InterfaceID>");
+       return(intf ? intf->ifname : mDNSNULL);
        }
 
 // For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
@@ -2651,8 +2681,9 @@ mDNSlocal void SetupOwnerOpt(const mDNS *const m, const NetworkInterfaceInfo *co
        owner->u.owner.password = zeroEthAddr;
 
        // Don't try to compute the optlen until *after* we've set up the data fields
+       // Right now the DNSOpt_Owner_Space macro does not depend on the owner->u.owner being set up correctly, but in the future it might
        owner->opt              = kDNSOpt_Owner;
-       owner->optlen           = DNSOpt_Owner_Space(owner) - 4;
+       owner->optlen           = DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC) - 4;
        }
 
 mDNSlocal void GrantUpdateCredit(AuthRecord *rr)
@@ -2837,6 +2868,7 @@ mDNSlocal void SendResponses(mDNS *const m)
 
        while (intf)
                {
+               const int OwnerRecordSpace = (m->AnnounceOwner && intf->MAC.l[0]) ? DNSOpt_Header_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC) : 0;
                int numDereg    = 0;
                int numAnnounce = 0;
                int numAnswer   = 0;
@@ -2855,7 +2887,7 @@ mDNSlocal void SendResponses(mDNS *const m)
                                newptr = mDNSNULL;
                                if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
                                        {
-                                       newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
+                                       newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
                                        if (newptr) { responseptr = newptr; numDereg++; }
                                        }
                                else if (rr->NewRData && !m->SleepState)                                        // If we have new data for this record
@@ -2865,14 +2897,14 @@ mDNSlocal void SendResponses(mDNS *const m)
                                        // See if we should send a courtesy "goodbye" for the old data before we replace it.
                                        if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye)
                                                {
-                                               newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
+                                               newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
                                                if (newptr) { responseptr = newptr; numDereg++; rr->RequireGoodbye = mDNSfalse; }
                                                }
                                        // Now try to see if we can fit the update in the same packet (not fatal if we can't)
                                        SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
                                        if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
                                                rr->resrec.rrclass |= kDNSClass_UniqueRRSet;            // Temporarily set the cache flush bit so PutResourceRecord will set it
-                                       newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
+                                       newptr = PutRR_OS(responseptr, &m->omsg.h.numAnswers, &rr->resrec);
                                        rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;                   // Make sure to clear cache flush bit back to normal state
                                        if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; }
                                        SetNewRData(&rr->resrec, OldRData, oldrdlength);
@@ -2882,7 +2914,7 @@ mDNSlocal void SendResponses(mDNS *const m)
                                        mDNSu8 active = (m->SleepState != SleepState_Sleeping || intf->SPSAddr[0].type || intf->SPSAddr[1].type || intf->SPSAddr[2].type);
                                        if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
                                                rr->resrec.rrclass |= kDNSClass_UniqueRRSet;            // Temporarily set the cache flush bit so PutResourceRecord will set it
-                                       newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0);
+                                       newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0);
                                        rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;                   // Make sure to clear cache flush bit back to normal state
                                        if (newptr)
                                                {
@@ -2893,7 +2925,7 @@ mDNSlocal void SendResponses(mDNS *const m)
 
                                        // The first time through (pktcount==0), if this record is verified unique
                                        // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
-                                       if (!pktcount && active && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = (mDNSInterfaceID)1;
+                                       if (!pktcount && active && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = mDNSInterfaceMark;
                                        }
 
                                if (newptr)             // If succeeded in sending, advance to next interface
@@ -2933,11 +2965,11 @@ mDNSlocal void SendResponses(mDNS *const m)
                                                {
                                                // The first time through (pktcount==0), if this record is verified unique
                                                // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
-                                               if (!pktcount && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = (mDNSInterfaceID)1;
+                                               if (!pktcount && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = mDNSInterfaceMark;
 
                                                if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
                                                        rr->resrec.rrclass |= kDNSClass_UniqueRRSet;    // Temporarily set the cache flush bit so PutResourceRecord will set it
-                                               newptr = PutResourceRecord(&m->omsg, newptr, &m->omsg.h.numAdditionals, &rr->resrec);
+                                               newptr = PutRR_OS(newptr, &m->omsg.h.numAdditionals, &rr->resrec);
                                                rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;           // Make sure to clear cache flush bit back to normal state
                                                if (newptr)
                                                        {
@@ -2956,7 +2988,7 @@ mDNSlocal void SendResponses(mDNS *const m)
 
                // Third Pass. Add NSEC records, if there's space.
                for (rr = m->ResourceRecords; rr; rr=rr->next)
-                       if (rr->SendNSECNow == (mDNSInterfaceID)1 || rr->SendNSECNow == intf->InterfaceID)
+                       if (rr->SendNSECNow == mDNSInterfaceMark || rr->SendNSECNow == intf->InterfaceID)
                                {
                                AuthRecord nsec;
                                mDNS_SetupResourceRecord(&nsec, mDNSNULL, mDNSInterface_Any, kDNSType_NSEC, rr->resrec.rroriginalttl, kDNSRecordTypeUnique, mDNSNULL, mDNSNULL);
@@ -2972,25 +3004,41 @@ mDNSlocal void SendResponses(mDNS *const m)
                                newptr = responseptr;
                                if (!r2)        // If we successfully built our NSEC record, add it to the packet now
                                        {
-                                       newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &nsec.resrec);
+                                       newptr = PutRR_OS(responseptr, &m->omsg.h.numAdditionals, &nsec.resrec);
                                        if (newptr) responseptr = newptr;
                                        }
 
                                // If we successfully put the NSEC record, clear the SendNSECNow flag
                                // If we consider this NSEC optional, then we unconditionally clear the SendNSECNow flag, even if we fail to put this additional record
-                               if (newptr || rr->SendNSECNow == (mDNSInterfaceID)1)
+                               if (newptr || rr->SendNSECNow == mDNSInterfaceMark)
                                        {
                                        rr->SendNSECNow = mDNSNULL;
                                        // Run through remainder of list clearing SendNSECNow flag for all other records which would generate the same NSEC
                                        for (r2 = rr->next; r2; r2=r2->next)
                                                if (SameResourceRecordNameClassInterface(r2, rr))
-                                                       if (r2->SendNSECNow == (mDNSInterfaceID)1 || r2->SendNSECNow == intf->InterfaceID)
+                                                       if (r2->SendNSECNow == mDNSInterfaceMark || r2->SendNSECNow == intf->InterfaceID)
                                                                r2->SendNSECNow = mDNSNULL;
                                        }
                                }
 
-               if (m->omsg.h.numAnswers > 0 || m->omsg.h.numAdditionals)
+               if (m->omsg.h.numAnswers || m->omsg.h.numAdditionals)
                        {
+                       // If we have data to send, add OWNER option if necessary, then send packet
+
+                       if (OwnerRecordSpace)
+                               {
+                               AuthRecord opt;
+                               mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+                               opt.resrec.rrclass    = NormalMaxDNSMessageData;
+                               opt.resrec.rdlength   = sizeof(rdataOPT);       // One option in this OPT record
+                               opt.resrec.rdestimate = sizeof(rdataOPT);
+                               SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]);
+                               newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &opt.resrec);
+                               if (newptr) { responseptr = newptr; LogSPS("SendResponses put %s", ARDisplayString(m, &opt)); }
+                               else LogMsg("SendResponses: How did we fail to have space for the OPT record (%d/%d/%d/%d) %s",
+                                       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",
@@ -3140,19 +3188,12 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
        mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353;
        mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
        const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData;
-       mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
+       mDNSu8 *newptr = putQuestion(query, *queryptr, limit - *answerforecast, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
        if (!newptr)
                {
                debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
                return(mDNSfalse);
                }
-       else if (newptr + *answerforecast >= limit)
-               {
-               verbosedebugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
-                       q->qname.c, DNSTypeName(q->qtype), newptr + *answerforecast - query->data);
-               query->h.numQuestions--;
-               return(mDNSfalse);
-               }
        else
                {
                mDNSu32 forecast = *answerforecast;
@@ -3536,7 +3577,9 @@ mDNSlocal void SendQueries(mDNS *const m)
                                        {
                                        if (rr->AddressProxy.type == mDNSAddrType_IPv4)
                                                {
-                                               LogSPS("SendQueries ARP Probe %d %s %s", rr->ProbeCount, InterfaceNameForID(m, rr->resrec.InterfaceID), ARDisplayString(m,rr));
+                                               char *ifname = InterfaceNameForID(m, rr->resrec.InterfaceID);
+                                               if (!ifname) ifname = "<NULL InterfaceID>";
+                                               LogSPS("SendQueries ARP Probe %d %s %s", rr->ProbeCount, ifname, ARDisplayString(m,rr));
                                                SendARP(m, 1, rr, zerov4Addr.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, rr->WakeUp.IMAC.b);
                                                }
                                        else if (rr->AddressProxy.type == mDNSAddrType_IPv6)
@@ -3598,18 +3641,16 @@ mDNSlocal void SendQueries(mDNS *const m)
        // go through our interface list sending the appropriate queries on each interface
        while (intf)
                {
-               const int os = !intf->MAC.l[0] ? 0 : DNSOpt_Header_Space + mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space;
-               int OwnerRecordSpace = 0;
+               const int OwnerRecordSpace = (m->AnnounceOwner && intf->MAC.l[0]) ? DNSOpt_Header_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC) : 0;
                AuthRecord *rr;
                mDNSu8 *queryptr = m->omsg.data;
-               mDNSu8 *limit    = m->omsg.data + AbsoluteMaxDNSMessageData;
                InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags);
                if (KnownAnswerList) verbosedebugf("SendQueries:   KnownAnswerList set... Will continue from previous packet");
                if (!KnownAnswerList)
                        {
                        // Start a new known-answer list
                        CacheRecord **kalistptr = &KnownAnswerList;
-                       mDNSu32 answerforecast = 0;
+                       mDNSu32 answerforecast = OwnerRecordSpace;              // We start by assuming we'll need at least enough space to put the Owner Option
                        
                        // Put query questions in this packet
                        for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
@@ -3623,10 +3664,7 @@ mDNSlocal void SendQueries(mDNS *const m)
                                        // If we're suppressing this question, or we successfully put it, update its SendQNow state
                                        if (SuppressOnThisInterface(q->DupSuppress, intf) ||
                                                BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
-                                               q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
-
-                                       // Once we've put at least one question, cut back our limit to the normal single-packet size
-                                       if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData;
+                                                       q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
                                        }
                                }
 
@@ -3636,42 +3674,34 @@ mDNSlocal void SendQueries(mDNS *const m)
                                        {
                                        mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353;
                                        mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
-                                       mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
+                                       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 + rr->resrec.rdestimate;
-                                       if (newptr && newptr + forecast + os < limit)
+                                       mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit - forecast, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
+                                       if (newptr)
                                                {
-                                               queryptr         = newptr;
-                                               limit            = m->omsg.data + NormalMaxDNSMessageData;
-                                               answerforecast   = forecast;
-                                               OwnerRecordSpace = os;
+                                               queryptr       = newptr;
+                                               answerforecast = forecast;
                                                rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
                                                rr->IncludeInProbe = mDNStrue;
                                                verbosedebugf("SendQueries:   Put Question %##s (%s) probecount %d",
                                                        rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
                                                }
-                                       else
-                                               {
-                                               verbosedebugf("SendQueries:   Retracting Question %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
-                                               m->omsg.h.numQuestions--;
-                                               }
                                        }
                        }
 
-               if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace;
-
                // Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
                while (KnownAnswerList)
                        {
                        CacheRecord *ka = KnownAnswerList;
                        mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - ka->TimeRcvd)) / mDNSPlatformOneSecond;
-                       mDNSu8 *newptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAnswers, &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd, limit);
+                       mDNSu8 *newptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAnswers,
+                               &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd, m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace);
                        if (newptr)
                                {
                                verbosedebugf("SendQueries:   Put %##s (%s) at %d - %d",
                                        ka->resrec.name->c, DNSTypeName(ka->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
                                queryptr = newptr;
-                               limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace;
                                KnownAnswerList = ka->NextInKAList;
                                ka->NextInKAList = mDNSNULL;
                                }
@@ -3695,24 +3725,29 @@ mDNSlocal void SendQueries(mDNS *const m)
                                else LogMsg("SendQueries:   How did we fail to have space for the Update record %s", ARDisplayString(m,rr));
                                }
 
-               if (OwnerRecordSpace)
-                       {
-                       AuthRecord opt;
-                       mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
-                       opt.resrec.rrclass    = NormalMaxDNSMessageData;
-                       opt.resrec.rdlength   = sizeof(rdataOPT);       // One option in this OPT record
-                       opt.resrec.rdestimate = sizeof(rdataOPT);
-                       SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]);
-                       LogSPS("SendQueries putting %s", 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 the OPT record (%d/%d/%d/%d) %s",
-                                       m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
-                       }
-
                if (queryptr > m->omsg.data)
                        {
+                       if (OwnerRecordSpace)
+                               {
+                               AuthRecord opt;
+                               mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+                               opt.resrec.rrclass    = NormalMaxDNSMessageData;
+                               opt.resrec.rdlength   = sizeof(rdataOPT);       // One option in this OPT record
+                               opt.resrec.rdestimate = sizeof(rdataOPT);
+                               SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]);
+                               LogSPS("SendQueries putting %s", 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 the OPT record (%d/%d/%d/%d) %s",
+                                               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 OPT record %p %p %p (%d/%d/%d/%d) %s",
+                                                       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));
+                               }
+
                        if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1)
                                LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions);
                        debugf("SendQueries:   Sending %d Question%s %d Answer%s %d Update%s on %p",
@@ -4535,6 +4570,10 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
                {
                int i;
 
+               // If there are DNS servers that will come out of the Penalty box, we should do that now
+               // so that any questions that we send below can start using that
+               ResetDNSServerPenalties(m);
+
                verbosedebugf("mDNS_Execute");
                if (m->CurrentQuestion)
                        LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
@@ -4571,6 +4610,9 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
 
                SetSPSProxyListChanged(mDNSNULL);               // Perform any deferred BPF reconfiguration now
 
+               // Clear AnnounceOwner if necessary. (Do this *before* SendQueries() and SendResponses().)
+               if (m->AnnounceOwner && m->timenow - m->AnnounceOwner >= 0) m->AnnounceOwner = 0;
+
                if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
                        {
                        m->DelaySleep = 0;
@@ -4764,8 +4806,7 @@ mDNSexport void mDNSCoreRestartQueries(mDNS *const m)
 
 mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *intf, const mDNSOpaque16 id)
        {
-       const int ownerspace = mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space;
-       const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + ownerspace;
+       const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC);
        const int sps = intf->NextSPSAttempt / 3;
        AuthRecord *rr;
 
@@ -4837,6 +4878,9 @@ mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *intf, co
                        else
                                {
                                mStatus err;
+                               // Once we've attempted to register, we need to include our OWNER option in our packets when we re-awaken
+                               m->SentSleepProxyRegistration = mDNStrue;
+
                                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
@@ -4987,7 +5031,8 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m)
                        else
                                {
                                FindSPSInCache(m, &intf->NetWakeBrowse, sps);
-                               if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found %d", intf->ifname, &intf->ip, intf->NetWakeBrowse.ThisQInterval);
+                               if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found (Next Browse Q in %d, interval %d)",
+                                       intf->ifname, &intf->ip, intf->NetWakeBrowse.LastQTime + intf->NetWakeBrowse.ThisQInterval - m->timenow, intf->NetWakeBrowse.ThisQInterval);
                                else
                                        {
                                        int i;
@@ -5082,6 +5127,11 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
                        {
                        m->SleepState = SleepState_Awake;
                        m->SleepSeqNum++;
+                       if (m->SentSleepProxyRegistration)              // Include OWNER option in packets for 60 seconds after waking
+                               {
+                               m->SentSleepProxyRegistration = mDNSfalse;
+                               m->AnnounceOwner = NonZeroTime(m->timenow + 60 * mDNSPlatformOneSecond);
+                               }
                        // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake)
                        // then we enforce a minimum delay of 16 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.,
@@ -5133,8 +5183,12 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
                // 4. Refresh NAT mappings
                // We don't want to have to assume that all hardware can necessarily keep accurate
                // track of passage of time while asleep, so on wake we refresh our NAT mappings
+               // We typically wake up with no interfaces active, so there's no need to rush to try to find our external address.
+               // When we get a DHCP address and mDNS_SetPrimaryInterfaceInfo is called, we'll then set m->retryGetAddr
+               // to immediately request our external address from the NAT gateway.
                m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
-               m->retryGetAddr         = m->timenow;
+               m->retryGetAddr         = m->timenow + mDNSPlatformOneSecond * 5;
+               LogInfo("mDNSCoreMachineSleep: retryGetAddr in %d %d", m->retryGetAddr - m->timenow, m->timenow);
                RecreateNATMappings(m);
                }
 
@@ -6375,7 +6429,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                        if (qptr)
                                                {
                                                LogInfo("Server %p responded with code %d to query %##s (%s)", qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
-                                               PushDNSServerToEnd(m, qptr);
+                                               PenalizeDNSServer(m, qptr, mDNSfalse);
                                                }
                                        returnEarly = mDNStrue;
                                        }
@@ -6584,8 +6638,37 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                }
                                        else if (m->rec.r.resrec.rroriginalttl > 0)
                                                {
+                                               DNSQuestion *q;
                                                //if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr));
                                                RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl);
+
+                                               // We have to reset the question interval to MaxQuestionInterval so that we don't keep
+                                               // polling the network once we get a valid response back. For the first time when a new
+                                               // cache entry is created, AnswerCurrentQuestionWithResourceRecord does that.
+                                               // Subsequently, if we reissue questions from within the mDNSResponder e.g., DNS server
+                                               // configuration changed, without flushing the cache, we reset the question interval here.
+                                               // Currently, we do this for for both multicast and unicast questions as long as the record
+                                               // type is unique. For unicast, resource record is always unique and for multicast it is
+                                               // true for records like A etc. but not for PTR.
+                                               if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
+                                                       {
+                                                       for (q = m->Questions; q; q=q->next)
+                                                               {
+
+                                                               if (!q->DuplicateOf && !q->LongLived && 
+                                                                       ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
+                                                                       {
+                                                                       q->LastQTime        = m->timenow;
+                                                                       q->LastQTxTime      = m->timenow;
+                                                                       q->RecentAnswerPkts = 0;
+                                                                       q->ThisQInterval    = MaxQuestionInterval;
+                                                                       q->RequestUnicast   = mDNSfalse;
+                                                                       q->unansweredQueries = 0;
+                                                                       debugf("mDNSCoreReceiveResponse: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+                                                                       break;
+                                                                       }
+                                                               }
+                                                       }
                                                break;
                                                }
                                        else
@@ -6849,8 +6932,9 @@ mDNSlocal void SPSRecordCallback(mDNS *const m, AuthRecord *const ar, mStatus re
 
        if (result == mStatus_NameConflict)
                {
-               LogMsg("Received Conflicting mDNS -- waking %s %.6a %s",
-                       InterfaceNameForID(m, ar->resrec.InterfaceID), &ar->WakeUp.HMAC, ARDisplayString(m, ar));
+               char *ifname = InterfaceNameForID(m, ar->resrec.InterfaceID);
+               if (!ifname) ifname = "<NULL InterfaceID>";
+               LogMsg("Received Conflicting mDNS -- waking %s %.6a %s", ifname, &ar->WakeUp.HMAC, ARDisplayString(m, ar));
                SendWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.IMAC, &ar->WakeUp.password);
                }
        else if (result == mStatus_MemFree)
@@ -6868,7 +6952,7 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
        int i;
        AuthRecord opt;
        mDNSu8 *p = m->omsg.data;
-       OwnerOptData owner;
+       OwnerOptData owner = zeroOwner;         // Need to zero this, so we'll know if this Update packet was missing its Owner option
        mDNSu32 updatelease = 0;
        const mDNSu8 *ptr;
 
@@ -7119,7 +7203,11 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co
 #endif
 
 #endif
-       if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; }
+       if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader))
+               {
+               LogMsg("DNS Message from %#a:%d to %#a:%d length %d too short", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt);
+               return;
+               }
        QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
        // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
        ptr = (mDNSu8 *)&msg->h.numQuestions;
@@ -7154,15 +7242,15 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co
        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);
+                       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)
+                       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);
+                               do if (i<end - (mDNSu8 *)pkt) p += mDNS_snprintf(p, sizeof(buffer), " %02X", ((mDNSu8 *)pkt)[i]); while (++i & 15);
                                LogInfo("%s", buffer);
                                }
                        }
@@ -7279,19 +7367,194 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
                                }
        }
 
+mDNSinline mDNSs32 PenaltyTimeForServer(mDNS *m, DNSServer *server)
+       {
+       mDNSs32 ptime = 0;
+       if (server->penaltyTime != 0)
+               {
+               ptime = server->penaltyTime - m->timenow;
+               if (ptime < 0)
+                       {
+                       // This should always be a positive value between 0 and DNSSERVER_PENALTY_TIME
+                       // If it does not get reset in ResetDNSServerPenalties for some reason, we do it
+                       // here
+                       LogMsg("PenaltyTimeForServer: PenaltyTime negative %d, (server penaltyTime %d, timenow %d) resetting the penalty", ptime, server->penaltyTime, m->timenow);
+                       server->penaltyTime = 0;
+                       ptime = 0;
+                       }
+               }
+       return ptime;
+       }
+
+// Return the next server to "prev" if it is a match and unpenalized
+mDNSlocal DNSServer *GetNextUnPenalizedServer(mDNS *m, DNSServer *prev)
+       {
+       int curmatchlen = -1;
+       DNSServer *curr = m->DNSServers;
+
+       if (prev == mDNSNULL) return mDNSNULL;
+
+       while (curr != mDNSNULL && curr != prev)
+               curr = curr->next;
+
+       if (curr == mDNSNULL)
+               return mDNSNULL;
+
+
+       // We need to set the curmatchlen as though we are walking the list
+       // from the beginning. Otherwise, we may not pick the best match.
+       // For example, if we are looking up xxx.com, and we used the "xxx.com"
+       // entry the previous time and the next one is "com", we should not pick
+       // "com" now
+       curmatchlen = CountLabels(&curr->domain);
+       curr = curr->next;
+       while (curr != mDNSNULL)
+               {
+               int scount = CountLabels(&curr->domain);
+
+               // Should not be delete because it is marked temporarily for cleaning up
+               // entries during configuration change and we pass NULL as the last argument
+               // to GetServerForName 
+               if (curr->flags & DNSServer_FlagDelete)
+                       {
+                       LogInfo("GetServerForName: DNS Server is marked delete, cannot happen");
+                       curr = curr->next;
+                       continue;
+                       }
+
+
+               debugf("GetNextUnPenalizedServer: Address %#a (Domain %##s), PenaltyTime(abs) %d, PenaltyTime(rel) %d", &curr->addr, curr->domain.c, curr->penaltyTime, PenaltyTimeForServer(m,curr));
+
+               // Note the "==" in comparing scount and curmatchlen. When we picked a match
+               // for the question the first time, we already made sure that prev is the best match.
+               // Any other match is as good if we can find another entry with same number of
+               // labels. There can't be better matches that have more labels, because
+               // we would have picked that in the first place. Also we don't care what the
+               // name in the question is as we picked the best server for the question first
+               // time and the domain name is in prev now
+
+               if ((curr->penaltyTime == 0) && (scount == curmatchlen) && SameDomainName(&prev->domain, &curr->domain))
+                               return curr;
+               curr = curr->next;
+               }
+       return mDNSNULL;
+       }
+
+
+//Checks to see whether the newname is a better match for the name, given the best one we have
+//seen so far (given in bestcount).
+//Returns -1 if the newname is not a better match
+//Returns 0 if the newname is the same as the old match
+//Returns 1 if the newname is a better match
+mDNSlocal int BetterMatchForName(const domainname *name, int namecount, const domainname *newname, int newcount,
+       int bestcount)
+       {
+       // If the name contains fewer labels than the new server's domain or the new name
+       // contains fewer labels than the current best, then it can't possibly be a better match
+       if (namecount < newcount || newcount < bestcount) return -1;
+
+       // If there is no match, return -1 and the caller will skip this newname for
+       // selection
+       //
+       // If we find a match and the number of labels is the same as bestcount, then
+       // we return 0 so that the caller can do additional logic to pick one of
+       // the best based on some other factors e.g., penaltyTime
+       //
+       // If we find a match and the number of labels is more than bestcount, then we
+       // return 1 so that the caller can pick this over the old one.
+       //
+       // NOTE: newcount can either be equal or greater than bestcount beause of the
+       // check above.
+
+       if (SameDomainName(SkipLeadingLabels(name, namecount - newcount), newname))
+               return bestcount == newcount ? 0 : 1;
+       else
+               return -1;
+       }
+
+// Get the Best server that matches a name. If you find penalized servers, look for the one
+// that will come out of the penalty box soon
+mDNSlocal DNSServer *GetAnyBestServer(mDNS *m, const domainname *name)
+       {
+       DNSServer *curmatch = mDNSNULL;
+       int bestmatchlen = -1, namecount = name ? CountLabels(name) : 0;
+       DNSServer *curr;
+       mDNSs32 bestPenaltyTime;
+       int bettermatch;
+
+       bestmatchlen = -1;
+       bestPenaltyTime = DNSSERVER_PENALTY_TIME + 1;
+       for (curr = m->DNSServers; curr; curr = curr->next)
+               {
+               int currcount = CountLabels(&curr->domain);
+               mDNSs32 currPenaltyTime = PenaltyTimeForServer(m, curr);
+
+               debugf("GetAnyBestServer: Address %#a (Domain %##s), PenaltyTime(abs) %d, PenaltyTime(rel) %d",
+                       &curr->addr, curr->domain.c, curr->penaltyTime, currPenaltyTime);
+
+
+               // If there are multiple best servers for a given question, we will pick the first one
+               // if none of them are penalized. If some of them are penalized in that list, we pick
+               // the least penalized one. BetterMatchForName walks through all best matches and
+               // "currPenaltyTime < bestPenaltyTime" check lets us either pick the first best server
+               // in the list when there are no penalized servers and least one among them
+               // when there are some penalized servers
+
+               if (!(curr->flags & DNSServer_FlagDelete))
+                       {
+
+                       bettermatch = BetterMatchForName(name, namecount, &curr->domain, currcount, bestmatchlen);
+
+                       // If we found a better match (bettermatch == 1) then we don't need to
+                       // compare penalty times. But if we found an equal match, then we compare
+                       // the penalty times to pick a better match
+
+                       if ((bettermatch == 1) || ((bettermatch == 0) && currPenaltyTime < bestPenaltyTime))
+                               { curmatch = curr; bestmatchlen = currcount; bestPenaltyTime = currPenaltyTime;}
+                       }
+               }
+
+       return curmatch;
+       }
+
 // Look up a DNS Server, matching by name in split-dns configurations.
-mDNSexport DNSServer *GetServerForName(mDNS *m, const domainname *name)
+mDNSexport DNSServer *GetServerForName(mDNS *m, const domainname *name, DNSServer *prev)
     {
-       DNSServer *curmatch = mDNSNULL, *p;
-       int curmatchlen = -1, ncount = name ? CountLabels(name) : 0;
+       DNSServer *curmatch = mDNSNULL;
 
-       for (p = m->DNSServers; p; p = p->next)
+       // prev is the previous DNS server used by some question
+       if (prev != mDNSNULL)
                {
-               int scount = CountLabels(&p->domain);
-               if (!(p->flags & DNSServer_FlagDelete) && ncount >= scount && scount > curmatchlen)
-                       if (SameDomainName(SkipLeadingLabels(name, ncount - scount), &p->domain))
-                               { curmatch = p; curmatchlen = scount; }
+               curmatch = GetNextUnPenalizedServer(m, prev);
+               if (curmatch != mDNSNULL) 
+                       {
+                       LogInfo("GetServerForName: Good DNS server %#a:%d (Penalty Time Left %d) found", &curmatch->addr,
+                           mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0));
+                       return curmatch;
+                       }
                }
+       
+       // We are here for many reasons.
+       //
+       // 1. We are looking up the DNS server first time for this question
+       // 2. We reached the end of list looking for unpenalized servers
+       //
+       // In the case of (1) we want to find the best match for the name. If nothing is penalized,
+       // we want the first one in the list. If some are penalized, we want the one that will get
+       // out of penalty box sooner
+       //
+       // In the case of (2) we want to select the first server that matches the name if StrictUnicastOrdering
+       // is TRUE. As penaltyTime is zero for all of them in that case, we automatically achieve that below.
+       // If StrictUnicastOrdering is FALSE, we want to pick the least penalized server in the list
+
+       curmatch = GetAnyBestServer(m, name);
+
+       if (curmatch != mDNSNULL) 
+               LogInfo("GetServerForName: DNS server %#a:%d (Penalty Time Left %d) found", &curmatch->addr,
+                   mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0));
+       else
+               LogInfo("GetServerForName: no DNS server found");
+
        return(curmatch);
        }
 
@@ -7444,7 +7707,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
                        // this routine with the question list data structures in an inconsistent state.
                        if (!mDNSOpaque16IsZero(question->TargetQID))
                                {
-                               question->qDNSServer = GetServerForName(m, &question->qname);
+                               question->qDNSServer = GetServerForName(m, &question->qname, mDNSNULL);
                                ActivateUnicastQuery(m, question, mDNSfalse);
 
                                // If long-lived query, and we don't have our NAT mapping active, start it now
@@ -9081,16 +9344,36 @@ mDNSexport mDNSOpaque16 mDNS_NewMessageID(mDNS * const m)
 #pragma mark - Sleep Proxy Server
 #endif
 
-mDNSlocal void RestartProbing(mDNS *const m, AuthRecord *const rr)
-       {
-       // We reset ProbeCount, so we'll suppress our own answers for a while, to avoid generating ARP conflicts with a waking machine.
-       // If the machine does wake properly then we'll discard our records when we see the first new mDNS probe from that machine.
-       // If it does not wake (perhaps we just picked up a stray delayed packet sent before it went to sleep)
-       // then we'll transition out of probing state and start answering ARPs again.
+mDNSlocal void RestartARPProbing(mDNS *const m, AuthRecord *const rr)
+       {
+       // If we see an ARP from a machine we think is sleeping, then either
+       // (i) the machine has woken, or
+       // (ii) it's just a stray old packet from before the machine slept
+       // To handle the second case, we reset ProbeCount, so we'll suppress our own answers for a while, to avoid
+       // generating ARP conflicts with a waking machine, and set rr->LastAPTime so we'll start probing again in 10 seconds.
+       // If the machine has just woken then we'll discard our records when we see the first new mDNS probe from that machine.
+       // If it was a stray old packet, then after 10 seconds we'll probe again and then start answering ARPs again. In this case we *do*
+       // need to send new ARP Announcements, because the owner's ARP broadcasts will have updated neighboring ARP caches, so we need to
+       // re-assert our (temporary) ownership of that IP address in order to receive subsequent packets addressed to that IPv4 address.
+       
        rr->resrec.RecordType = kDNSRecordTypeUnique;
        rr->ProbeCount        = DefaultProbeCountForTypeUnique;
-       rr->AnnounceCount     = InitialAnnounceCount;
-       InitializeLastAPTime(m, rr);
+
+       // If we haven't started announcing yet (and we're not already in ten-second-delay mode) the machine is probably
+       // still going to sleep, so we just reset rr->ProbeCount so we'll continue probing until it stops responding.
+       // If we *have* started announcing, the machine is probably in the process of waking back up, so in that case
+       // we're more cautious and we wait ten seconds before probing it again. We do this because while waking from
+       // sleep, some network interfaces tend to lose or delay inbound packets, and without this delay, if the waking machine
+       // didn't answer our three probes within three seconds then we'd announce and cause it an unnecessary address conflict.
+       if (rr->AnnounceCount == InitialAnnounceCount && m->timenow - rr->LastAPTime >= 0)
+               InitializeLastAPTime(m, rr);
+       else
+               {
+               rr->AnnounceCount  = InitialAnnounceCount;
+               rr->ThisAPInterval = mDNSPlatformOneSecond;
+               rr->LastAPTime     = m->timenow + mDNSPlatformOneSecond * 9;    // Send first packet at rr->LastAPTime + rr->ThisAPInterval, i.e. 10 seconds from now
+               SetNextAnnounceProbeTime(m, rr);
+               }
        }
 
 mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID)
@@ -9115,13 +9398,18 @@ mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, c
 
                // Pass 1:
                // Process ARP Requests and Probes (but not Announcements), and generate an ARP Reply if necessary.
-               // We also process and answer ARPs from our own kernel (no special treatment for localhost).
+               // We also process ARPs from our own kernel (and 'answer' them by injecting a local ARP table entry)
                // We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them.
-               // The only time we might need to respond to an ARP Announcement is if it's a conflict -- and we check for that in Pass 2 below.
+               // The times we might need to react to an ARP Announcement are:
+               // (i) as an indication that the host in question has not gone to sleep yet (so we should delay beginning to proxy for it) or
+               // (ii) if it's a conflicting Announcement from another host
+               // -- and we check for these in Pass 2 below.
                if (mDNSSameOpaque16(arp->op, ARP_op_request) && !mDNSSameIPv4Address(arp->spa, arp->tpa))
                        for (rr = m->ResourceRecords; rr; rr=rr->next)
                                if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->tpa))
                                        {
+                                       char *ifname = InterfaceNameForID(m, InterfaceID);
+                                       if (!ifname) ifname = "<NULL InterfaceID>";
                                        static const char msg1[] = "ARP Req from owner -- re-probing";
                                        static const char msg2[] = "Ignoring  ARP Request from      ";
                                        static const char msg3[] = "Creating Local ARP Cache entry  ";
@@ -9130,8 +9418,8 @@ mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, c
                                                                                        (rr->AnnounceCount == InitialAnnounceCount)     ? msg2 :
                                                                                        mDNSSameEthAddress(&arp->sha, &intf->MAC)       ? msg3 : msg4;
                                        LogSPS("%-7s %s %.6a %.4a for %.4a -- H-MAC %.6a I-MAC %.6a %s",
-                                               InterfaceNameForID(m, InterfaceID), msg, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
-                                       if      (msg == msg1) RestartProbing(m, rr);
+                                               ifname, msg, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
+                                       if      (msg == msg1) RestartARPProbing(m, rr);
                                        else if (msg == msg3) mDNSPlatformSetLocalARP(&arp->tpa, &rr->WakeUp.IMAC, InterfaceID);
                                        else if (msg == msg4) SendARP(m, 2, rr, arp->tpa.b, arp->sha.b, arp->spa.b, arp->sha.b);
                                        }
@@ -9152,16 +9440,19 @@ mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, c
                                for (rr = m->ResourceRecords; rr; rr=rr->next)
                                        if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->spa))
                                                {
-                                               RestartProbing(m, rr);
+                                               char *ifname = InterfaceNameForID(m, InterfaceID);
+                                               if (!ifname) ifname = "<NULL InterfaceID>";
+
+                                               RestartARPProbing(m, rr);
                                                if (mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC))
                                                        LogSPS("%-7s ARP %s from owner %.6a %.4a for %-15.4a -- re-starting probing for %s",
-                                                               InterfaceNameForID(m, InterfaceID),
+                                                               ifname,
                                                                mDNSSameIPv4Address(arp->spa, arp->tpa) ? "Announcement" : mDNSSameOpaque16(arp->op, ARP_op_request) ? "Request     " : "Response    ",
                                                                &arp->sha, &arp->spa, &arp->tpa, ARDisplayString(m, rr));
                                                else
                                                        {
                                                        LogMsg("%-7s Conflicting ARP from %.6a %.4a for %.4a -- waking H-MAC %.6a I-MAC %.6a %s",
-                                                               InterfaceNameForID(m, InterfaceID), &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
+                                                               ifname, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
                                                        SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password);
                                                        }
                                                }
@@ -9178,10 +9469,8 @@ mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, c
                        {
                        #define SSH_AsNumber 22
                        #define ARD_AsNumber 3283
-                       #define IPSEC_AsNumber 4500
                        static const mDNSIPPort SSH   = { { SSH_AsNumber   >> 8, SSH_AsNumber   & 0xFF } };
                        static const mDNSIPPort ARD   = { { ARD_AsNumber   >> 8, ARD_AsNumber   & 0xFF } };
-                       static const mDNSIPPort IPSEC = { { IPSEC_AsNumber >> 8, IPSEC_AsNumber & 0xFF } };
 
                        mDNSBool wake = mDNSfalse;
                        mDNSIPPort port = zeroIPPort;
@@ -9215,27 +9504,51 @@ mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, c
 
                                case 17:        {
                                                        const UDPHeader *const udp = (const UDPHeader *)trans;
-                                                       mDNSu16 len = (mDNSu16)((mDNSu16)trans[4] << 8 | trans[5]);
-                                                       port = udp->dst;
-                                                       wake = mDNStrue;
-
-                                                       // For Back to My Mac UDP port 4500 (IPSEC) packets, we specially ignore NAT keepalive packets
-                                                       if (mDNSSameIPPort(port, IPSEC)) wake = (len != 9 || end < trans + 9 || trans[8] != 0xFF);
-
-                                                       // For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the
-                                                       // Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port),
-                                                       // except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this:
-                                                       // UDP header (8 bytes) 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 118 bytes total
-                                                       if (mDNSSameIPPort(port, ARD)) wake = (len >= 118 && end >= trans+10 && trans[8] == 0x13 && trans[9] == 0x88);
-
-                                                       LogSPS("%s %d-byte UDP from %.4a:%d to %.4a:%d", XX, &v4->src, mDNSVal16(udp->src), &v4->dst, mDNSVal16(port));
+                                                       const mDNSu16 udplen = (mDNSu16)((mDNSu16)trans[4] << 8 | trans[5]);            // Length *including* 8-byte UDP header
+                                                       if (udplen >= sizeof(UDPHeader))
+                                                               {
+                                                               const mDNSu16 datalen = udplen - sizeof(UDPHeader);
+                                                               port = udp->dst;
+                                                               wake = mDNStrue;
+
+                                                               // For Back to My Mac UDP port 4500 (IPSEC) packets, we do some special handling
+                                                               if (mDNSSameIPPort(port, IPSECPort))
+                                                                       {
+                                                                       // Specifically ignore NAT keepalive packets
+                                                                       if (datalen == 1 && end >= trans + 9 && trans[8] == 0xFF) wake = mDNSfalse;
+                                                                       else
+                                                                               {
+                                                                               // Skip over the Non-ESP Marker if present
+                                                                               const mDNSBool NonESP = (end >= trans + 12 && trans[8] == 0 && trans[9] == 0 && trans[10] == 0 && trans[11] == 0);
+                                                                               const IKEHeader *const ike    = (IKEHeader *)(trans + (NonESP ? 12 : 8));
+                                                                               const mDNSu16          ikelen = datalen - (NonESP ? 4 : 0);
+                                                                               if (ikelen >= sizeof(IKEHeader) && end >= ((mDNSu8 *)ike) + sizeof(IKEHeader))
+                                                                                       if ((ike->Version & 0x10) == 0x10)
+                                                                                               {
+                                                                                               // ExchangeType ==  5 means 'Informational' <http://www.ietf.org/rfc/rfc2408.txt>
+                                                                                               // ExchangeType == 34 means 'IKE_SA_INIT'   <http://www.iana.org/assignments/ikev2-parameters>
+                                                                                               if (ike->ExchangeType == 5 || ike->ExchangeType == 34) wake = mDNSfalse;
+                                                                                               LogSPS("%s %d-byte IKE ExchangeType %d", XX, ike->ExchangeType);
+                                                                                               }
+                                                                               }
+                                                                       }
+
+                                                               // For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the
+                                                               // Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port),
+                                                               // except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this:
+                                                               // UDP header (8 bytes)
+                                                               // Payload: 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 110 bytes total
+                                                               if (mDNSSameIPPort(port, ARD)) wake = (datalen >= 110 && end >= trans+10 && trans[8] == 0x13 && trans[9] == 0x88);
+
+                                                               LogSPS("%s %d-byte UDP from %.4a:%d to %.4a:%d", XX, &v4->src, mDNSVal16(udp->src), &v4->dst, mDNSVal16(port));
+                                                               }
                                                        }
                                                        break;
 
                                default:        LogSPS("%s %d-byte IP packet unknown protocol %d from %.4a to %.4a", XX, v4->protocol, &v4->src, &v4->dst);
                                                        break;
                                }
-       
+
                        if (wake)
                                {
                                AuthRecord *rr, *r2;
@@ -9251,17 +9564,19 @@ mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, c
                                                                r2->resrec.rrtype == kDNSType_SRV && mDNSSameIPPort(r2->resrec.rdata->u.srv.port, port) &&
                                                                SameDomainLabel(ThirdLabel(r2->resrec.name)->c, tp))
                                                                break;
-                                               if (!r2 && mDNSSameIPPort(port, IPSEC)) r2 = rr;        // So that we wake for BTMM IPSEC packets, even without a matching SRV record
+                                               if (!r2 && mDNSSameIPPort(port, IPSECPort)) r2 = rr;    // So that we wake for BTMM IPSEC packets, even without a matching SRV record
+                                               char *ifname = InterfaceNameForID(m, rr->resrec.InterfaceID);
+                                               if (!ifname) ifname = "<NULL InterfaceID>";
                                                if (r2)
                                                        {
                                                        rr->AnnounceCount = 0;
                                                        LogMsg("Waking host at %s %.4a H-MAC %.6a I-MAC %.6a for %s",
-                                                               InterfaceNameForID(m, rr->resrec.InterfaceID), &v4->dst, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, r2));
+                                                               ifname, &v4->dst, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, r2));
                                                        SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password);
                                                        }
                                                else
                                                        LogSPS("Sleeping host at %s %.4a %.6a has no service on %#s %d",
-                                                               InterfaceNameForID(m, rr->resrec.InterfaceID), &v4->dst, &rr->WakeUp.HMAC, tp, mDNSVal16(port));
+                                                               ifname, &v4->dst, &rr->WakeUp.HMAC, tp, mDNSVal16(port));
                                                }
                                mDNS_Unlock(m);
                                }
@@ -9415,6 +9730,8 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        m->SleepState              = SleepState_Awake;
        m->SleepSeqNum             = 0;
        m->SystemWakeOnLANEnabled  = mDNSfalse;
+       m->SentSleepProxyRegistration = mDNSfalse;
+       m->AnnounceOwner           = 0;
        m->DelaySleep              = 0;
        m->SleepLimit              = 0;
 
@@ -9587,7 +9904,11 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
        // Let the platform layer get the current DNS information
        // The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand
        // (no need to hit the network with domain enumeration queries until we actually need that information).
-       for (ptr = m->DNSServers; ptr; ptr = ptr->next) ptr->flags |= DNSServer_FlagDelete;
+       for (ptr = m->DNSServers; ptr; ptr = ptr->next)
+               {
+               ptr->penaltyTime = 0;
+               ptr->flags |= DNSServer_FlagDelete;
+               }
 
        mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL);
 
@@ -9595,7 +9916,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
        for (q = m->Questions; q; q=q->next)
                if (!mDNSOpaque16IsZero(q->TargetQID))
                        {
-                       DNSServer *s = GetServerForName(m, &q->qname);
+                       DNSServer *s = GetServerForName(m, &q->qname, mDNSNULL);
                        DNSServer *t = q->qDNSServer;
                        if (t != s)
                                {
@@ -9606,6 +9927,10 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
                                        q->qname.c, DNSTypeName(q->qtype));
                                q->qDNSServer = s;
                                q->unansweredQueries = 0;
+                               
+                               // Change the query ID so that we won't cache responses to any in-flight queries
+                               q->TargetQID = mDNS_NewMessageID(m);
+
                                ActivateUnicastQuery(m, q, mDNStrue);
                                }
                        }
@@ -9613,8 +9938,9 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
        // Flush all records that match a new resolver
        FORALL_CACHERECORDS(slot, cg, cr)
                {
-               ptr = GetServerForName(m, cr->resrec.name);
-               if (ptr && (ptr->flags & DNSServer_FlagNew) && !cr->resrec.InterfaceID)
+               if (cr->resrec.InterfaceID) continue;
+               ptr = GetServerForName(m, cr->resrec.name, mDNSNULL);
+               if (ptr && (ptr->flags & DNSServer_FlagNew))
                        PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse);
                }
        
@@ -9628,7 +9954,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
                        ptr = *p;
                        ptr->flags &= ~DNSServer_FlagDelete;    // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted
                        FORALL_CACHERECORDS(slot, cg, cr)
-                               if (!cr->resrec.InterfaceID && GetServerForName(m, cr->resrec.name) == ptr)
+                               if (!cr->resrec.InterfaceID && GetServerForName(m, cr->resrec.name, mDNSNULL) == ptr)
                                        PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNStrue);
                        *p = (*p)->next;
                        debugf("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
@@ -9651,12 +9977,11 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
                FORALL_CACHERECORDS(slot, cg, cr) if (!cr->resrec.InterfaceID) { mDNS_PurgeCacheResourceRecord(m, cr); count++; }
                LogInfo("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache",
                        m->DNSServers ? "DNS server became" : "No DNS servers", count);
+
+               // Force anything that needs to get zone data to get that information again
+               RestartRecordGetZoneData(m);
                }
 
-       // If we no longer have any DNS servers, we need to force anything that needs to get zone data
-       // to get that information again (which will fail, since we have no more DNS servers)
-       if ((m->DNSServers == mDNSNULL) && (oldServers != mDNSNULL))    RestartRecordGetZoneData(m);
-       
        // Did our FQDN change?
        if (!SameDomainName(&fqdn, &m->FQDN))
                {
index 00329ec7e220539563dc667abdd96e0fe98558fe..621d534f7e2558a08a80e4530c24b5f01fa36c3a 100755 (executable)
     Change History (most recent first):
 
 $Log: mDNSEmbeddedAPI.h,v $
+Revision 1.577  2009/07/16 00:34:18  cheshire
+<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
+Additional refinement: If we didn't register with a Sleep Proxy when going to sleep,
+we don't need to include our OWNER option in our packets when we re-awaken
+
+Revision 1.576  2009/07/15 23:35:37  cheshire
+<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
+
 Revision 1.575  2009/07/11 01:57:00  cheshire
 <rdar://problem/6613674> Sleep Proxy: Add support for using sleep proxy in local network interface hardware
 Added declaration of ActivateLocalProxy
@@ -1466,6 +1474,18 @@ typedef packedstruct
        mDNSu16      checksum;
        } UDPHeader;                    // 8 bytes
 
+typedef packedstruct
+       {
+       mDNSOpaque64 InitiatorCookie;
+       mDNSOpaque64 ResponderCookie;
+       mDNSu8       NextPayload;
+       mDNSu8       Version;
+       mDNSu8       ExchangeType;
+       mDNSu8       Flags;
+       mDNSOpaque32 MessageID;
+       mDNSu32      Length;
+       } IKEHeader;                    // 28 bytes
+
 typedef packedstruct
        {
        mDNSIPPort   src;
@@ -1640,12 +1660,12 @@ typedef packedstruct
                                                ((O)->opt == kDNSOpt_Lease && (O)->optlen == DNSOpt_LeaseData_Space - 4) || \
                                                ((O)->opt == kDNSOpt_Owner && ValidOwnerLength((O)->optlen)            )    )
 
-#define DNSOpt_Owner_Space(O) (mDNSSameEthAddress(&(O)->u.owner.HMAC, &(O)->u.owner.IMAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space)
+#define DNSOpt_Owner_Space(A,B) (mDNSSameEthAddress((A),(B)) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space)
 
 #define DNSOpt_Data_Space(O) (                                  \
        (O)->opt == kDNSOpt_LLQ   ? DNSOpt_LLQData_Space   :        \
        (O)->opt == kDNSOpt_Lease ? DNSOpt_LeaseData_Space :        \
-       (O)->opt == kDNSOpt_Owner ? DNSOpt_Owner_Space(O)  : 0x10000)
+       (O)->opt == kDNSOpt_Owner ? DNSOpt_Owner_Space(&(O)->u.owner.HMAC, &(O)->u.owner.IMAC) : 0x10000)
 
 // A maximal NSEC record is:
 //   256 bytes domainname 'nextname'
@@ -2132,6 +2152,7 @@ typedef struct DNSServer
        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                 
        } DNSServer;
 
 typedef struct ExtraResourceRecord_struct ExtraResourceRecord;
@@ -2332,7 +2353,10 @@ struct DNSQuestion_struct
        LLQ_State             state;
        mDNSu32               ReqLease;                 // seconds (relative)
        mDNSs32               expire;                   // ticks (absolute)
-       mDNSs16               ntries;
+       mDNSs16               ntries;           // for UDP: the number of packets sent for this LLQ state
+                                              // 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
        mDNSOpaque64          id;
 
        // Client API fields: The client must set up these fields *before* calling mDNS_StartQuery()
@@ -2573,6 +2597,8 @@ struct mDNS_struct
        mDNSu8   SleepState;                            // Set if we're sleeping
        mDNSu8   SleepSeqNum;                           // "Epoch number" of our current period of wakefulness
        mDNSu8   SystemWakeOnLANEnabled;        // Set if we want to register with a Sleep Proxy before going to sleep
+       mDNSu8   SentSleepProxyRegistration;// Set if we registered (or tried to register) with a Sleep Proxy
+       mDNSs32  AnnounceOwner;                         // After waking from sleep, include OWNER option in packets until this time
        mDNSs32  DelaySleep;                            // To inhibit re-sleeping too quickly right after wake
        mDNSs32  SleepLimit;                            // Time window to allow deregistrations, etc.,
                                                                                // during which underying platform layer should inhibit system sleep
@@ -2710,6 +2736,7 @@ extern const OwnerOptData    zeroOwner;
 extern const mDNSInterfaceID mDNSInterface_Any;                                // Zero
 extern const mDNSInterfaceID mDNSInterface_LocalOnly;          // Special value
 extern const mDNSInterfaceID mDNSInterface_Unicast;                    // Special value
+extern const mDNSInterfaceID mDNSInterfaceMark;                                // Special value
 
 extern const mDNSIPPort   DiscardPort;
 extern const mDNSIPPort   SSHPort;
@@ -2739,6 +2766,8 @@ extern const mDNSOpaque16 UpdateRespFlags;
 
 extern const mDNSOpaque64 zeroOpaque64;
 
+extern mDNSBool StrictUnicastOrdering;
+
 #define localdomain           (*(const domainname *)"\x5" "local")
 #define DeviceInfoName        (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp")
 #define SleepProxyServiceType (*(const domainname *)"\xC" "_sleep-proxy" "\x4" "_udp")
@@ -2968,7 +2997,7 @@ extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainT
 
 extern mDNSOpaque16 mDNS_NewMessageID(mDNS *const m);
                
-extern DNSServer *GetServerForName(mDNS *m, const domainname *name);
+extern DNSServer *GetServerForName(mDNS *m, const domainname *name, DNSServer *current);
 
 // ***************************************************************************
 #if 0
@@ -3167,7 +3196,7 @@ extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCa
 extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
 extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr,  const mDNSAddr *v6addr, const mDNSAddr *router);
 extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port);
-extern void PushDNSServerToEnd(mDNS *const m, DNSQuestion *q);
+extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSBool QueryFail);
 extern void mDNS_AddSearchDomain(const domainname *const domain);
 
 // We use ((void *)0) here instead of mDNSNULL to avoid compile warnings on gcc 4.2
@@ -3418,6 +3447,7 @@ extern void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const Cach
 #define SPSMetric(X) (!ValidSPSName(X) || PrototypeSPSName(X) ? 1000000 : \
        ((X)[1]-'0') * 100000 + ((X)[2]-'0') * 10000 + ((X)[4]-'0') * 1000 + ((X)[5]-'0') * 100 + ((X)[7]-'0') * 10 + ((X)[8]-'0'))
 extern void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord);
+extern char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID);
 
 // For now this AutoTunnel stuff is specific to Mac OS X.
 // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
@@ -3466,7 +3496,8 @@ struct CompileTimeAssertionChecks_mDNS
        char assertI[(sizeof(IPv6Header    )   ==   40                         ) ? 1 : -1];
        char assertJ[(sizeof(IPv6ND        )   ==   24                         ) ? 1 : -1];
        char assertK[(sizeof(UDPHeader     )   ==    8                         ) ? 1 : -1];
-       char assertL[(sizeof(TCPHeader     )   ==   20                         ) ? 1 : -1];
+       char assertL[(sizeof(IKEHeader     )   ==   28                         ) ? 1 : -1];
+       char assertM[(sizeof(TCPHeader     )   ==   20                         ) ? 1 : -1];
 
        // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
        // other overly-large structures instead of having a pointer to them, can inadvertently
index 962c53656df50a89641612a0d2aa3db92b1ad64a..992e2141bd3dac23609b61ed1224a60326318e37 100755 (executable)
@@ -1345,6 +1345,9 @@ mDNSexport SearchListElem *SearchList = mDNSNULL;
 // would avoid the perils of modifying that list cleanly while some other piece of code is iterating through it.
 ServiceRecordSet *CurrentServiceRecordSet = mDNSNULL;
 
+// The value can be set to true by the Platform code e.g., MacOSX uses the plist mechanism
+mDNSBool StrictUnicastOrdering = mDNSfalse;
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark - General Utility Functions
@@ -1486,44 +1489,110 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
                        (*p)->next = mDNSNULL;
                        }
                }
+       (*p)->penaltyTime = 0;
        return(*p);
        }
 
-mDNSexport void PushDNSServerToEnd(mDNS *const m, DNSQuestion *q)
+// PenalizeDNSServer is called when the number of queries to the unicast
+// DNS server exceeds MAX_UCAST_UNANSWERED_QUERIES or when we receive an
+// error e.g., SERV_FAIL from DNS server. QueryFail is TRUE if this function
+// is called when we exceed MAX_UCAST_UNANSWERED_QUERIES
+
+mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSBool QueryFail)
        {
        DNSServer *orig = q->qDNSServer;
-       DNSServer **p = &m->DNSServers;
        
        if (m->mDNS_busy != m->mDNS_reentrancy+1)
-               LogMsg("PushDNSServerToEnd: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+               LogMsg("PenalizeDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
        if (!q->qDNSServer)
                {
-               LogMsg("PushDNSServerToEnd: Null DNS server for %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), q->unansweredQueries);
+               LogMsg("PenalizeDNSServer: Null DNS server for %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), q->unansweredQueries);
                goto end;
                }
 
-       LogInfo("PushDNSServerToEnd: Pushing DNS server %#a:%d (%##s) due to %d unanswered queries for %##s (%s)",
+       if (QueryFail)
+               {
+                       LogInfo("PenalizeDNSServer: DNS server %#a:%d (%##s) %d unanswered queries for %##s (%s)",
                &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype));
-
-       while (*p)
+               }
+       else
                {
-               if (*p == q->qDNSServer) *p = q->qDNSServer->next;
-               else p=&(*p)->next;
+                       LogInfo("PenalizeDNSServer: DNS server %#a:%d (%##s) Server Error for %##s (%s)",
+               &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->qname.c, DNSTypeName(q->qtype));
                }
 
-       *p = q->qDNSServer;
-       q->qDNSServer->next = mDNSNULL;
+
+       // If strict ordering of unicast servers needs to be preserved, we just lookup
+       // the next best match server below
+       //
+       // If strict ordering is not required which is the default behavior, we penalize the server
+       // for DNSSERVER_PENALTY_TIME. We may also use additional logic e.g., don't penalize for PTR
+       // in the future.
+
+       if (!StrictUnicastOrdering)
+               {
+               LogInfo("PenalizeDNSServer: Strict Unicast Ordering is FALSE");
+               // We penalize the server so that new queries don't pick this server for DNSSERVER_PENALTY_TIME
+               // XXX Include other logic here to see if this server should really be penalized
+               //
+               if (q->qtype == kDNSType_PTR)
+                       {
+                       LogInfo("PenalizeDNSServer: Not Penalizing PTR question");
+                       }
+               else
+                       {
+                       LogInfo("PenalizeDNSServer: Penalizing question type %d", q->qtype);
+                       q->qDNSServer->penaltyTime = NonZeroTime(m->timenow + DNSSERVER_PENALTY_TIME);
+                       }
+               }
+       else
+               {
+               LogInfo("PenalizeDNSServer: Strict Unicast Ordering is TRUE");
+               }
 
 end:
-       q->qDNSServer = GetServerForName(m, &q->qname);
+       q->qDNSServer = GetServerForName(m, &q->qname, q->qDNSServer);
+
+       if ((q->qDNSServer != orig) && (QueryFail))
+               {
+               // We picked a new server. In the case where QueryFail is true, the code has already incremented the interval
+               // and to compensate that we decrease it here.  When two queries are sent, the QuestionIntervalStep is at 9. We just
+               // move it back to 3 here when we pick a new server. We can't start at 1 because if we have two servers failing, we will never
+               // backoff 
+               //
+               q->ThisQInterval = q->ThisQInterval / QuestionIntervalStep;
+               if (q->qDNSServer) LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to %#a:%d (%##s), Question Interval %u", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->ThisQInterval);
+               else               LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to <null>, Question Interval %u",        q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
 
-       if (q->qDNSServer != orig)
+               }
+       else 
                {
-               if (q->qDNSServer) LogInfo("PushDNSServerToEnd: Server for %##s (%s) changed to %#a:%d (%##s)", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c);
-               else               LogInfo("PushDNSServerToEnd: Server for %##s (%s) changed to <null>",        q->qname.c, DNSTypeName(q->qtype));
-               q->ThisQInterval = q->ThisQInterval / QuestionIntervalStep; // Decrease interval one step so we don't quickly bounce between servers for queries that will not be answered.
+               // if we are here it means,
+               //
+               // 1) We picked the same server, QueryFail = false
+               // 2) We picked the same server, QueryFail = true 
+               // 3) We picked a different server, QueryFail = false
+               //
+               // For all these three cases, ThisQInterval is already set properly
+
+               if (q->qDNSServer) 
+                       {
+                       if (q->qDNSServer != orig)
+                               {
+                               LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to %#a:%d (%##s)", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c);
+                               }
+                               else
+                               {
+                               LogInfo("PenalizeDNSServer: Server for %##s (%s) remains the same at %#a:%d (%##s)", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c);
+                               }
+                       }
+               else
+                       { 
+                       LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to <null>",        q->qname.c, DNSTypeName(q->qtype));
+                       }
                }
+       q->unansweredQueries = 0;
        }
 
 // ***************************************************************************
@@ -2213,6 +2282,7 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
                // connection is established - send the message
                if (q && q->LongLived && q->state == LLQ_Established)
                        {
+                       // Lease renewal over TCP, resulting from opening a TCP connection in sendLLQRefresh
                        end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
                        }
                else if (q && q->LongLived && q->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort) && !mDNSIPPortIsZero(q->servPort))
@@ -2232,9 +2302,11 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
                        end = putLLQ(&tcpInfo->request, tcpInfo->request.data, q, &llqData);
                        if (!end) { LogMsg("ERROR: tcpCallback - putLLQ"); err = mStatus_UnknownErr; goto exit; }
                        AuthInfo = q->AuthInfo;         // Need to add TSIG to this message
+                       q->ntries = 0; // Reset ntries so that tcp/tls connection failures don't affect sendChallengeResponse failures
                        }
                else if (q)
                        {
+                       // LLQ Polling mode or non-LLQ uDNS over TCP
                        InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, uQueryFlags);
                        end = putQuestion(&tcpInfo->request, tcpInfo->request.data, tcpInfo->request.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
                        AuthInfo = q->AuthInfo;         // Need to add TSIG to this message
@@ -2261,16 +2333,33 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
                        {
                        mDNSu8 *lenptr = (mDNSu8 *)&tcpInfo->replylen;
                        n = mDNSPlatformReadTCP(sock, lenptr + tcpInfo->nread, 2 - tcpInfo->nread, &closed);
-                       if (n < 0) { LogMsg("ERROR: tcpCallback - attempt to read message length failed (%d)", n); err = mStatus_ConnFailed; goto exit; }
+                       if (n < 0)
+                               {
+                               LogMsg("ERROR: tcpCallback - attempt to read message length failed (%d)", n);
+                               err = mStatus_ConnFailed;
+                               goto exit;
+                               }
                        else if (closed)
                                {
                                // It's perfectly fine for this socket to close after the first reply. The server might
                                // be sending gratuitous replies using UDP and doesn't have a need to leave the TCP socket open.
                                // We'll only log this event if we've never received a reply before.
                                // BIND 9 appears to close an idle connection after 30 seconds.
-                               if (tcpInfo->numReplies == 0) LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo->nread);
-                               err = mStatus_ConnFailed;
-                               goto exit;
+                               if (tcpInfo->numReplies == 0)
+                                       {
+                                       LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo->nread);
+                                       err = mStatus_ConnFailed;
+                                       goto exit;
+                                       }
+                               else
+                                       {
+                                       // Note that we may not be doing the best thing if an error occurs after we've sent a second request
+                                       // over this tcp connection.  That is, we only track whether we've received at least one response
+                                       // which may have been to a previous request sent over this tcp connection.
+                                       if (backpointer) *backpointer = mDNSNULL; // Clear client backpointer FIRST so we don't risk double-disposing our tcpInfo_t 
+                                       DisposeTCPConn(tcpInfo);
+                                       return;
+                                       }
                                }
 
                        tcpInfo->nread += n;
@@ -2286,8 +2375,30 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
 
                n = mDNSPlatformReadTCP(sock, ((char *)tcpInfo->reply) + (tcpInfo->nread - 2), tcpInfo->replylen - (tcpInfo->nread - 2), &closed);
 
-               if      (n < 0)  { LogMsg("ERROR: tcpCallback - read returned %d", n);            err = mStatus_ConnFailed; goto exit; }
-               else if (closed) { LogMsg("ERROR: socket closed prematurely %d", tcpInfo->nread); err = mStatus_ConnFailed; goto exit; }
+               if (n < 0)
+                       {
+                       LogMsg("ERROR: tcpCallback - read returned %d", n);
+                       err = mStatus_ConnFailed;
+                       goto exit;
+                       }
+               else if (closed)
+                       {
+                       if (tcpInfo->numReplies == 0)
+                               {
+                               LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo->nread);
+                               err = mStatus_ConnFailed;
+                               goto exit;
+                               }
+                       else
+                               {
+                               // Note that we may not be doing the best thing if an error occurs after we've sent a second request
+                               // over this tcp connection.  That is, we only track whether we've received at least one response
+                               // which may have been to a previous request sent over this tcp connection.
+                               if (backpointer) *backpointer = mDNSNULL; // Clear client backpointer FIRST so we don't risk double-disposing our tcpInfo_t 
+                               DisposeTCPConn(tcpInfo);
+                               return;
+                               }
+                       }
 
                tcpInfo->nread += n;
 
@@ -2338,14 +2449,58 @@ exit:
 
                if (q)
                        {
-                       if (q->ThisQInterval == 0 || q->LastQTime + q->ThisQInterval - m->timenow > MAX_UCAST_POLL_INTERVAL)
+                       if (q->ThisQInterval == 0)
+                               {
+                               // We get here when we fail to establish a new TCP/TLS connection that would have been used for a new LLQ request or an LLQ renewal.
+                               // Note that ThisQInterval is also zero when sendChallengeResponse resends the LLQ request on an extant TCP/TLS connection.
+                               q->LastQTime = m->timenow;
+                               if (q->LongLived)
+                                       {
+                                       // We didn't get the chance to send our request packet before the TCP/TLS connection failed.
+                                       // We want to retry quickly, but want to back off exponentially in case the server is having issues.
+                                       // Since ThisQInterval was 0, we can't just multiply by QuestionIntervalStep, we must track the number
+                                       // of TCP/TLS connection failures using ntries.
+                                       mDNSu32 count = q->ntries + 1; // want to wait at least 1 second before retrying
+
+                                       q->ThisQInterval = InitialQuestionInterval;
+
+                                       for (;count;count--)
+                                               q->ThisQInterval *= QuestionIntervalStep;
+
+                                       if (q->ThisQInterval > LLQ_POLL_INTERVAL)
+                                               q->ThisQInterval = LLQ_POLL_INTERVAL;
+                                       else
+                                               q->ntries++;
+                                               
+                                       LogMsg("tcpCallback: stream connection for LLQ %##s (%s) failed %d times, retrying in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ntries, q->ThisQInterval);
+                                       }
+                               else
+                                       {
+                                       q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
+                                       LogMsg("tcpCallback: stream connection for %##s (%s) failed, retrying in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
+                                       }
+                               SetNextQueryTime(m, q);
+                               }
+                       else if (q->LastQTime + q->ThisQInterval - m->timenow > (q->LongLived ? LLQ_POLL_INTERVAL : MAX_UCAST_POLL_INTERVAL))
                                {
+                               // If we get an error and our next scheduled query for this question is more than the max interval from now,
+                               // reset the next query to ensure we wait no longer the maximum interval from now before trying again.
                                q->LastQTime     = m->timenow;
-                               q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
+                               q->ThisQInterval = q->LongLived ? LLQ_POLL_INTERVAL : MAX_UCAST_POLL_INTERVAL;
                                SetNextQueryTime(m, q);
+                               LogMsg("tcpCallback: stream connection for %##s (%s) failed, retrying in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
                                }
-                       // ConnFailed may be actually okay. It just means that the server closed the connection but the LLQ may still be okay.
-                       // If the error isn't ConnFailed, then the LLQ is in bad shape.
+                       
+                       // We're about to dispose of the TCP connection, so we must reset the state to retry over TCP/TLS
+                       // because sendChallengeResponse will send the query via UDP if we don't have a tcp pointer.
+                       // Resetting to LLQ_InitialRequest will cause uDNS_CheckCurrentQuestion to call startLLQHandshake, which
+                       // will attempt to establish a new tcp connection.
+                       if (q->LongLived && q->state == LLQ_SecondaryRequest)
+                               q->state = LLQ_InitialRequest;
+                       
+                       // ConnFailed may happen if the server sends a TCP reset or TLS fails, in which case we want to retry establishing the LLQ
+                       // quickly rather than switching to polling mode.  This case is handled by the above code to set q->ThisQInterval just above.
+                       // If the error isn't ConnFailed, then the LLQ is in bad shape, so we switch to polling mode.
                        if (err != mStatus_ConnFailed)
                                {
                                if (q->LongLived && q->state != LLQ_Poll) StartLLQPolling(m, q);
@@ -3451,14 +3606,21 @@ mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, co
 
                if (v4Changed || RouterChanged)
                        {
+                       // If we have a non-zero IPv4 address, we should try immediately to see if we have a NAT gateway
+                       // If we have no IPv4 address, we don't want to be in quite such a hurry to report failures to our clients
+                       // <rdar://problem/6935929> Sleeping server sometimes briefly disappears over Back to My Mac after it wakes up
                        m->ExternalAddress      = zerov4Addr;
                        m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
-                       m->retryGetAddr         = m->timenow;
+                       m->retryGetAddr         = m->timenow + (v4addr ? 0 : mDNSPlatformOneSecond * 5);
                        m->NextScheduledNATOp   = m->timenow;
                        m->LastNATMapResultCode = NATErr_None;
 #ifdef _LEGACY_NAT_TRAVERSAL_
                        LNT_ClearState(m);
 #endif // _LEGACY_NAT_TRAVERSAL_
+                       LogInfo("mDNS_SetPrimaryInterfaceInfo:%s%s: retryGetAddr in %d %d",
+                               v4Changed     ? " v4Changed"     : "",
+                               RouterChanged ? " RouterChanged" : "",
+                               m->retryGetAddr - m->timenow, m->timenow);
                        }
 
                if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, &m->ReverseMap);
@@ -4707,8 +4869,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                        DNSServer *orig = q->qDNSServer;
                        if (orig) LogInfo("Sent %d unanswered queries for %##s (%s) to %#a:%d (%##s)", q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype), &orig->addr, mDNSVal16(orig->port), orig->domain.c);
 
-                       PushDNSServerToEnd(m, q);
-                       q->unansweredQueries = 0;
+                       PenalizeDNSServer(m, q, mDNStrue);
                        }
 
                if (q->qDNSServer && q->qDNSServer->teststate != DNSServer_Disabled)
@@ -4740,7 +4901,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                                        {
                                        if (q->nta) CancelGetZoneData(m, q->nta);
                                        q->nta = StartGetZoneData(m, &q->qname, q->LongLived ? ZoneServiceLLQ : ZoneServiceQuery, PrivateQueryGotZoneData, q);
-                                       q->ThisQInterval = (LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10)) / QuestionIntervalStep;
+                                       if (q->state == LLQ_Poll) q->ThisQInterval = (LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10)) / QuestionIntervalStep;
                                        }
                                else
                                        {
@@ -4758,6 +4919,16 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                                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);
+                                       }
                                debugf("Increased ThisQInterval to %d for %##s (%s)", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype));
                                }
                        q->LastQTime = m->timenow;
@@ -4781,7 +4952,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                                for (rr = cg->members; rr; rr=rr->next)
                                        if (SameNameRecordAnswersQuestion(&rr->resrec, q)) mDNS_PurgeCacheResourceRecord(m, rr);
 
-                       if (!q->qDNSServer) debugf("uDNS_CheckCurrentQuestion no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+                       if (!q->qDNSServer) LogInfo("uDNS_CheckCurrentQuestion no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
                        else LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qname.c);
 
                        MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any);
@@ -4840,6 +5011,8 @@ mDNSlocal void CheckNATMappings(mDNS *m)
                                else if (m->retryIntervalGetAddr < NATMAP_MAX_RETRY_INTERVAL / 2) m->retryIntervalGetAddr *= 2;
                                else                                                              m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL;
                                }
+                       LogInfo("CheckNATMappings retryGetAddr sent address request err %d interval %d", err, m->retryIntervalGetAddr);
+
                        // Always update m->retryGetAddr, even if we fail to send the packet. Otherwise in cases where we can't send the packet
                        // (like when we have no active interfaces) we'll spin in an infinite loop repeatedly failing to send the packet
                        m->retryGetAddr = m->timenow + m->retryIntervalGetAddr;
@@ -4996,6 +5169,40 @@ mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m)
        return nextevent;
        }
 
+// This function is called early on in mDNS_Execute before any uDNS questions are
+// dispatched so that if there are some good servers, the uDNS questions can now
+// use it
+mDNSexport void ResetDNSServerPenalties(mDNS *m)
+       {
+       DNSServer *d;
+       for (d = m->DNSServers; d; d=d->next)
+               {
+               if (d->penaltyTime != 0)
+                       {
+                       if (d->penaltyTime - m->timenow <= 0)
+                               {
+                               LogInfo("ResetDNSServerPenalties: DNS server %#a:%d out of penalty box", &d->addr, mDNSVal16(d->port));
+                               d->penaltyTime = 0;
+                               }
+                       }
+               }
+       }
+
+mDNSlocal mDNSs32 CheckDNSServerPenalties(mDNS *m)
+       {
+       mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
+       DNSServer *d;
+       for (d = m->DNSServers; d; d=d->next)
+               {
+               if (d->penaltyTime != 0)
+                       {
+                       if ((nextevent - d->penaltyTime) > 0)
+                               nextevent = d->penaltyTime;
+                       }
+               }
+       return nextevent;
+       }
+
 mDNSexport void uDNS_Execute(mDNS *const m)
        {
        mDNSs32 nexte;
@@ -5015,6 +5222,9 @@ mDNSexport void uDNS_Execute(mDNS *const m)
 
        nexte = CheckServiceRegistrations(m);
        if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
+
+       nexte = CheckDNSServerPenalties(m);
+       if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
        }
 
 // ***************************************************************************
index 71f40975b8c5090fdc02c10a48d13a1a93b2ac50..88beb9f569f223d1c188f194e26097b7dbf90bd1 100755 (executable)
@@ -236,6 +236,7 @@ Revision 1.33  2006/07/05 22:53:28  cheshire
 #define LLQ_POLL_INTERVAL       (15 * 60 * mDNSPlatformOneSecond) // Polling interval for zones w/ an advertised LLQ port (ie not static zones) if LLQ fails due to NAT, etc.
 #define RESPONSE_WINDOW (60 * mDNSPlatformOneSecond)         // require server responses within one minute of request
 #define MAX_UCAST_UNANSWERED_QUERIES 2                       // the number of unanswered queries from any one uDNS server before trying another server
+#define DNSSERVER_PENALTY_TIME (60 * mDNSPlatformOneSecond) // number of seconds for which new questions don't pick this server
 
 #define DEFAULT_UPDATE_LEASE 7200
 
@@ -289,6 +290,7 @@ extern void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *
 
 // returns time of next scheduled event
 extern void uDNS_Execute(mDNS *const m);
+extern void ResetDNSServerPenalties(mDNS *m);
 
 extern mStatus         uDNS_SetupDNSConfig(mDNS *const m);
 extern mStatus         uDNS_RegisterSearchDomains(mDNS *const m);
diff --git a/mDNSMacOSX/LaunchDaemonInfo-Tiger.helper.plist b/mDNSMacOSX/LaunchDaemonInfo-Tiger.helper.plist
new file mode 100644 (file)
index 0000000..895287c
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>Label</key>
+       <string>com.apple.mDNSResponderHelper</string>
+       <key>OnDemand</key>
+       <false/>
+       <key>ProgramArguments</key>
+       <array>
+               <string>/usr/sbin/mDNSResponderHelper</string>
+               <string>-t</string>
+               <string>0</string>
+       </array>
+       <key>ServiceIPC</key>
+       <false/>
+</dict>
+</plist>
diff --git a/mDNSMacOSX/LaunchDaemonInfo-Tiger.plist b/mDNSMacOSX/LaunchDaemonInfo-Tiger.plist
new file mode 100644 (file)
index 0000000..e91b775
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>Label</key>
+       <string>com.apple.mDNSResponder</string>
+       <key>OnDemand</key>
+       <false/>
+       <key>ProgramArguments</key>
+       <array>
+                       <string>/usr/sbin/mDNSResponder</string>
+                       <string>-launchdaemon</string>
+       </array>
+       <key>ServiceIPC</key>
+       <false/>
+</dict>
+</plist>
index 7e6db357f399ca940a6e3913e631dfcecf549220..69e23d6b53bcdde49309e06f0dc77ff13d568226 100644 (file)
@@ -668,6 +668,8 @@ static int restarting_via_mach_init = 0;    // Used on Jaguar/Panther when daemon i
 static int started_via_launchdaemon = 0;       // Indicates we're running on Tiger or later, where daemon is managed by launchd
 static mDNSBool advertise = mDNS_Init_AdvertiseLocalAddresses; // By default, advertise addresses (& other records) via multicast
 
+extern mDNSBool StrictUnicastOrdering;
+
 //*************************************************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -1388,7 +1390,7 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
        {
        kern_return_t status;
        DNSServiceResolver *x = (DNSServiceResolver *)query->ServiceInfoQueryContext;
-       NetworkInterfaceInfoOSX *ifx = (NetworkInterfaceInfoOSX *)query->info->InterfaceID;
+       NetworkInterfaceInfoOSX *ifx = IfindexToInterfaceInfoOSX(m, query->info->InterfaceID);
        if (query->info->InterfaceID == mDNSInterface_LocalOnly) ifx = mDNSNULL;
        struct sockaddr_storage interface;
        struct sockaddr_storage address;
@@ -2346,9 +2348,10 @@ mDNSlocal void INFOCallback(void)
                {
                for (s = mDNSStorage.DNSServers; s; s = s->next)
                        {
-                       NetworkInterfaceInfoOSX *ifx = (NetworkInterfaceInfoOSX *)s->interface;
-                       LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %s",
+                       NetworkInterfaceInfoOSX *ifx = IfindexToInterfaceInfoOSX(&mDNSStorage, s->interface);
+                       LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %d %s",
                                s->domain.c, ifx ? ifx->ifinfo.ifname : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port),
+                               s->penaltyTime ? s->penaltyTime - mDNS_TimeNow(&mDNSStorage) : 0,
                                s->teststate == DNSServer_Untested ? "(Untested)" :
                                s->teststate == DNSServer_Passed   ? ""           :
                                s->teststate == DNSServer_Failed   ? "(Failed)"   :
@@ -3070,6 +3073,7 @@ mDNSexport int main(int argc, char **argv)
                if (!strcasecmp(argv[i], "-UnicastPacketLogging"     )) mDNS_PacketLoggingEnabled = mDNStrue;
                if (!strcasecmp(argv[i], "-OfferSleepProxyService"   ))
                        OfferSleepProxyService = (i+1<argc && mDNSIsDigit(argv[i+1][0]) && mDNSIsDigit(argv[i+1][1]) && argv[i+1][2]==0) ? atoi(argv[++i]) : 80;
+               if (!strcasecmp(argv[i], "-StrictUnicastOrdering"     )) StrictUnicastOrdering = mDNStrue;
                }
        
        // Note that mDNSPlatformInit will set DivertMulticastAdvertisements in the mDNS structure
index 3bf71f2abe5ddd24ef44fd6a8bc1f14b8c04b992..336dd68bc86aeee960424e05a73ca0da1387b3c3 100644 (file)
@@ -378,7 +378,7 @@ int main(int ac, char *av[])
 #ifndef NO_SECURITYFRAMEWORK
        // We should normally be running as a system daemon.  However, that might not be the case in some scenarios (e.g. debugging).
        // Explicitly ensure that our Keychain operations utilize the system domain.
-       SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
+       if (opt_debug) SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
 #endif
        gPort = checkin(kmDNSHelperServiceName);
        if (!gPort)
index 720d18dbc9321724a73aab39c81d27ca60c73194..8b2a74200b40f96d36440afea5a7fd33fb228953 100644 (file)
@@ -1551,7 +1551,7 @@ createAnonymousRacoonConfiguration(const char *fqdn)
        static const char config2[] =
          "\";\n"
          "  nonce_size 16;\n"
-         "  lifetime time 5 min;\n"
+         "  lifetime time 15 min;\n"
          "  initial_contact on;\n"
          "  support_proxy on;\n"
          "  nat_traversal force;\n"
@@ -1561,7 +1561,7 @@ createAnonymousRacoonConfiguration(const char *fqdn)
          "    hash_algorithm sha1;\n"
          "    authentication_method pre_shared_key;\n"
          "    dh_group 2;\n"
-         "    lifetime time 5 min;\n"
+         "    lifetime time 15 min;\n"
          "  }\n"
          "}\n\n"
          "sainfo anonymous { \n"
@@ -2251,6 +2251,7 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
        static const char config[] =
          "%s"
          "remote %s [%u] {\n"
+         "  disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
          "  exchange_mode aggressive;\n"
          "  doi ipsec_doi;\n"
          "  situation identity_only;\n"
@@ -2259,7 +2260,7 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
          "  my_identifier user_fqdn \"dns:%s\";\n"
          "  shared_secret keychain \"dns:%s\";\n"
          "  nonce_size 16;\n"
-         "  lifetime time 5 min;\n"
+         "  lifetime time 15 min;\n"
          "  initial_contact on;\n"
          "  support_proxy on;\n"
          "  nat_traversal force;\n"
@@ -2269,7 +2270,7 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
          "    hash_algorithm sha1;\n"
          "    authentication_method pre_shared_key;\n"
          "    dh_group 2;\n"
-         "    lifetime time 5 min;\n"
+         "    lifetime time 15 min;\n"
          "  }\n"
          "}\n\n"
          "sainfo address %s any address %s any {\n"
index cb3b3c732024074b54b60a7791d26f95871be764..0c6684f0d711e1d6aad5899caad64e87ffc58a9b 100644 (file)
@@ -1459,40 +1459,55 @@ mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
        return -1;
        }
 
+mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex)
+{
+       mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
+       NetworkInterfaceInfoOSX *i;
+
+       // Don't get tricked by inactive interfaces
+       for (i = m->p->InterfaceList; i; i = i->next)
+               if (i->Registered && i->scope_id == scope_id) return(i);
+
+       return mDNSNULL;
+}
+
 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
        {
-       NetworkInterfaceInfoOSX *i;
        if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
        if (ifindex == kDNSServiceInterfaceIndexAny      ) return(mDNSNULL);
 
-       // Don't get tricked by inactive interfaces with no InterfaceID set
-       for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->ifinfo.InterfaceID && i->scope_id == ifindex) return(i->ifinfo.InterfaceID);
-
-       // Not found. Make sure our interface list is up to date, then try again.
-       LogInfo("InterfaceID for interface index %d not found; Updating interface list", ifindex);
-       mDNSMacOSXNetworkChanged(m);
-       for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->ifinfo.InterfaceID && i->scope_id == ifindex) return(i->ifinfo.InterfaceID);
+       NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
+       if (!ifi)
+               {
+               // Not found. Make sure our interface list is up to date, then try again.
+               LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
+               mDNSMacOSXNetworkChanged(m);
+               ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
+               }
 
-       return(mDNSNULL);
+       if (!ifi) return(mDNSNULL);     
+       
+       return(ifi->ifinfo.InterfaceID);
        }
 
+
 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
        {
        NetworkInterfaceInfoOSX *i;
        if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
        if (id == mDNSInterface_Any      ) return(0);
 
-       // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
+       mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
+
+       // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
        for (i = m->p->InterfaceList; i; i = i->next)
-               if ((mDNSInterfaceID)i == id) return(i->scope_id);
+               if (i->scope_id == scope_id) return(i->scope_id);
 
        // Not found. Make sure our interface list is up to date, then try again.
        LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
        mDNSMacOSXNetworkChanged(m);
        for (i = m->p->InterfaceList; i; i = i->next)
-               if ((mDNSInterfaceID)i == id) return(i->scope_id);
+               if (i->scope_id == scope_id) return(i->scope_id);
 
        return(0);
        }
@@ -1508,7 +1523,7 @@ mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *resu
        if (!asl_msg)   { LogMsg("mDNSASLLog: asl_new failed"); return; }
        if (uuid)
                {
-               char            uuidStr[36];
+               char            uuidStr[37];
                uuid_unparse(*uuid, uuidStr);
                asl_set         (asl_msg, "com.apple.message.uuid", uuidStr);
                }
@@ -1560,15 +1575,23 @@ mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
        mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstPort)
        {
-       // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
-       // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
-       // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
-       NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
-       char *ifa_name = info ? info->ifinfo.ifname : "unicast";
+       NetworkInterfaceInfoOSX *info = mDNSNULL;
        struct sockaddr_storage to;
        int s = -1, err;
        mStatus result = mStatus_NoError;
 
+       if (InterfaceID)
+               {
+               info = IfindexToInterfaceInfoOSX(m, InterfaceID);
+               if (info == NULL)
+                       {
+                       LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
+                       return mStatus_BadParamErr;
+                       }
+               }
+
+       char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
+
        if (dst->type == mDNSAddrType_IPv4)
                {
                struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
@@ -1809,14 +1832,18 @@ mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
 
                // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
                mDNSInterfaceID InterfaceID = mDNSNULL;
-               NetworkInterfaceInfo *intf = m->HostInterfaces;
-               while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
+               //NetworkInterfaceInfo *intf = m->HostInterfaces;
+               //while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
+
+               NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
+               while (intf && strcmp(intf->ifinfo.ifname, packetifname)) intf = intf->next;
+
                // When going to sleep we deregister all our interfaces, but if the machine
                // takes a few seconds to sleep we may continue to receive multicasts
                // during that time, which would confuse mDNSCoreReceive, because as far
                // as it's concerned, we should have no active interfaces any more.
                // Hence we ignore multicasts for which we can find no matching InterfaceID.
-               if (intf) InterfaceID = intf->InterfaceID;
+               if (intf) InterfaceID = intf->ifinfo.InterfaceID;
                else if (mDNSAddrIsDNSMulticast(&destAddr)) continue;
 
 //             LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
@@ -1963,7 +1990,7 @@ mDNSlocal void *doSSLHandshake(void *ctx)
        mStatus err = SSLHandshake(sock->tlsContext);
        
        KQueueLock(m);
-       LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
+       debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
 
        if (sock->handshake == handshake_to_be_closed)
                {
@@ -1981,27 +2008,27 @@ mDNSlocal void *doSSLHandshake(void *ctx)
                        {
                        if (err)
                                {
-                               LogMsg("SSLHandshake failed: %d", err);
+                               LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
                                SSLDisposeContext(sock->tlsContext);
                                sock->tlsContext = NULL;
                                }
                        
-                       sock->err = err;
+                       sock->err = err ? mStatus_ConnFailed : 0;
                        sock->handshake = handshake_completed;
                        
-                       LogInfo("doSSLHandshake: %p calling doTcpSocketCallback", sock);
+                       debugf("doSSLHandshake: %p calling doTcpSocketCallback", sock);
                        doTcpSocketCallback(sock);
                        }
                }
        
-       LogInfo("SSLHandshake %p: dropping lock", sock);
+       debugf("SSLHandshake %p: dropping lock", sock);
        KQueueUnlock(m, "doSSLHandshake");
        return NULL;
        }
 
 mDNSlocal mStatus spawnSSLHandshake(TCPSocket* sock)
        {
-       LogInfo("spawnSSLHandshake %p: entry", sock);
+       debugf("spawnSSLHandshake %p: entry", sock);
        if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
        sock->handshake = handshake_in_progress;
        KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, &sock->kqEntry);
@@ -2017,7 +2044,7 @@ mDNSlocal mStatus spawnSSLHandshake(TCPSocket* sock)
                sock->err = err;
                KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry);
                }
-       LogInfo("spawnSSLHandshake %p: done", sock);
+       debugf("spawnSSLHandshake %p: done", sock);
        return err;
        }
 
@@ -2568,7 +2595,15 @@ mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
        {
        if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
-       NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
+       NetworkInterfaceInfoOSX *info;
+
+       extern mDNS mDNSStorage;
+       info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
+       if (info == NULL)
+               {
+               LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
+               return;
+               }
        if (info->BPF_fd < 0)
                LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
        else
@@ -2582,7 +2617,14 @@ mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *c
 mDNSexport void mDNSPlatformSetLocalARP(const mDNSv4Addr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
        {
        if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalARP: No InterfaceID specified"); return; }
-       NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
+       NetworkInterfaceInfoOSX *info;
+       extern mDNS mDNSStorage;
+       info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
+       if (info == NULL)
+               {
+               LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
+               return;
+               }
        // Manually inject an entry into our local ARP cache.
        // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
        mDNSBool makearp = mDNSv4AddressIsLinkLocal(tpa);
@@ -2663,16 +2705,16 @@ mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *
        AuthRecord *rr;
 
        for (rr = m->ResourceRecords; rr; rr=rr->next)
-               if (rr->resrec.InterfaceID == (mDNSInterfaceID)x && rr->AddressProxy.type == mDNSAddrType_IPv4)
+               if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
                        {
-                       if (p4) LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
+                       if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
                        numv4++;
                        }
 
        for (rr = m->ResourceRecords; rr; rr=rr->next)
-               if (rr->resrec.InterfaceID == (mDNSInterfaceID)x && rr->AddressProxy.type == mDNSAddrType_IPv6)
+               if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
                        {
-                       if (p6) LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
+                       if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
                        numv6++;
                        }
 
@@ -2684,7 +2726,10 @@ mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *
 mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
        {
        NetworkInterfaceInfoOSX *x;
-       for (x = m->p->InterfaceList; x; x = x->next) if (x == (NetworkInterfaceInfoOSX *)InterfaceID) break;
+
+       //NOTE: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
+       for (x = m->p->InterfaceList; x; x = x->next) if (x->ifinfo.InterfaceID == InterfaceID) break;
+
        if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
 
        #define MAX_BPF_ADDRS 250
@@ -2730,9 +2775,9 @@ mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID
        static const struct bpf_insn g6  = BPF_STMT(BPF_LD  + BPF_W   + BPF_ABS, 50);   // Read IPv6 Dst LSW (bytes 50,51,52,53)
 
        static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B   + BPF_MSH, 14);   // Get IP Header length (normally 20)
-       static const struct bpf_insn r4b = BPF_STMT(BPF_LD  + BPF_IMM,           34);   // A = 34 (14-byte Ethernet plus 20-byte TCP)
+       static const struct bpf_insn r4b = BPF_STMT(BPF_LD  + BPF_IMM,           54);   // A = 54 (14-byte Ethernet plus 20-byte TCP + 20 bytes spare)
        static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X,    0);   // A += IP Header length
-       static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0);                                // Success: Return Ethernet + IP + TCP
+       static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0);                                // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
 
        static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94);                               // Success: Return Eth + IPv6 + TCP + 20 bytes spare
 
@@ -2751,6 +2796,13 @@ mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID
        // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
        // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
 
+       // IPSEC capture size notes:
+       //  8 bytes UDP header
+       //  4 bytes Non-ESP Marker
+       // 28 bytes IKE Header
+       // --
+       // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
+
        AuthRecord *rr;
        for (rr = m->ResourceRecords; rr; rr=rr->next)
                if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
@@ -2857,7 +2909,7 @@ mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd)
                        i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
                        i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
                        CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
-                       mDNSPlatformUpdateProxyList(m, (mDNSInterfaceID)i);
+                       mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID);
                        }
                }
 
@@ -3166,7 +3218,7 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad
                                // If this interface is not already registered (i.e. it's a dormant interface we had in our list
                                // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
                                // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
-                               if ((*p)->ifinfo.InterfaceID)
+                               if ((*p)->Registered)
                                        {
                                        mDNS_Lock(m);
                                        if (NetWake) mDNS_ActivateNetWake_internal  (m, &(*p)->ifinfo);
@@ -3182,7 +3234,7 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad
        debugf("AddInterfaceToList: Making   new   interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
        if (!i) return(mDNSNULL);
        mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
-       i->ifinfo.InterfaceID = mDNSNULL;
+       i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
        i->ifinfo.ip          = ip;
        i->ifinfo.mask        = mask;
        strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
@@ -3205,6 +3257,7 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad
        i->sa_family       = ifa->ifa_addr->sa_family;
        i->BPF_fd          = -1;
        i->BPF_len         = 0;
+       i->Registered      = mDNSNULL;
 
        // Do this AFTER i->BSSID has been set up
        i->ifinfo.NetWake  = NetWakeInterface(i);
@@ -3990,6 +4043,11 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
                                        LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
                                                ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
                                        }
+                                       // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
+                               else if ((int)if_nametoindex(ifa->ifa_name) <= 0)
+                                       {
+                                       LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
+                                       }
                                else
                                        {
                                        // Make sure ifa_netmask->sa_family is set correctly
@@ -4171,18 +4229,20 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
                        NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
                        if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
 
-                       if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary)       // Sanity check
+                       if (i->Registered && i->Registered != primary)  // Sanity check
                                {
-                               LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n->InterfaceID, primary);
-                               n->InterfaceID = mDNSNULL;
+                               LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
+                               i->Registered = mDNSNULL;
                                }
 
-                       if (!n->InterfaceID)
+                       if (!i->Registered)
                                {
-                               // Note: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
+                               // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
                                // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
-                               // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
-                               n->InterfaceID = (mDNSInterfaceID)primary;
+                               // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it
+                               //
+
+                               i->Registered = primary;
 
                                // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
                                // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
@@ -4190,15 +4250,16 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
                                i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
 
                                mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
+
                                if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
-                               LogInfo("SetupActiveInterfaces:   Registered    %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
-                                       i->ifinfo.ifname, i->scope_id, &i->BSSID, primary, &n->ip, CountMaskBits(&n->mask),
+                               LogInfo("SetupActiveInterfaces:   Registered    %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
+                                       i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary, &n->ip, CountMaskBits(&n->mask),
                                        i->Flashing        ? " (Flashing)"  : "",
                                        i->Occulting       ? " (Occulting)" : "",
                                        n->InterfaceActive ? " (Primary)"   : "");
 
                                if (!n->McastTxRx)
-                                       debugf("SetupActiveInterfaces:   No Tx/Rx on   %5s(%lu) %.6a InterfaceID %p %#a", i->ifinfo.ifname, i->scope_id, &i->BSSID, primary, &n->ip);
+                                       debugf("SetupActiveInterfaces:   No Tx/Rx on   %5s(%lu) %.6a InterfaceID %p %#a", i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, &n->ip);
                                else
                                        {
                                        if (i->sa_family == AF_INET)
@@ -4285,22 +4346,22 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
                {
                // If this interface is no longer active, or its InterfaceID is changing, deregister it
                NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
-               if (i->ifinfo.InterfaceID)
-                       if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary)
+               if (i->Registered)
+                       if (i->Exists == 0 || i->Exists == 2 || i->Registered != primary)
                                {
                                i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
-                               LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
-                                       i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
+                               LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
+                                       i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary,
                                        &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
                                        i->Flashing               ? " (Flashing)"  : "",
                                        i->Occulting              ? " (Occulting)" : "",
                                        i->ifinfo.InterfaceActive ? " (Primary)"   : "");
                                mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
                                if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
-                               i->ifinfo.InterfaceID = mDNSNULL;
-                               // Note: If i->ifinfo.InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
+                               i->Registered = mDNSNULL;
+                               // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
                                // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
-                               // If i->ifinfo.InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
+                               // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
 
                                // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
                                // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
@@ -4317,9 +4378,9 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
                if (!i->Exists)
                        {
                        if (i->LastSeen == utc) i->LastSeen = utc - 1;
-                       mDNSBool delete = (NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0) && (utc - i->LastSeen >= 60);
-                       LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
-                               i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
+                       mDNSBool delete = (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0) && (utc - i->LastSeen >= 60);
+                       LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
+                               i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
                                &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
                                i->ifinfo.InterfaceActive ? " (Primary)" : "");
 #if APPLE_OSX_mDNSResponder
@@ -5626,7 +5687,7 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
                        }
                else                                                            // else, we're Sleep Proxy Server; open BPF fds
                        {
-                       if (i->Exists && i->ifinfo.InterfaceID == (mDNSInterfaceID)i && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1)
+                       if (i->Exists && i->Registered == i && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1)
                                { LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); }
                        }
                }
index d2e0e73bfc9f0aea7850b1fe04dabaf18810ace4..03db2357adfd8913e983ffab2d62c0b88e47a31a 100644 (file)
@@ -255,6 +255,7 @@ struct NetworkInterfaceInfoOSX_struct
        u_int                    BPF_len;
        CFSocketRef              BPF_cfs;
        CFRunLoopSourceRef       BPF_rls;
+       NetworkInterfaceInfoOSX *Registered;            // non-NULL means registered with mDNS Core
        };
 
 struct mDNS_PlatformSupport_struct
@@ -312,6 +313,7 @@ extern void NotifyOfElusiveBug(const char *title, const char *msg); // Both stri
 extern void SetDomainSecrets(mDNS *m);
 extern void mDNSMacOSXNetworkChanged(mDNS *const m);
 extern int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring);
+extern NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex);
 
 extern int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef);
 
index cb3660f20be5417c1bc07cb79555cd504ae446cc..bf25e008352b8b21969ba240b9e9e68d4b9b1ce4 100644 (file)
@@ -27,6 +27,7 @@
                        isa = PBXAggregateTarget;
                        buildConfigurationList = 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */;
                        buildPhases = (
+                               FF045B6A0C7E4AA600448140 /* ShellScript */,
                        );
                        dependencies = (
                                03067D680C83A3830022BE1F /* PBXTargetDependency */,
                                2E0405ED0C31955500F13B59 /* Sources */,
                                2E0405EE0C31955500F13B59 /* Frameworks */,
                                4AAE0C5A0C68E6EC003882A5 /* CopyFiles */,
-                               FF045B6A0C7E4AA600448140 /* ShellScript */,
                        );
                        buildRules = (
                        );
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "if [ -e \"${SDKROOT}/usr/lib/libipsec.dylib\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nelse\necho \"#define MDNS_NO_IPSEC 1\" > ${CONFIGURATION_TEMP_DIR}/ipsec_options.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n";
+                       shellScript = "if [ -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/lib/libipsec.dylib\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nelse\necho \"#define MDNS_NO_IPSEC 1\" > ${CONFIGURATION_TEMP_DIR}/ipsec_options.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n";
                };
                D284BE510ADD80740027CCDF /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/tcsh;
-                       shellScript = "# Install plist to tell launchd to start mDNSResponder\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\n\n# Install mDNSResponder.bundle containing language localizations\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices\ncp -R ${SRCROOT}/mDNSResponder-bundle ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle\n\n# Remove unwanted CVS directories\nfind ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -depth -name CVS -exec rm -rf {} \\;\n\n# Expand UTF-8 files to UTF-16 (at one time this appeared to be necessary, but it's not, so we don't do it any more)\n#foreach file (`find ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -name Localizable.strings`)\n#iconv -f utf-8 -t utf-16 ${file} > ${file}.new\n#mv -f ${file}.new ${file}\n#end\n\n# Remove French localization (not wanted for Apple B&I builds)\nrm -rf ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle/Resources/French.lproj\n\n# Copy Sandbox profile, stripping initial license header to make the file fit in the ~16kB Sandbox profile limit\n(umask 022; mkdir -p -m 0755 ${DSTROOT}/usr/share/sandbox)\n(umask 222; awk '/^\\(version 1\\)$/,EOF' ${SRCROOT}/mDNSResponder.sb > ${DSTROOT}/usr/share/sandbox/mDNSResponder.sb)\n";
+                       shellScript = "# Install mDNSResponder.bundle containing language localizations\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices\ncp -R ${SRCROOT}/mDNSResponder-bundle ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle\n\n# Remove unwanted CVS directories\nfind ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -depth -name CVS -exec rm -rf {} \\;\n\n# Expand UTF-8 files to UTF-16 (at one time this appeared to be necessary, but it's not, so we don't do it any more)\n#foreach file (`find ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -name Localizable.strings`)\n#iconv -f utf-8 -t utf-16 ${file} > ${file}.new\n#mv -f ${file}.new ${file}\n#end\n\n# Remove French localization (not wanted for Apple B&I builds)\nrm -rf ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle/Resources/French.lproj\n\n# Copy Sandbox profile, stripping initial license header to make the file fit in the ~16kB Sandbox profile limit\n(umask 022; mkdir -p -m 0755 ${DSTROOT}/usr/share/sandbox)\n(umask 222; awk '/^\\(version 1\\)$/,EOF' ${SRCROOT}/mDNSResponder.sb > ${DSTROOT}/usr/share/sandbox/mDNSResponder.sb)\n";
                };
                D284BE760ADD80800027CCDF /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\ncc -arch i386 -arch ppc \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n";
+                       shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n";
                };
                FF045B6A0C7E4AA600448140 /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/tcsh;
-                       shellScript = "# Install plist to tell launchd how to start mDNSResponderHelper\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.helper.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\n";
+                       shellScript = "# Install plists to tell launchd how to start mDNSResponder and mDNSResponderHelper\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\n\nif (${MACOSX_DEPLOYMENT_TARGET} == \"10.4\") then\ncp ${SRCROOT}/LaunchDaemonInfo-Tiger.plist        ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\ncp ${SRCROOT}/LaunchDaemonInfo-Tiger.helper.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\nelse\ncp ${SRCROOT}/LaunchDaemonInfo.plist              ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\ncp ${SRCROOT}/LaunchDaemonInfo.helper.plist       ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\nendif\n";
                };
                FF37FAAD0BC581780044A5CF /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                HEADER_SEARCH_PATHS = ../mDNSShared;
                                INSTALL_PATH = /usr/bin;
-                               MACOSX_DEPLOYMENT_TARGET = 10.4;
                                OTHER_CFLAGS = "-no-cpp-precomp";
                                OTHER_LDFLAGS = "";
                                OTHER_REZFLAGS = "";
index 59891f78e0963936887f37c3133105c3ed901a5e..39d84a651ffb6a4dc179f2ef32865bbb189600e9 100644 (file)
@@ -77,7 +77,7 @@
  */
 
 #ifndef _DNS_SD_H
-#define _DNS_SD_H 2140000
+#define _DNS_SD_H 2140300
 
 #ifdef  __cplusplus
     extern "C" {
index 9022f948cc825ced00d5b76deeed9ae20d7ab40e..8b89b151a3e218499992729b47ee89b2f2912036 100644 (file)
@@ -4138,7 +4138,7 @@ mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *Reso
                LogMsgNoIdent("    Int    Next  Expire   State");
                for (ar = ResourceRecords; ar; ar=ar->next)
                        {
-                       NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)ar->resrec.InterfaceID;
+                       char *ifname = InterfaceNameForID(m, ar->resrec.InterfaceID);
                        if (ar->WakeUp.HMAC.l[0]) (*proxy)++;
                        if (!mDNSSameEthAddress(&owner, &ar->WakeUp.HMAC))
                                {
@@ -4161,7 +4161,7 @@ mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *Reso
                                        ar->ThisAPInterval / mDNSPlatformOneSecond,
                                        ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
                                        ar->TimeExpire    ? (ar->TimeExpire                      - now) / mDNSPlatformOneSecond : 0,
-                                       info ? info->ifname : "ALL",
+                                       ifname ? ifname : "ALL",
                                        ARDisplayString(m, ar));
                        else
                                LogMsgNoIdent("                             LO %s", ARDisplayString(m, ar));
@@ -4191,14 +4191,14 @@ mDNSexport void udsserver_info(mDNS *const m)
                        for (cr = cg->members; cr; cr=cr->next)
                                {
                                mDNSs32 remain = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond;
-                               NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)cr->resrec.InterfaceID;
+                               char *ifname = InterfaceNameForID(m, cr->resrec.InterfaceID);
                                CacheUsed++;
                                if (cr->CRActiveQuestion) CacheActive++;
                                LogMsgNoIdent("%3d %s%8ld %-7s%s %-6s%s",
                                        slot,
                                        cr->CRActiveQuestion ? "*" : " ",
                                        remain,
-                                       info ? info->ifname : "-U-",
+                                       ifname ? ifname : "-U-",
                                        (cr->resrec.RecordType == kDNSRecordTypePacketNegative)  ? "-" :
                                        (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
                                        DNSTypeName(cr->resrec.rrtype),
@@ -4244,12 +4244,12 @@ mDNSexport void udsserver_info(mDNS *const m)
                        {
                        mDNSs32 i = q->ThisQInterval / mDNSPlatformOneSecond;
                        mDNSs32 n = (q->LastQTime + q->ThisQInterval - now) / mDNSPlatformOneSecond;
-                       NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)q->InterfaceID;
+                       char *ifname = InterfaceNameForID(m, q->InterfaceID);
                        CacheUsed++;
                        if (q->ThisQInterval) CacheActive++;
                        LogMsgNoIdent("%6d%6d %-7s%s%s %5d  %-6s%##s%s",
                                i, n,
-                               info ? info->ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
+                               ifname ? ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
                                mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"),
                                q->AuthInfo    ? "P" : " ",
                                q->CurrentAnswers,