version 214.3
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
index 65f5324..da14969 100644
--- a/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
@@ -442,10 +442,6 @@
 				>

 			</File>

 			<File

-				RelativePath=".\StdioFileEx.cpp"

-				>

-			</File>

-			<File

 				RelativePath="ThirdPage.cpp"

 				>

 			</File>

@@ -491,10 +487,6 @@
 				>

 			</File>

 			<File

-				RelativePath=".\StdioFileEx.h"

-				>

-			</File>

-			<File

 				RelativePath="ThirdPage.h"

 				>

 			</File>

diff --git a/Clients/PrinterSetupWizard/ThirdPage.cpp b/Clients/PrinterSetupWizard/ThirdPage.cpp
index 8981bd4..deca4df 100644
--- a/Clients/PrinterSetupWizard/ThirdPage.cpp
+++ b/Clients/PrinterSetupWizard/ThirdPage.cpp
@@ -162,7 +162,6 @@
 #include "PrinterSetupWizardApp.h"
 #include "PrinterSetupWizardSheet.h"
 #include "ThirdPage.h"
-#include "StdioFileEx.h"
 #include <dns_sd.h>
 #include <tcpxcv.h>
 #include <winspool.h>
diff --git a/Clients/dns-sd.c b/Clients/dns-sd.c
index 993632d..b945552 100644
--- a/Clients/dns-sd.c
+++ b/Clients/dns-sd.c
@@ -70,6 +70,14 @@
 // 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()
diff --git a/Makefile b/Makefile
index aaf7bc6..93d4c32 100644
--- 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"
 
diff --git a/mDNSCore/DNSCommon.c b/mDNSCore/DNSCommon.c
index bf57929..a866aa6 100644
--- a/mDNSCore/DNSCommon.c
+++ b/mDNSCore/DNSCommon.c
@@ -592,8 +592,9 @@
 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
diff --git a/mDNSCore/DNSCommon.h b/mDNSCore/DNSCommon.h
index 95d4e30..b097680 100644
--- a/mDNSCore/DNSCommon.h
+++ b/mDNSCore/DNSCommon.h
@@ -17,6 +17,10 @@
     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 @@
 
 // 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);
 
diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c
index 8fe2a80..8bf8a32 100755
--- a/mDNSCore/mDNS.c
+++ b/mDNSCore/mDNS.c
@@ -38,6 +38,37 @@
     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 @@
 
 #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 @@
 	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 @@
 	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 @@
 
 	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 @@
 				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 @@
 					// 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 @@
 					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 @@
 
 					// 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 @@
 						{
 						// 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 @@
 
 		// 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 @@
 				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 @@
 	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 @@
 					{
 					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 @@
 	// 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 @@
 					// 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 @@
 					{
 					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 @@
 				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 @@
 		{
 		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 @@
 
 		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 @@
 
 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 @@
 			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 @@
 			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 @@
 			{
 			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 @@
 		// 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 @@
 					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 @@
 						}
 					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 @@
 
 	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 @@
 	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 @@
 #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 @@
 	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 @@
 				}
 	}
 
-// Look up a DNS Server, matching by name in split-dns configurations.
-mDNSexport DNSServer *GetServerForName(mDNS *m, const domainname *name)
-    {
-	DNSServer *curmatch = mDNSNULL, *p;
-	int curmatchlen = -1, ncount = name ? CountLabels(name) : 0;
-
-	for (p = m->DNSServers; p; p = p->next)
+mDNSinline mDNSs32 PenaltyTimeForServer(mDNS *m, DNSServer *server)
+	{
+	mDNSs32 ptime = 0;
+	if (server->penaltyTime != 0)
 		{
-		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; }
+		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, DNSServer *prev)
+    {
+	DNSServer *curmatch = mDNSNULL;
+
+	// prev is the previous DNS server used by some question
+	if (prev != mDNSNULL)
+		{
+		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 @@
 			// 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 @@
 #pragma mark - Sleep Proxy Server
 #endif
 
-mDNSlocal void RestartProbing(mDNS *const m, AuthRecord *const rr)
+mDNSlocal void RestartARPProbing(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.
+	// 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 @@
 
 		// 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 @@
 											(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 @@
 				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 @@
 			{
 			#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 @@
 
 				case 17:	{
 							const UDPHeader *const udp = (const UDPHeader *)trans;
-							mDNSu16 len = (mDNSu16)((mDNSu16)trans[4] << 8 | trans[5]);
-							port = udp->dst;
-							wake = mDNStrue;
+							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 specially ignore NAT keepalive packets
-							if (mDNSSameIPPort(port, IPSEC)) wake = (len != 9 || end < trans + 9 || trans[8] != 0xFF);
+								// 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) 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);
+								// 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));
+								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 @@
 								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 @@
 	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 @@
 	// 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 @@
 	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 @@
 					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 @@
 	// 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 @@
 			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 @@
 		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))
 		{
diff --git a/mDNSCore/mDNSEmbeddedAPI.h b/mDNSCore/mDNSEmbeddedAPI.h
index 00329ec..621d534 100755
--- a/mDNSCore/mDNSEmbeddedAPI.h
+++ b/mDNSCore/mDNSEmbeddedAPI.h
@@ -54,6 +54,14 @@
     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
@@ -1468,6 +1476,18 @@
 
 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;
 	mDNSIPPort   dst;
 	mDNSu32      seq;
@@ -1640,12 +1660,12 @@
 						((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 @@
 	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 @@
 	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 @@
 	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 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 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 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_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 @@
 #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 @@
 	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
diff --git a/mDNSCore/uDNS.c b/mDNSCore/uDNS.c
index 962c536..992e214 100755
--- a/mDNSCore/uDNS.c
+++ b/mDNSCore/uDNS.c
@@ -1345,6 +1345,9 @@
 // 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 @@
 			(*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)",
-		&q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype));
-
-	while (*p)
+	if (QueryFail)
 		{
-		if (*p == q->qDNSServer) *p = q->qDNSServer->next;
-		else p=&(*p)->next;
+			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));
+		}
+	else
+		{
+			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)
+	if ((q->qDNSServer != orig) && (QueryFail))
 		{
-		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.
+		// 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);
+
 		}
+	else 
+		{
+		// 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 @@
 		// 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 @@
 			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 @@
 			{
 			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 @@
 
 		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 @@
 
 		if (q)
 			{
-			if (q->ThisQInterval == 0 || q->LastQTime + q->ThisQInterval - m->timenow > MAX_UCAST_POLL_INTERVAL)
+			if (q->ThisQInterval == 0)
 				{
-				q->LastQTime     = m->timenow;
-				q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
+				// 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);
 				}
-			// 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.
+			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 = 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);
+				}
+			
+			// 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 @@
 
 		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 @@
 			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 @@
 					{
 					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 @@
 				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 @@
 				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 @@
 				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 @@
 	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 @@
 
 	nexte = CheckServiceRegistrations(m);
 	if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
+
+	nexte = CheckDNSServerPenalties(m);
+	if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
 	}
 
 // ***************************************************************************
diff --git a/mDNSCore/uDNS.h b/mDNSCore/uDNS.h
index 71f4097..88beb9f 100755
--- a/mDNSCore/uDNS.h
+++ b/mDNSCore/uDNS.h
@@ -236,6 +236,7 @@
 #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 @@
 
 // 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
index 0000000..895287c
--- /dev/null
+++ b/mDNSMacOSX/LaunchDaemonInfo-Tiger.helper.plist
@@ -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
index 0000000..e91b775
--- /dev/null
+++ b/mDNSMacOSX/LaunchDaemonInfo-Tiger.plist
@@ -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>
diff --git a/mDNSMacOSX/daemon.c b/mDNSMacOSX/daemon.c
index 7e6db35..69e23d6 100644
--- a/mDNSMacOSX/daemon.c
+++ b/mDNSMacOSX/daemon.c
@@ -668,6 +668,8 @@
 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 @@
 	{
 	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 @@
 		{
 		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 @@
 		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
diff --git a/mDNSMacOSX/helper-main.c b/mDNSMacOSX/helper-main.c
index 3bf71f2..336dd68 100644
--- a/mDNSMacOSX/helper-main.c
+++ b/mDNSMacOSX/helper-main.c
@@ -378,7 +378,7 @@
 #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)
diff --git a/mDNSMacOSX/helper.c b/mDNSMacOSX/helper.c
index 720d18d..8b2a742 100644
--- a/mDNSMacOSX/helper.c
+++ b/mDNSMacOSX/helper.c
@@ -1551,7 +1551,7 @@
 	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 @@
 	  "    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 @@
 	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 @@
 	  "  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 @@
 	  "    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"
diff --git a/mDNSMacOSX/mDNSMacOSX.c b/mDNSMacOSX/mDNSMacOSX.c
index cb3b3c7..0c6684f 100644
--- a/mDNSMacOSX/mDNSMacOSX.c
+++ b/mDNSMacOSX/mDNSMacOSX.c
@@ -1459,40 +1459,55 @@
 	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);
+	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);
+		}
 
-	// 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);
-
-	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 @@
 	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 @@
 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 @@
 
 		// 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 @@
 	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 @@
 			{
 			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 @@
 		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 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 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 @@
 	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 @@
 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 @@
 	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 @@
 	// 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 @@
 			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 @@
 				// 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 @@
 	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 @@
 	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 @@
 					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 @@
 			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 @@
 				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 @@
 		{
 		// 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 @@
 		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 @@
 			}
 		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(); }
 			}
 		}
diff --git a/mDNSMacOSX/mDNSMacOSX.h b/mDNSMacOSX/mDNSMacOSX.h
index d2e0e73..03db235 100644
--- a/mDNSMacOSX/mDNSMacOSX.h
+++ b/mDNSMacOSX/mDNSMacOSX.h
@@ -255,6 +255,7 @@
 	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 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);
 
diff --git a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
index cb3660f..bf25e00 100644
--- a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
+++ b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
@@ -27,6 +27,7 @@
 			isa = PBXAggregateTarget;
 			buildConfigurationList = 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */;
 			buildPhases = (
+				FF045B6A0C7E4AA600448140 /* ShellScript */,
 			);
 			dependencies = (
 				03067D680C83A3830022BE1F /* PBXTargetDependency */,
@@ -990,7 +991,6 @@
 				2E0405ED0C31955500F13B59 /* Sources */,
 				2E0405EE0C31955500F13B59 /* Frameworks */,
 				4AAE0C5A0C68E6EC003882A5 /* CopyFiles */,
-				FF045B6A0C7E4AA600448140 /* ShellScript */,
 			);
 			buildRules = (
 			);
@@ -1346,7 +1346,7 @@
 			);
 			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;
@@ -1364,7 +1364,7 @@
 			);
 			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;
@@ -1373,7 +1373,7 @@
 			);
 			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;
@@ -1386,7 +1386,7 @@
 			);
 			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;
@@ -1856,7 +1856,6 @@
 				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 = "";
diff --git a/mDNSShared/dns_sd.h b/mDNSShared/dns_sd.h
index 59891f7..39d84a6 100644
--- a/mDNSShared/dns_sd.h
+++ b/mDNSShared/dns_sd.h
@@ -77,7 +77,7 @@
  */
 
 #ifndef _DNS_SD_H
-#define _DNS_SD_H 2140000
+#define _DNS_SD_H 2140300
 
 #ifdef  __cplusplus
     extern "C" {
diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c
index 9022f94..8b89b15 100644
--- a/mDNSShared/uds_daemon.c
+++ b/mDNSShared/uds_daemon.c
@@ -4138,7 +4138,7 @@
 		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 @@
 					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 @@
 			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 @@
 			{
 			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,