From 8b5f5b69b7b25122b277c7193727c36ba7ae69e6 Mon Sep 17 00:00:00 2001 From: Apple Date: Wed, 16 Nov 2011 00:40:14 +0000 Subject: [PATCH] mDNSResponder-320.14.tar.gz --- Clients/dns-sd.c | 6 +- Makefile | 2 +- mDNSCore/mDNS.c | 34 +++++- mDNSCore/mDNSEmbeddedAPI.h | 15 ++- mDNSCore/uDNS.c | 13 ++- mDNSMacOSX/mDNSMacOSX.c | 106 ++++++++++++++++-- mDNSPosix/Identify.c | 9 +- mDNSPosix/Makefile | 19 ++-- mDNSPosix/ReadMe.txt | 10 -- mDNSPosix/Responder.c | 212 +++++++++++++++--------------------- mDNSPosix/Services.txt | 27 +---- mDNSPosix/mDNSPosix.c | 11 +- mDNSPosix/mDNSUNP.c | 92 +++------------- mDNSPosix/mDNSUNP.h | 9 -- mDNSShared/CommonServices.h | 23 +--- mDNSShared/dns_sd.h | 2 +- mDNSShared/uds_daemon.c | 30 +++-- 17 files changed, 293 insertions(+), 327 deletions(-) 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 @@ cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Rele #include // For inet_addr() #include // 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 @@ exit: // *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 @@ mDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q) } } +// 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 @@ enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 }; #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 @@ typedef struct DomainAuthInfo 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 *AuthGroupForName(AuthHash *r, const mDNSu32 slot, const mDNSu3 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 @@ struct CompileTimeAssertionChecks_mDNS 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 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, // 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 @@ static mDNSu8 SPMetricTotalPower = 99; mDNSexport domainname ActiveDirectoryPrimaryDomain; mDNSexport int ActiveDirectoryPrimaryDomainLabelCount; mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer; + +static mDNSBool AWACSDConnected = mDNSfalse; #endif // APPLE_OSX_mDNSResponder // Used by AutoTunnel @@ -3699,6 +3701,41 @@ mDNSlocal void DeregisterAutoTunnelDevInfoRecord(mDNS *m, DomainAuthInfo *info) } #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 @@ mDNSlocal void RegisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info) 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 @@ mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mSt 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 @@ mDNSlocal void AutoTunnelDeleteAuthInfoState(mDNS *m, DomainAuthInfo *info) 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 @@ mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info) #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 @@ mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m) { 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 @@ mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m) 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 @@ mDNSlocal void AddAutoTunnel6Record(mDNS *const m, char *ifname, CFDictionaryRef // 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 @@ mDNSlocal void ParseBackToMyMac(mDNS *const m, CFDictionaryRef connd) 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 @@ mDNSlocal void mDNSMacOSXParseEtcHosts(mDNS *const m, int fd, AuthHash *auth) 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 @@ mDNSexport int main(int argc, char **argv) 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 @@ mDNSexport int main(int argc, char **argv) return(0); usage: - fprintf(stderr, "Usage: %s or or ...\n", progname); + fprintf(stderr, "%s or or ...\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 @@ STRIP = strip 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 @@ else 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 @@ ifeq ($(os),x) # 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 @@ JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Header 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 @@ Networking, Communications, Hardware 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 @@ static mStatus RegisterOneService(const char * richTextName, 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 @@ static mStatus RegisterOneService(const char * richTextName, 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 (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 . 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; + 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]; + + // 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); - } - - 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 (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)); - 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: -# -# -# . -# -# -# -# -# -# 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 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms 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 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf #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 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf #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 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct // 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 @@ void plen_to_mask(int plen, char *addr) { /* 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 ifi_info *get_ifi_info_linuxv6(int family, int doaliases) struct sockaddr_in6 *sin6; struct in6_addr *addrptr; int err; - int sockfd = -1; - struct ifreq ifr; res0=NULL; ifihead = NULL; @@ -101,10 +99,6 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) 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 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) 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 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) /* 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 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) 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_linuxv6(int family, int doaliases) 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 @@ struct ifi_info *get_ifi_info(int family, int doaliases) 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 @@ struct ifi_info *get_ifi_info(int family, int doaliases) 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 @@ struct ifi_info *get_ifi_info(int family, int doaliases) 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 @@ struct in_pktinfo } #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 @@ struct in_pktinfo #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 -#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 #include -#elif( TARGET_OS_FREEBSD ) - - // FreeBSD - #include - #include - #include - #include - #include - #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 @@ mDNSlocal mStatus SendAdditionalQuery(DNSQuestion *q, request_state *request, mS *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 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question, { 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 @@ mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count) // 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); -- 2.47.2