version 320.14
diff --git a/Clients/dns-sd.c b/Clients/dns-sd.c
index c73c221..bf6cc10 100644
--- a/Clients/dns-sd.c
+++ b/Clients/dns-sd.c
@@ -170,11 +170,7 @@
 	#include <arpa/inet.h>		// For inet_addr()
 	#include <net/if.h>			// For if_nametoindex()
 	static const char kFilePathSep = '/';
-// #ifndef NOT_HAVE_SA_LEN
-// 	#define SA_LEN(addr) ((addr)->sa_len)
-// #else
-    #define SA_LEN(addr) (((addr)->sa_family == AF_INET6)? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))
-// #endif
+	#define SA_LEN(addr) ((addr)->sa_len)
 #endif
 
 #if (TEST_NEW_CLIENTSTUB && !defined(__APPLE_API_PRIVATE))
diff --git a/Makefile b/Makefile
index 7233229..2201ed0 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 
 include /Developer/Makefiles/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-320.10.80"
+MVERS = "mDNSResponder-320.14.0"
 
 DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
 
diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c
index ede13e9..a07b8ee 100755
--- a/mDNSCore/mDNS.c
+++ b/mDNSCore/mDNS.c
@@ -7074,11 +7074,15 @@
 			// *not* on a Microsoft Active Directory network, and there is no authoritative server for "local". Note that this is not
 			// in conflict with the mDNS spec, because that spec says, "Multicast DNS Zones have no SOA record," so it's okay to cache
 			// negative answers for "local. SOA" from a uDNS server, because the mDNS spec already says that such records do not exist :-)
+			//
+			// By suppressing negative responses, it might take longer to timeout a .local question as it might be expecting a
+			// response e.g., we deliver a positive "A" response and suppress negative "AAAA" response and the upper layer may
+			// be waiting longer to get the AAAA response before returning the "A" response to the application. To handle this
+			// case without creating the negative cache entries, we generate a negative response and let the layer above us
+			// do the appropriate thing. This negative response is also needed for appending new search domains.
 			if (!InterfaceID && q.qtype != kDNSType_SOA && IsLocalDomain(&q.qname))
 				{
-				// If we did not find a positive answer and we can append search domains to this question,
-				// generate a negative response (without creating a cache entry) to append search domains.
-				if (qptr->AppendSearchDomains && !rr)
+				if (!rr)
 					{
 					LogInfo("mDNSCoreReceiveResponse: Generate negative response for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
 					m->CurrentQuestion = qptr;
@@ -10859,6 +10863,30 @@
 		}
 	}
 
+// Check for a positive unicast response to the question but with qtype
+mDNSexport mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype)
+	{
+	DNSQuestion question;
+	const mDNSu32 slot = HashSlot(&q->qname);
+	CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+	CacheRecord *rp;
+
+	// Create an identical question but with qtype
+	mDNS_SetupQuestion(&question, q->InterfaceID, &q->qname, qtype, mDNSNULL, mDNSNULL);
+	question.qDNSServer = q->qDNSServer;
+
+	for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
+		{
+		if (!rp->resrec.InterfaceID && rp->resrec.RecordType != kDNSRecordTypePacketNegative && 
+			SameNameRecordAnswersQuestion(&rp->resrec, &question))
+			{
+			LogInfo("mDNS_CheckForCacheRecord: Found %s", CRDisplayString(m, rp));
+			return mDNStrue;
+			}
+		}
+	return mDNSfalse;
+	}
+
 mDNSlocal void CacheRecordResetDNSServer(mDNS *const m, DNSQuestion *q, DNSServer *new)
 	{
 	const mDNSu32 slot = HashSlot(&q->qname);
diff --git a/mDNSCore/mDNSEmbeddedAPI.h b/mDNSCore/mDNSEmbeddedAPI.h
index 3d6c12a..6756fe2 100755
--- a/mDNSCore/mDNSEmbeddedAPI.h
+++ b/mDNSCore/mDNSEmbeddedAPI.h
@@ -1466,10 +1466,11 @@
 #define MD5_LEN     16
 
 #define AutoTunnelUnregistered(X) (                                              \
-	(X)->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered && \
-	(X)->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered && \
-	(X)->AutoTunnelService.   resrec.RecordType == kDNSRecordTypeUnregistered && \
-	(X)->AutoTunnel6Record.   resrec.RecordType == kDNSRecordTypeUnregistered    )
+	(X)->AutoTunnelHostRecord. resrec.RecordType == kDNSRecordTypeUnregistered && \
+	(X)->AutoTunnelDeviceInfo. resrec.RecordType == kDNSRecordTypeUnregistered && \
+	(X)->AutoTunnelService.    resrec.RecordType == kDNSRecordTypeUnregistered && \
+	(X)->AutoTunnel6Record.    resrec.RecordType == kDNSRecordTypeUnregistered && \
+	(X)->AutoTunnel6MetaRecord.resrec.RecordType == kDNSRecordTypeUnregistered    )
 
 // Internal data structure to maintain authentication information
 typedef struct DomainAuthInfo
@@ -1481,7 +1482,8 @@
 	AuthRecord       AutoTunnelTarget;		// Opaque hostname of tunnel endpoint; used as SRV target for AutoTunnelService record
 	AuthRecord       AutoTunnelDeviceInfo;	// Device info of tunnel endpoint
 	AuthRecord       AutoTunnelService;		// Service record (possibly NAT-Mapped) of IKE daemon implementing tunnel endpoint
-	AuthRecord       AutoTunnel6Record;     // AutoTunnel AAAA Record obtained from Connectivityd
+	AuthRecord       AutoTunnel6Record;     // AutoTunnel AAAA record obtained from awacsd
+	AuthRecord       AutoTunnel6MetaRecord; // Notify remote peers to connect to the relay servers for potential outbound connections from this host
 	NATTraversalInfo AutoTunnelNAT;
 	domainname       domain;
 	domainname       keyname;
@@ -2737,6 +2739,7 @@
 extern AuthGroup *AuthGroupForRecord(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr);
 extern AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
 extern AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
+extern mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype);
 
 // 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
@@ -2946,7 +2949,7 @@
 	char sizecheck_DNSServer           [(sizeof(DNSServer)            <=   320) ? 1 : -1];
 	char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <=  6850) ? 1 : -1];
 	char sizecheck_ServiceRecordSet    [(sizeof(ServiceRecordSet)     <=  5500) ? 1 : -1];
-	char sizecheck_DomainAuthInfo      [(sizeof(DomainAuthInfo)       <=  7808) ? 1 : -1];
+	char sizecheck_DomainAuthInfo      [(sizeof(DomainAuthInfo)       <=  7968) ? 1 : -1];
 	char sizecheck_ServiceInfoQuery    [(sizeof(ServiceInfoQuery)     <=  3200) ? 1 : -1];
 #if APPLE_OSX_mDNSResponder
 	char sizecheck_ClientTunnel        [(sizeof(ClientTunnel)         <=  1148) ? 1 : -1];
diff --git a/mDNSCore/uDNS.c b/mDNSCore/uDNS.c
index 47559a4..5c4e3a1 100755
--- a/mDNSCore/uDNS.c
+++ b/mDNSCore/uDNS.c
@@ -384,12 +384,13 @@
 
 	// Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo
 	// being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use.
-	info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
-	info->AutoTunnelHostRecord.namestorage.c[0] = 0;
-	info->AutoTunnelTarget    .resrec.RecordType = kDNSRecordTypeUnregistered;
-	info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
-	info->AutoTunnelService   .resrec.RecordType = kDNSRecordTypeUnregistered;
-	info->AutoTunnel6Record   .resrec.RecordType = kDNSRecordTypeUnregistered;
+	info->AutoTunnelHostRecord .resrec.RecordType = kDNSRecordTypeUnregistered;
+	info->AutoTunnelHostRecord .namestorage.c[0] = 0;
+	info->AutoTunnelTarget     .resrec.RecordType = kDNSRecordTypeUnregistered;
+	info->AutoTunnelDeviceInfo .resrec.RecordType = kDNSRecordTypeUnregistered;
+	info->AutoTunnelService    .resrec.RecordType = kDNSRecordTypeUnregistered;
+	info->AutoTunnel6Record    .resrec.RecordType = kDNSRecordTypeUnregistered;
+	info->AutoTunnel6MetaRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
 	info->AutoTunnelNAT.clientContext = mDNSNULL;
 	info->next = mDNSNULL;
 	*p = info;
diff --git a/mDNSMacOSX/mDNSMacOSX.c b/mDNSMacOSX/mDNSMacOSX.c
index 1ee1c1f..07146cf 100644
--- a/mDNSMacOSX/mDNSMacOSX.c
+++ b/mDNSMacOSX/mDNSMacOSX.c
@@ -204,6 +204,8 @@
 mDNSexport domainname ActiveDirectoryPrimaryDomain;
 mDNSexport int        ActiveDirectoryPrimaryDomainLabelCount;
 mDNSexport mDNSAddr   ActiveDirectoryPrimaryDomainServer;
+
+static mDNSBool AWACSDConnected = mDNSfalse;
 #endif // APPLE_OSX_mDNSResponder
 
 // Used by AutoTunnel
@@ -3699,6 +3701,41 @@
 	}
 #endif
 
+// pre-declaration
+mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+
+// Notify remote peers to connect to the relay servers for potential outbound connections from this host.
+// Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
+// sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
+// not e.g., AutoTunnelHostNameChanged
+mDNSlocal void RegisterAutoTunnel6MetaRecord(mDNS *m, DomainAuthInfo *info)
+	{
+	mStatus err;
+
+	if (!m->mDNS_busy) LogMsg("RegisterAutoTunnel6MetaRecord: ERROR!! Lock not held");
+	
+	if (!AWACSDConnected)
+		{
+		LogInfo("RegisterAutoTunnel6MetaRecord no need to register");
+		return;
+		}
+
+	if (info->AutoTunnel6MetaRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
+		{
+		mDNS_SetupResourceRecord(&info->AutoTunnel6MetaRecord, mDNSNULL, mDNSInterface_Any, kDNSType_PTR, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
+		AssignDomainName (&info->AutoTunnel6MetaRecord.namestorage, (const domainname*) "\x0C" "_autotunnel6");
+		AppendDomainName (&info->AutoTunnel6MetaRecord.namestorage, &info->domain);
+
+		info->AutoTunnel6MetaRecord.resrec.rdata->u.name.c[0] = 0;
+		AppendDomainLabel(&info->AutoTunnel6MetaRecord.resrec.rdata->u.name, &m->hostlabel);
+		AppendDomainName (&info->AutoTunnel6MetaRecord.resrec.rdata->u.name, &info->domain);
+		info->AutoTunnel6MetaRecord.resrec.RecordType = kDNSRecordTypeShared;
+
+		err = mDNS_Register_internal(m, &info->AutoTunnel6MetaRecord);
+		if (err) LogMsg("RegisterAutoTunnel6MetaRecord error %d registering %##s", err, info->AutoTunnel6MetaRecord.namestorage.c);
+		else LogInfo("RegisterAutoTunnel6MetaRecord registering %##s %##s", info->AutoTunnel6MetaRecord.namestorage.c, info->AutoTunnel6MetaRecord.resrec.rdata->u.name.c);
+		}
+	}
 
 // Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
 // sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
@@ -3786,6 +3823,24 @@
 	UpdateAutoTunnelDomainStatus(m, info);
 	}
 
+mDNSlocal void DeregisterAutoTunnel6MetaRecord(mDNS *m, DomainAuthInfo *info)
+	{
+	LogInfo("DeregisterAutoTunnel6MetaRecord %##s", info->domain.c);
+
+	if (info->AutoTunnel6MetaRecord.resrec.RecordType > kDNSRecordTypeDeregistering)
+		{
+		mStatus err = mDNS_Deregister(m, &info->AutoTunnel6MetaRecord);
+		if (err)
+			{
+			info->AutoTunnel6MetaRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
+			info->AutoTunnel6MetaRecord.resrec.rdata->u.name.c[0] = 0;
+			LogMsg("DeregisterAutoTunnel6MetaRecord error %d deregistering %##s", err, info->AutoTunnel6MetaRecord.namestorage.c);
+			}
+		else LogInfo("DeregisterAutoTunnel6MetaRecord: Deregistered record");
+		}
+	else LogInfo("DeregisterAutoTunnel6MetaRecord: Not deregistering record state:%d", info->AutoTunnel6MetaRecord.resrec.RecordType);
+	}
+
 mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
 	{
 	LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
@@ -3846,6 +3901,12 @@
 			info->AutoTunnel6Record.resrec.rdata->u.ipv6 = zerov6Addr;
 			RegisterAutoTunnel6Record(m,info);
 			}
+		else if (rr == &info->AutoTunnel6MetaRecord)
+			{
+			LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnel6MetaRecord");
+			info->AutoTunnel6MetaRecord.resrec.rdata->u.name.c[0] = 0;
+			RegisterAutoTunnel6MetaRecord(m,info);
+			}
 		}
 	}
 
@@ -3858,6 +3919,7 @@
 	DeregisterAutoTunnelDevInfoRecord(m, info);
 	DeregisterAutoTunnelServiceRecords(m, info);
 	DeregisterAutoTunnel6Record(m, info);
+	DeregisterAutoTunnel6MetaRecord(m, info);
 	UpdateAnonymousRacoonConfig(m);		// Determine whether we need racoon to accept incoming connections
 	UpdateAutoTunnelDomainStatus(m, info);
 	}
@@ -3900,11 +3962,13 @@
 #endif
 	DeregisterAutoTunnelServiceRecords(m, info);
 	DeregisterAutoTunnel6Record(m, info);
+	DeregisterAutoTunnel6MetaRecord(m, info);
 	RegisterAutoTunnelServiceRecords(m, info);
 
 	mDNS_Lock(m);
 	RegisterAutoTunnelDevInfoRecord(m, info);
 	RegisterAutoTunnel6Record(m, info);
+	RegisterAutoTunnel6MetaRecord(m, info);
 	m->NextSRVUpdate = NonZeroTime(m->timenow);
 	mDNS_Unlock(m);
 	}
@@ -5596,7 +5660,6 @@
 	{
 	DomainAuthInfo *BTMMDomain = mDNSNULL;
 	DomainAuthInfo *FoundInList;
-	static mDNSBool AWACSDConnected = mDNSfalse;
 	char AllUsers[1024];	// maximum size of mach message
 	char AllPass[1024];  	// maximum size of mach message
 	char username[MAX_DOMAIN_LABEL + 1];
@@ -5635,6 +5698,14 @@
 		LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
 		AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
 		AWACSDConnected = mDNStrue;
+		
+		// We have to do this after AWACSDConnected is true
+		for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
+			if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
+				{
+				LogInfo("UpdateBTMMRelayConnection RegisterAutoTunnel6MetaRecord: %##s", FoundInList->domain.c);
+				RegisterAutoTunnel6MetaRecord(m, FoundInList);
+				}
 		}
 	else
 		{
@@ -6633,7 +6704,9 @@
 		// this case as though the dictionary does not have the value
 		RemoveAutoTunnel6Record(m);
 		// If awacsd crashes or exits for some reason, restart the relay connection
+		mDNS_Lock(m);
 		UpdateBTMMRelayConnection(m);
+		mDNS_Unlock(m);
 		return;
 		}
 	
@@ -6697,7 +6770,9 @@
 		RemoveAutoTunnel6Record(m);
 		m->AutoTunnelRelayAddrOut = zerov6Addr;
 		// We don't have a utun interface, start the relay connection if possible
+		mDNS_Lock(m);
 		UpdateBTMMRelayConnection(m);
+		mDNS_Unlock(m);
 		}
 	else
 		{
@@ -7960,15 +8035,32 @@
 
 		len = strlen(buf);
 		if (!len) break;	// sanity check
-
+		//Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)  
 		if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
+			{
 			buf[len - 1] = '\0';
-
+			len = len - 1;
+			}
 		// fgets always null terminates and hence even if we have no
-		// newline at the end, it is null terminated. The callee expects
-		// the length to be such that buf[length] to be zero and hence
-		// we pass len - 1.
-		mDNSMacOSXParseEtcHostsLine(m, buf, len - 1, auth);
+                // newline at the end, it is null terminated. The callee                                                                                                          
+                // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
+                // buf[length] is zero and hence we decrement len to reflect that.
+		if (len)
+			{
+			//Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
+			//here we need to check for just \r but taking extra caution.
+			if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
+				{
+				buf[len - 1] = '\0';
+				len = len - 1;
+				}
+			}
+		if (!len) //Sanity Check: len should never be zero
+			{
+			LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
+			continue;
+			}
+		mDNSMacOSXParseEtcHostsLine(m, buf, len, auth);
 		}
 	fclose(fp);
 	}
diff --git a/mDNSPosix/Identify.c b/mDNSPosix/Identify.c
index 66f7410..2ca9fc6 100644
--- a/mDNSPosix/Identify.c
+++ b/mDNSPosix/Identify.c
@@ -335,13 +335,8 @@
 			if (StopNow == 2) break;
 			}
 #endif
-		else {
-			if (strlen(arg) >= sizeof(hostname)) {
-				fprintf(stderr, "hostname must be < %d characters\n", (int)sizeof(hostname));
-				goto usage;
-			}
+		else
 			strcpy(hostname, arg);
-		}
 	
 		// Now we have the host name; get its A, AAAA, and HINFO
 		if (hostname[0]) DoQuery(&q, hostname, kDNSQType_ANY, &target, InfoCallback);
@@ -373,6 +368,6 @@
 	return(0);
 
 usage:
-	fprintf(stderr, "Usage: %s <dot-local hostname> or <IPv4 address> or <IPv6 address> ...\n", progname);
+	fprintf(stderr, "%s <dot-local hostname> or <IPv4 address> or <IPv6 address> ...\n", progname);
 	return(-1);
 	}
diff --git a/mDNSPosix/Makefile b/mDNSPosix/Makefile
index 55d7f8d..6ca9013 100755
--- a/mDNSPosix/Makefile
+++ b/mDNSPosix/Makefile
@@ -99,18 +99,12 @@
 endif
 else
 
-# any target that contains the string "linux"
-ifeq ($(findstring linux,$(os)),linux)
-CFLAGS_OS = -D_GNU_SOURCE -DHAVE_IPV6 -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX -DTARGET_OS_LINUX -fno-strict-aliasing
-LD = gcc -shared
+ifeq ($(os),linux)
+CFLAGS_OS = -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX -DTARGET_OS_LINUX
 FLEXFLAGS_OS = -l
 JAVACFLAGS_OS += -I$(JDK)/include/linux
-
-# uClibc does not support Name Service Switch
-ifneq ($(os),linux-uclibc)
 OPTIONALTARG = nss_mdns
 OPTINSTALL   = InstalledNSS
-endif
 else
 
 ifeq ($(os),netbsd)
@@ -120,9 +114,11 @@
 
 ifeq ($(os),freebsd)
 # If not already defined, set LOCALBASE to /usr/local
+# FreeBSD requires the startup script to end in ".sh"
 LOCALBASE?=/usr/local
 INSTBASE=$(LOCALBASE)
-CFLAGS_OS = -DHAVE_IPV6
+STARTUPSCRIPTNAME=mdns.sh
+CFLAGS_OS =
 # FreeBSD 4 requires threaded code to be compiled and linked using the "-pthread" option,
 # and requires that the "-lpthread" link option NOT be used
 # This appies only to FreeBSD -- "man cc" on FreeBSD says:
@@ -144,8 +140,7 @@
 # We have to define __MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 or on Leopard
 # we get build failures: ‘daemon’ is deprecated (declared at /usr/include/stdlib.h:283)
 CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -Wdeclaration-after-statement \
-	-D__MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 \
-	-D__APPLE_USE_RFC_2292 #-Wunreachable-code
+	-D__MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 #-Wunreachable-code
 CC = gcc
 LD = $(CC) -dynamiclib
 LINKOPTS = -lSystem
@@ -155,7 +150,7 @@
 else
 
 $(error ERROR: Must specify target OS on command-line, e.g. "make os=x [target]".\
-Supported operating systems include: x, linux, linux-uclibc, netbsd, freebsd, openbsd, solaris) 
+Supported operating systems include: x, linux, netbsd, freebsd, openbsd, solaris) 
 endif
 endif
 endif
diff --git a/mDNSPosix/ReadMe.txt b/mDNSPosix/ReadMe.txt
index c2f5641..d4bff85 100755
--- a/mDNSPosix/ReadMe.txt
+++ b/mDNSPosix/ReadMe.txt
@@ -297,16 +297,6 @@
 
 6 Aug 2002
 
-Impact: A local network user may cause a denial of the Bonjour service
-Description: An error handling issue exists in the Bonjour Namespace
-Provider. A local network user may send a maliciously crafted multicast
-DNS packet leading to an unexpected termination of the Bonjour service.
-This update addresses the issue by performing additional validation of
-multicast DNS packets. This issue does not affect systems running Mac OS
-X or Windows.
-CVE-ID
-CVE-2011-0220 : JaeSeung Song of the Department of Computing at Imperial
-College London
 
 To Do List
 ----------
diff --git a/mDNSPosix/Responder.c b/mDNSPosix/Responder.c
index 38639ea..21109b8 100755
--- a/mDNSPosix/Responder.c
+++ b/mDNSPosix/Responder.c
@@ -453,12 +453,11 @@
 
         if (gMDNSPlatformPosixVerboseLevel > 0) {
             fprintf(stderr, 
-                    "%s: Registered service %d, name \"%s\", type \"%s\", domain \"%s\",  port %ld\n", 
+                    "%s: Registered service %d, name '%s', type '%s', port %ld\n", 
                     gProgramName, 
                     thisServ->serviceID, 
                     richTextName,
                     serviceType,
-                    serviceDomain,
                     portNumber);
         }
     } else {
@@ -469,143 +468,108 @@
     return status;
 }
 
-static mDNSBool ReadALine(char *buf, size_t bufSize, FILE *fp, mDNSBool skipBlankLines)
+static mDNSBool ReadALine(char *buf, size_t bufSize, FILE *fp)
+// Read a line, skipping over any blank lines or lines starting with '#'
 {
-	size_t	len;
-	mDNSBool readNextLine;
-
+	mDNSBool good, skip;
 	do {
-		readNextLine = mDNSfalse;
-
-		if (fgets(buf, bufSize, fp) == NULL)
-			return mDNSfalse;	// encountered EOF or an error condition
-
-		// These first characters indicate a blank line.
-		if (buf[0] == ' ' || buf[0] == '\t' || buf[0] == '\r' || buf[0] == '\n') {
-			if (!skipBlankLines)
-				return mDNSfalse;
-			readNextLine = mDNStrue;
-		}
-		// always skip comment lines
-		if (buf[0] == '#')
-			readNextLine = mDNStrue;
-
-	} while (readNextLine);
-
-	len = strlen( buf);
-	if ( buf[len - 1] == '\r' || buf[len - 1] == '\n')
-		buf[len - 1] = '\0';
-
-    return mDNStrue;
+		good = (fgets(buf, bufSize, fp) != NULL);
+		skip = (good && (buf[0] == '#'));
+	} while (good && skip);
+	if (good)
+	{
+		int		len = strlen( buf);
+		if ( buf[len - 1] == '\r' || buf[len - 1] == '\n')
+			buf[len - 1] = '\0';
+	}
+    return good;
 }
 
 static mStatus RegisterServicesInFile(const char *filePath)
 {
     mStatus     status = mStatus_NoError;
     FILE *      fp = fopen(filePath, "r");
+    int         junk;
     
     if (fp == NULL) {
-        return mStatus_UnknownErr;
+        status = mStatus_UnknownErr;
     }
+    if (status == mStatus_NoError) {
+        mDNSBool good = mDNStrue;
+        do {
+			int         ch;
+			char name[256];
+			char type[256];
+			const char *dom = kDefaultServiceDomain;
+			char rawText[1024];
+			mDNSu8  text[sizeof(RDataBody)];
+			unsigned int textLen = 0;
+			char port[256];
 
-	if (gMDNSPlatformPosixVerboseLevel > 1)
-		fprintf(stderr, "Parsing %s for services\n", filePath);
-
-	do {
-		char nameBuf[256];
-		char * name = nameBuf; 
-		char type[256];
-		const char *dom = kDefaultServiceDomain;
-		char rawText[1024];
-		mDNSu8  text[sizeof(RDataBody)];
-		unsigned int textLen = 0;
-		char port[256];
-		char *p;
-
-		// Read the service name, type, port, and optional text record fields.
-		// Skip blank lines while looking for the next service name.
-		if (! ReadALine(name, sizeof(nameBuf), fp, mDNStrue))
-			break;
-
-		// Special case that allows service name to begin with a '#'
-		// character by escaping it with a '\' to distiguish it from
-		// a comment line.  Remove the leading '\' here before
-		// registering the service.
-		if (name[0] == '\\' && name[1] == '#')
-			name++;
-
-		if (gMDNSPlatformPosixVerboseLevel > 1)
-			fprintf(stderr, "Service name: \"%s\"\n", name);
-
-		// Don't skip blank lines in calls to ReadAline() after finding the
-		// service name since the next blank line indicates the end
-		// of this service record.
-		if (! ReadALine(type, sizeof(type), fp, mDNSfalse))
-			break;
-
-		// see if a domain name is specified
-		p = type;
-		while (*p && *p != ' ' && *p != '\t') p++;
-		if (*p) {
-			*p = 0;	// NULL terminate the <type>.<protocol> string
-			// skip any leading whitespace before domain name
-			p++;
-			while (*p && (*p == ' ' || *p == '\t')) p++;
-			if (*p)
-				dom = p;
-		}
-		if (gMDNSPlatformPosixVerboseLevel > 1) {
-			fprintf(stderr, "Service type: \"%s\"\n", type);
-			fprintf(stderr, "Service domain: \"%s\"\n", dom);
-		}
-
-		if (! ReadALine(port, sizeof(port), fp, mDNSfalse))
-			break;
-		if (gMDNSPlatformPosixVerboseLevel > 1)
-			fprintf(stderr, "Service port: %s\n", port);
-
-		if (   ! CheckThatRichTextNameIsUsable(name, mDNStrue)
-			|| ! CheckThatServiceTypeIsUsable(type, mDNStrue)
-			|| ! CheckThatPortNumberIsUsable(atol(port), mDNStrue))
-			break;
-
-		// read the TXT record fields
-		while (1) {
-			int len;
-			if (!ReadALine(rawText, sizeof(rawText), fp, mDNSfalse)) break;
-			if (gMDNSPlatformPosixVerboseLevel > 1)
-				fprintf(stderr, "Text string: \"%s\"\n", rawText);
-			len = strlen(rawText);
-			if (len <= 255)
-				{
-				unsigned int newlen = textLen + 1 + len;
-				if (len == 0 || newlen >= sizeof(text)) break;
-				text[textLen] = len;
-				mDNSPlatformMemCopy(text + textLen + 1, rawText, len);
-				textLen = newlen;
+            // Skip over any blank lines.
+            do ch = fgetc(fp); while ( ch == '\n' || ch == '\r' );
+            if (ch != EOF) good = (ungetc(ch, fp) == ch);
+            
+            // Read three lines, check them for validity, and register the service.
+			good = ReadALine(name, sizeof(name), fp);               
+			if (good) {
+				good = ReadALine(type, sizeof(type), fp);
+			}
+			if (good) {
+				char *p = type;
+				while (*p && *p != ' ') p++;
+				if (*p) {
+					*p = 0;
+					dom = p+1;
 				}
-			else
-				fprintf(stderr, "%s: TXT attribute too long for name = %s, type = %s, port = %s\n", 
-					gProgramName, name, type, port);
-		}
+			}
+			if (good) {
+				good = ReadALine(port, sizeof(port), fp);
+			}
+			if (good) {
+				good =     CheckThatRichTextNameIsUsable(name, mDNSfalse)
+						&& CheckThatServiceTypeIsUsable(type, mDNSfalse)
+						&& CheckThatPortNumberIsUsable(atol(port), mDNSfalse);
+			}
+			if (good) {
+				while (1) {
+					int len;
+					if (!ReadALine(rawText, sizeof(rawText), fp)) break;
+					len = strlen(rawText);
+					if (len <= 255)
+						{
+						unsigned int newlen = textLen + 1 + len;
+						if (len == 0 || newlen >= sizeof(text)) break;
+						text[textLen] = len;
+						mDNSPlatformMemCopy(text + textLen + 1, rawText, len);
+						textLen = newlen;
+						}
+					else
+						fprintf(stderr, "%s: TXT attribute too long for name = %s, type = %s, port = %s\n", 
+							gProgramName, name, type, port);
+				}
+			}
+			if (good) {
+				status = RegisterOneService(name, type, dom, text, textLen, atol(port));
+				if (status != mStatus_NoError) {
+					fprintf(stderr, "%s: Failed to register service, name = %s, type = %s, port = %s\n", 
+							gProgramName, name, type, port);
+					status = mStatus_NoError;       // keep reading
+				}
+			}
+        } while (good && !feof(fp));
 
-		status = RegisterOneService(name, type, dom, text, textLen, atol(port));
-		if (status != mStatus_NoError) {
-			// print error, but try to read and register other services in the file
-			fprintf(stderr, "%s: Failed to register service, name \"%s\", type \"%s\", domain \"%s\", port %s\n", 
-					gProgramName, name, type, dom, port);
-		}
-
-	} while (!feof(fp));
-
-	if (!feof(fp)) {
-		fprintf(stderr, "%s: Error reading service file %s\n", gProgramName, filePath);
-		status = mStatus_UnknownErr;
-	}
+        if ( ! good ) {
+            fprintf(stderr, "%s: Error reading service file %s\n", gProgramName, filePath);
+        }
+    }
     
-	assert(0 == fclose(fp));
+    if (fp != NULL) {
+        junk = fclose(fp);
+        assert(junk == 0);
+    }
     
-	return status;
+    return status;
 }
 
 static mStatus RegisterOurServices(void)
diff --git a/mDNSPosix/Services.txt b/mDNSPosix/Services.txt
index f8d6978..f5870bb 100755
--- a/mDNSPosix/Services.txt
+++ b/mDNSPosix/Services.txt
@@ -1,36 +1,15 @@
-#
-# Example services file parsed by mDNSResponderPosix.
-# 
-# Lines beginning with '#' are comments/ignored.
-# Blank lines indicate the end of a service record specification.
-# The first character of the service name can be a '#' if you escape it with 
-# backslash to distinguish if from a comment line.
-# ie, "\#serviceName" will be registered as "#serviceName".
-# Note that any line beginning with white space is considered a blank line.
-#
-# The record format is:
-# 
-# <service name>
-# <type>.<protocol> <optional domain>
-# <port number>
-# <zero or more strings for the text record, one string per line>
-#
-# <One or more blank lines between records>
-# 
-# Examples shown below.
-
-serviceName1
+Tweedlebug
 _afpovertcp._tcp.
 548
 name=val1
 
-serviceName2
+Tweedlebug2
 _afpovertcp._tcp. local.
 548
 name=val2
 name2=anotherattribute
 
-serviceName3
+Tweedlebug3
 _afpovertcp._tcp.
 548
 name=val3
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index 74a2161..3db5266 100755
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -159,12 +159,8 @@
 	assert(msg != NULL);
 	assert(end != NULL);
 	assert((((char *) end) - ((char *) msg)) > 0);
+	assert(dstPort.NotAnInteger != 0);
 
-	if (dstPort.NotAnInteger == 0) 
-		{
-		LogMsg("mDNSPlatformSendUDP: Invalid argument -dstPort is set to 0");
-		return PosixErrorToStatus(EINVAL);
-		}
 	if (dst->type == mDNSAddrType_IPv4)
 		{
 		struct sockaddr_in *sin = (struct sockaddr_in*)&to;
@@ -718,7 +714,7 @@
 	#if defined(IPV6_PKTINFO)
 		if (err == 0)
 			{
-				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_PKTINFO, &kOn, sizeof(kOn));
+				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_PKTINFO, &kOn, sizeof(kOn));
 				if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
 			}
 	#else
@@ -727,7 +723,7 @@
 	#if defined(IPV6_HOPLIMIT)
 		if (err == 0)
 			{
-				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_HOPLIMIT, &kOn, sizeof(kOn));
+				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_HOPLIMIT, &kOn, sizeof(kOn));
 				if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
 			}
 	#endif
@@ -845,7 +841,6 @@
 		// Set up the fields required by the mDNS core.
 		SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL);
 		SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL);
-
 		//LogMsg("SetupOneInterface: %#a %#a",  &intf->coreIntf.ip,  &intf->coreIntf.mask);
 		strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
 		intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
diff --git a/mDNSPosix/mDNSUNP.c b/mDNSPosix/mDNSUNP.c
index 8027676..e8fc649 100755
--- a/mDNSPosix/mDNSUNP.c
+++ b/mDNSPosix/mDNSUNP.c
@@ -82,7 +82,7 @@
 /* Gets IPv6 interface information from the /proc filesystem in linux*/
 struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
 	{
-		struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
+	struct ifi_info *ifi, *ifihead, **ifipnext;
 	FILE *fp;
 	char addr[8][5];
 	int flags, myflags, index, plen, scope;
@@ -92,8 +92,6 @@
 	struct sockaddr_in6 *sin6;
 	struct in6_addr *addrptr;
 	int err;
-	int sockfd = -1;
-	struct ifreq ifr;
 
 	res0=NULL;
 	ifihead = NULL;
@@ -101,10 +99,6 @@
 	lastname[0] = 0;
 
 	if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
-		sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
-		if (sockfd < 0) {
-			goto gotError;
-		}
 		while (fscanf(fp,
 					  "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
 					  addr[0],addr[1],addr[2],addr[3],
@@ -121,10 +115,8 @@
 			ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
 			if (ifi == NULL) {
 				goto gotError;
-			}
-			
-			ifipold   = *ifipnext;       /* need this later */
-			ifiptr    = ifipnext;
+				}
+
 			*ifipnext = ifi;            /* prev points to this new one */
 			ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
 
@@ -169,25 +161,9 @@
 			/* Add interface index */
 			ifi->ifi_index = index;
 
-			/* Add interface flags*/
-			memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-			if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
-				if (errno == EADDRNOTAVAIL) {
-					/* 
-					 * If the main interface is configured with no IP address but 
-					 * an alias interface exists with an IP address, you get 
-					 * EADDRNOTAVAIL for the main interface 
-					 */
-					free(ifi->ifi_addr);
-					free(ifi);
-					ifipnext  = ifiptr; 
-					*ifipnext = ifipold;
-					continue;
-				} else {
-					goto gotError;
-				}
-			}
-			ifi->ifi_flags = ifr.ifr_flags;
+			/* If interface is in /proc then it is up*/
+			ifi->ifi_flags = IFF_UP;
+
 			freeaddrinfo(res0);
 			res0=NULL;
 			}
@@ -204,9 +180,6 @@
 		res0=NULL;
 		}
 	done:
-	if (sockfd != -1) {
-		assert(close(sockfd) == 0);
-	}
 	return(ifihead);    /* pointer to first structure in linked list */
 	}
 #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
@@ -214,7 +187,7 @@
 struct ifi_info *get_ifi_info(int family, int doaliases)
 {
     int                 junk;
-    struct ifi_info     *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
+    struct ifi_info     *ifi, *ifihead, **ifipnext;
     int                 sockfd, sockf6, len, lastlen, flags, myflags;
 #ifdef NOT_HAVE_IF_NAMETOINDEX
     int                 index = 200;
@@ -306,11 +279,9 @@
         if (ifi == NULL) {
             goto gotError;
         }
-		ifipold   = *ifipnext;       /* need this later */
-		ifiptr    = ifipnext;
-		*ifipnext = ifi;             /* prev points to this new one */
-		ifipnext  = &ifi->ifi_next;  /* pointer to next one goes here */
-		
+        *ifipnext = ifi;            /* prev points to this new one */
+        ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
+
         ifi->ifi_flags = flags;     /* IFF_xxx values */
         ifi->ifi_myflags = myflags; /* IFI_xxx values */
 #ifndef NOT_HAVE_IF_NAMETOINDEX
@@ -339,23 +310,7 @@
                 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
 
 #ifdef  SIOCGIFNETMASK
-				if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
-					if (errno == EADDRNOTAVAIL) {
-						/* 
-						 * If the main interface is configured with no IP address but 
-						 * an alias interface exists with an IP address, you get 
-						 * EADDRNOTAVAIL for the main interface 
-						 */
-						free(ifi->ifi_addr);
-						free(ifi);
-						ifipnext  = ifiptr; 
-						*ifipnext = ifipold;
-						continue;
-					} else {
-						goto gotError;
-					}				
-				}
-
+				if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError;
 				ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
 				if (ifi->ifi_netmask == NULL) goto gotError;
 				sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
@@ -430,22 +385,7 @@
 				memset(&ifr6, 0, sizeof(ifr6));
 				memcpy(&ifr6.ifr_name,           &ifr->ifr_name, sizeof(ifr6.ifr_name          ));
 				memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
-				if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) {
-					if (errno == EADDRNOTAVAIL) {
-						/* 
-						 * If the main interface is configured with no IP address but 
-						 * an alias interface exists with an IP address, you get 
-						 * EADDRNOTAVAIL for the main interface 
-						 */
-						free(ifi->ifi_addr);
-						free(ifi);
-						ifipnext  = ifiptr; 
-						*ifipnext = ifipold;
-						continue;
-					} else {
-						goto gotError;
-					}				
-				}
+				if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError;
 				ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
 				if (ifi->ifi_netmask == NULL) goto gotError;
 				sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
@@ -636,9 +576,9 @@
         }
 #endif
 
-#if defined(IPV6_PKTINFO) && HAVE_IPV6 
-		if (cmptr->cmsg_level == IPPROTO_IPV6 && 
-            cmptr->cmsg_type  == IPV6_2292_PKTINFO) {
+#if defined(IPV6_PKTINFO) && HAVE_IPV6
+        if (cmptr->cmsg_level == IPPROTO_IPV6 && 
+            cmptr->cmsg_type == IPV6_PKTINFO) {
             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
 			struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
 			
@@ -657,7 +597,7 @@
 
 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
         if (cmptr->cmsg_level == IPPROTO_IPV6 && 
-            cmptr->cmsg_type == IPV6_2292_HOPLIMIT) {
+            cmptr->cmsg_type == IPV6_HOPLIMIT) {
 			*ttl = *(int*)CMSG_DATA(cmptr);
             continue;
         }
diff --git a/mDNSPosix/mDNSUNP.h b/mDNSPosix/mDNSUNP.h
index 6b04601..59b5501 100755
--- a/mDNSPosix/mDNSUNP.h
+++ b/mDNSPosix/mDNSUNP.h
@@ -25,15 +25,6 @@
 
 #ifdef HAVE_LINUX
 #include <linux/socket.h>
-#define IPV6_2292_PKTINFO  IPV6_2292PKTINFO
-#define IPV6_2292_HOPLIMIT IPV6_2292HOPLIMIT
-#else
-// The following are the supported non-linux posix OSes -
-// netbsd, freebsd and openbsd.
-#if HAVE_IPV6
-#define IPV6_2292_PKTINFO  19
-#define IPV6_2292_HOPLIMIT 20
-#endif 
 #endif
 
 #ifdef  __cplusplus
diff --git a/mDNSShared/CommonServices.h b/mDNSShared/CommonServices.h
index be49257..1261f1d 100644
--- a/mDNSShared/CommonServices.h
+++ b/mDNSShared/CommonServices.h
@@ -54,16 +54,6 @@
 	#endif
 #endif
 
-// FreeBSD
-
-#if( !defined( TARGET_OS_FREEBSD ) )
-	#if( defined( __FreeBSD__ ) )
-		#define TARGET_OS_FREEBSD		1
-	#else
-		#define TARGET_OS_FREEBSD		0
-	#endif
-#endif
-
 // Linux
 
 #if( !defined( TARGET_OS_LINUX ) )
@@ -100,7 +90,7 @@
 	
 	// No predefined macro for VxWorks so just assume VxWorks if nothing else is set.
 	
-	#if( !macintosh && !__MACH__  && !defined( __FreeBSD__ ) && !defined( __linux__ ) && !defined ( __SVR4 ) && !defined ( __sun ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) )
+	#if( !macintosh && !__MACH__  && !defined( __linux__ ) && !defined ( __SVR4 ) && !defined ( __sun ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) )
 		#define	TARGET_OS_VXWORKS		1
 	#else
 		#define	TARGET_OS_VXWORKS		0
@@ -189,15 +179,6 @@
 	#include	<libkern/OSTypes.h>
 	#include	<sys/types.h>
 	
-#elif( TARGET_OS_FREEBSD )
-
-	// FreeBSD
-	#include	<stdint.h>
-	#include	<pthread.h>
-	#include	<netinet/in.h>
-	#include	<arpa/inet.h>
-	#include	<sys/socket.h>
-
 #elif( TARGET_OS_LINUX )
 	
 	// Linux
@@ -474,7 +455,7 @@
 // - Windows
 
 #if( TARGET_LANGUAGE_C_LIKE )
-	#if( !defined(_SSIZE_T) && ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_FREEBSD && !TARGET_OS_LINUX && !TARGET_OS_VXWORKS && !TARGET_OS_MAC)
+	#if( !defined(_SSIZE_T) && ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_LINUX && !TARGET_OS_VXWORKS && !TARGET_OS_MAC)
 		typedef int						ssize_t;
 	#endif
 #endif
diff --git a/mDNSShared/dns_sd.h b/mDNSShared/dns_sd.h
index 607ebcd..45735c3 100644
--- a/mDNSShared/dns_sd.h
+++ b/mDNSShared/dns_sd.h
@@ -77,7 +77,7 @@
  */
 
 #ifndef _DNS_SD_H
-#define _DNS_SD_H 3201080
+#define _DNS_SD_H 3201400
 
 #ifdef  __cplusplus
     extern "C" {
diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c
index cfdc1bd..c3673a7 100644
--- a/mDNSShared/uds_daemon.c
+++ b/mDNSShared/uds_daemon.c
@@ -2504,6 +2504,9 @@
 			*q2               = *q;
 			q2->InterfaceID   = mDNSInterface_Unicast;
 			q2->ExpectUnique  = mDNStrue;
+			// Always set the QuestionContext to indicate that this question should be stopped
+			// before freeing. Don't rely on "q".
+			q2->QuestionContext = request;
 			// If the query starts as a single label e.g., somehost, and we have search domains with .local,
 			// queryrecord_result_callback calls this function when .local is appended to "somehost".
 			// At that time, the name in "q" is pointing at somehost.local and its qnameOrig pointing at
@@ -2727,8 +2730,26 @@
 			{
 			if (!answer->InterfaceID && IsLocalDomain(answer->name))
 				{
-				LogInfo("queryrecord_result_callback:Question %##s (%s) answering local with unicast", question->qname.c, DNSTypeName(question->qtype));
-				return;
+				mDNSu16 qtype;
+				// Sanity check: "q" will be set only if "question" is the .local unicast query.
+				if (!q)
+					{
+					LogMsg("queryrecord_result_callback: ERROR!! answering multicast question with unicast cache record");
+					return;
+					}
+				// Deliver negative response for A/AAAA if there was a positive response for AAAA/A respectively.
+				if (question->qtype != kDNSType_A && question->qtype != kDNSType_AAAA)
+					{
+					LogInfo("queryrecord_result_callback:Question %##s (%s) not answering local question with negative unicast response", question->qname.c, DNSTypeName(question->qtype));
+					return;
+					}
+				qtype = (question->qtype == kDNSType_A ? kDNSType_AAAA : kDNSType_A);
+				if (!mDNS_CheckForCacheRecord(m, question, qtype))
+					{
+					LogInfo("queryrecord_result_callback:Question %##s (%s) not answering local question with negative unicast response (can't find positive record)", question->qname.c, DNSTypeName(question->qtype));
+					return;
+					}
+				LogInfo("queryrecord_result_callback:Question %##s (%s) answering local with negative unicast response (found positive record)", question->qname.c, DNSTypeName(question->qtype));
 				}
 			error = kDNSServiceErr_NoSuchRecord;
 			}
@@ -3994,11 +4015,6 @@
 			// determine whether sa_len is defined on a particular platform.
 			laddr.sun_len = sizeof(struct sockaddr_un);
 			#endif
-			if (strlen(MDNS_UDS_SERVERPATH) >= sizeof(laddr.sun_path))
-				{
-					LogMsg("ERROR: MDNS_UDS_SERVERPATH must be < %d characters", (int)sizeof(laddr.sun_path));
-					goto error;
-				}
 			mDNSPlatformStrCopy(laddr.sun_path, MDNS_UDS_SERVERPATH);
 			ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
 			umask(mask);