diff options
Diffstat (limited to 'mDNSResponder/mDNSMacOSX/mDNSMacOSX.c')
-rw-r--r-- | mDNSResponder/mDNSMacOSX/mDNSMacOSX.c | 1346 |
1 files changed, 906 insertions, 440 deletions
diff --git a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c index deae0d1a..c57eddda 100644 --- a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c +++ b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2002-2015 Apple Inc. All rights reserved. + * Copyright (c) 2002-2016 Apple Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ #include "uDNS.h" #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform #include "dns_sd.h" // For mDNSInterface_LocalOnly etc. +#include "dns_sd_private.h" #include "PlatformCommon.h" #include "uds_daemon.h" #include "CryptoSupport.h" @@ -60,7 +61,7 @@ #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below #include <netinet/ip.h> // For IPTOS_LOWDELAY etc. -#include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc. +#include <netinet6/in6_var.h> // For IN6_IFF_TENTATIVE etc. #include <netinet/tcp.h> @@ -100,6 +101,8 @@ #include <AWACS.h> #include <ne_session.h> // for ne_session_set_socket_attributes() #if !NO_D2D +#include "BLE.h" + D2DStatus D2DInitialize(CFRunLoopRef runLoop, D2DServiceCallback serviceCallback, void* userData) __attribute__((weak_import)); D2DStatus D2DRetain(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import)); D2DStatus D2DStopAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import)); @@ -111,6 +114,9 @@ void D2DStartResolvingPairOnTransport(const Byte *key, const size_t keySize, con void D2DStopResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import)); D2DStatus D2DTerminate() __attribute__((weak_import)); +void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize); +void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize); + #endif // ! NO_D2D #else @@ -132,7 +138,7 @@ D2DStatus D2DTerminate() __attribute__((weak_import)); #define DARK_WAKE_TIME 16 // Time we hold an idle sleep assertion for maintenance after a wake notification // cache the InterfaceID of the AWDL interface -static mDNSInterfaceID AWDLInterfaceID; +mDNSInterfaceID AWDLInterfaceID; // *************************************************************************** // Globals @@ -176,9 +182,6 @@ mDNSexport int WatchDogReportingThreshold = 250; dispatch_queue_t SSLqueue; -//To prevent blocking the main queue, all writes to DynamicStore happen on the DynamicStoreQueue -static dispatch_queue_t DynamicStoreQueue; - #if TARGET_OS_EMBEDDED #define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist") #endif @@ -243,6 +246,26 @@ mDNSexport void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface) } } +// If record would have been advertised to the D2D plugin layer, stop that advertisement. +mDNSexport void D2D_stop_advertising_record(AuthRecord *ar) +{ + DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(ar->ARType); + if (callExternalHelpers(ar->resrec.InterfaceID, ar->resrec.name, flags)) + { + external_stop_advertising_service(&ar->resrec, flags); + } +} + +// If record should be advertised to the D2D plugin layer, start that advertisement. +mDNSexport void D2D_start_advertising_record(AuthRecord *ar) +{ + DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(ar->ARType); + if (callExternalHelpers(ar->resrec.InterfaceID, ar->resrec.name, flags)) + { + external_start_advertising_service(&ar->resrec, flags); + } +} + // Name compression items for fake packet version number 1 static const mDNSu8 compression_packet_v1 = 0x01; @@ -304,65 +327,6 @@ mDNSlocal void DomainnameToLower(const domainname * const in, domainname * const out->c[ptr-start] = *ptr; } -mDNSlocal mStatus DNSNameCompressionParseBytes(mDNS *const m, const mDNSu8 *const lhs, const mDNSu16 lhs_len, const mDNSu8 *const rhs, const mDNSu16 rhs_len, AuthRecord *rr) -{ - if (mDNS_LoggingEnabled) - { - LogInfo("%s", __func__); - LogInfo(" Static Bytes: (%d bytes)", compression_lhs - (mDNSu8*)&compression_base_msg); - PrintHex((mDNSu8*)&compression_base_msg, compression_lhs - (mDNSu8*)&compression_base_msg); - } - - mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet - - // Check to make sure we're not going to go past the end of the DNSMessage data - // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH - if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr; - - // Copy the LHS onto our fake wire packet - mDNSPlatformMemCopy(ptr, lhs, lhs_len); - ptr += lhs_len - 1; - - // Check the 'fake packet' version number, to ensure that we know how to decompress this data - if (*ptr != compression_packet_v1) return mStatus_Incompatible; - - // two bytes of CLASS - ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet); - - // four bytes of TTL - ptr = putVal32(ptr, 120); - - // Copy the RHS length into the RDLENGTH of our fake wire packet - ptr = putVal16(ptr, rhs_len); - - // Copy the RHS onto our fake wire packet - mDNSPlatformMemCopy(ptr, rhs, rhs_len); - ptr += rhs_len; - - if (mDNS_LoggingEnabled) - { - LogInfo(" Our Bytes (%d bytes): ", ptr - compression_lhs); - PrintHex(compression_lhs, ptr - compression_lhs); - } - - ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec); - if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative) - { LogMsg("DNSNameCompressionParseBytes: failed to get large RR"); m->rec.r.resrec.RecordType = 0; return mStatus_UnknownErr; } - else LogInfo("DNSNameCompressionParseBytes: got rr: %s", CRDisplayString(m, &m->rec.r)); - - mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, AuthRecordP2P, FreeD2DARElemCallback, NULL); - AssignDomainName(&rr->namestorage, &m->rec.namestorage); - rr->resrec.rdlength = m->rec.r.resrec.rdlength; - rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength; - mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength); - rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); - SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us - - m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use - - return mStatus_NoError; -} - mDNSlocal mDNSu8 * DNSNameCompressionBuildLHS(const domainname* typeDomain, DNS_TypeValues qtype) { mDNSu8 *ptr = putDomainNameAsLabels(&compression_base_msg, compression_lhs, compression_limit, typeDomain); @@ -459,8 +423,8 @@ mDNSlocal void xD2DClearCache(const domainname *regType, DNS_TypeValues qtype) { if ((ptr->ar.resrec.rrtype == qtype) && SameDomainName(&ptr->ar.namestorage, regType)) { - mDNS_Deregister(&mDNSStorage, &ptr->ar); LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage, &ptr->ar)); + mDNS_Deregister(&mDNSStorage, &ptr->ar); } } } @@ -498,11 +462,12 @@ mDNSlocal void D2DBrowseListRetain(const domainname *const name, mDNSu16 type) LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount); } -mDNSlocal void D2DBrowseListRelease(const domainname *const name, mDNSu16 type) +// Returns true if found in list, false otherwise +mDNSlocal bool D2DBrowseListRelease(const domainname *const name, mDNSu16 type) { D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type); - if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return; } + if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return false; } (*ptr)->refCount -= 1; @@ -514,35 +479,125 @@ mDNSlocal void D2DBrowseListRelease(const domainname *const name, mDNSu16 type) *ptr = (*ptr)->next; mDNSPlatformMemFree(tmp); } + return true; } -mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, AuthRecord *rr) +mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, D2DRecordListElem **D2DListp) { - if (*(lhs + (lhs_len - 1)) == compression_packet_v1) - return DNSNameCompressionParseBytes(m, lhs, lhs_len, rhs, rhs_len, rr); - else + // Sanity check that key array (lhs) has one domain name, followed by the record type and single byte D2D + // plugin protocol version number. + // Note, we don't have a DNSMessage pointer at this point, so just pass in the lhs value as the lower bound + // of the input bytes we are processing. skipDomainName() does not try to follow name compression pointers, + // so it is safe to pass it the key byte array since it will stop parsing the DNS name and return a pointer + // to the byte after the first name compression pointer it encounters. + const mDNSu8 *keyp = skipDomainName((const DNSMessage *const) lhs, lhs, lhs + lhs_len); + + // There should be 3 bytes remaining in a valid key, + // two for the DNS record type, and one for the D2D protocol version number. + if (keyp == NULL || (keyp + 3 != (lhs + lhs_len))) + { + LogInfo("xD2DParse: Could not parse DNS name in key"); return mStatus_Incompatible; + } + keyp += 2; // point to D2D compression packet format version byte + if (*keyp != compression_packet_v1) + { + LogInfo("xD2DParse: Invalid D2D packet version: %d", *keyp); + return mStatus_Incompatible; + } + + if (mDNS_LoggingEnabled) + { + LogInfo("%s", __func__); + LogInfo(" Static Bytes: (%d bytes)", compression_lhs - (mDNSu8*)&compression_base_msg); + PrintHex((mDNSu8*)&compression_base_msg, compression_lhs - (mDNSu8*)&compression_base_msg); + } + + mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet + + // Check to make sure we're not going to go past the end of the DNSMessage data + // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH + if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr; + + // Copy the LHS onto our fake wire packet + mDNSPlatformMemCopy(ptr, lhs, lhs_len); + ptr += lhs_len - 1; + + // Check the 'fake packet' version number, to ensure that we know how to decompress this data + if (*ptr != compression_packet_v1) return mStatus_Incompatible; + + // two bytes of CLASS + ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet); + + // four bytes of TTL + ptr = putVal32(ptr, 120); + + // Copy the RHS length into the RDLENGTH of our fake wire packet + ptr = putVal16(ptr, rhs_len); + + // Copy the RHS onto our fake wire packet + mDNSPlatformMemCopy(ptr, rhs, rhs_len); + ptr += rhs_len; + + if (mDNS_LoggingEnabled) + { + LogInfo(" Our Bytes (%d bytes): ", ptr - compression_lhs); + PrintHex(compression_lhs, ptr - compression_lhs); + } + + ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec); + if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative) + { + LogMsg("xD2DParse: failed to get large RR"); + m->rec.r.resrec.RecordType = 0; + return mStatus_UnknownErr; + } + else + { + LogInfo("xD2DParse: got rr: %s", CRDisplayString(m, &m->rec.r)); + } + + *D2DListp = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (m->rec.r.resrec.rdlength <= sizeof(RDataBody) ? 0 : m->rec.r.resrec.rdlength - sizeof(RDataBody))); + if (!*D2DListp) return mStatus_NoMemoryErr; + + AuthRecord *rr = &(*D2DListp)->ar; + mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, AuthRecordP2P, FreeD2DARElemCallback, NULL); + AssignDomainName(&rr->namestorage, &m->rec.namestorage); + rr->resrec.rdlength = m->rec.r.resrec.rdlength; + rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength; + mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength); + rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); + SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us + + m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use + + return mStatus_NoError; } -mDNSlocal void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize) +mDNSexport void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize) { if (result == kD2DSuccess) { if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; } mStatus err; - D2DRecordListElem *ptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData))); - - if (ptr == NULL) { LogMsg("xD2DAddToCache: memory allocation failure"); return; } + D2DRecordListElem *ptr = NULL; - err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr->ar); + err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr); if (err) { LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err); PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize); - mDNSPlatformMemFree(ptr); + if (ptr) + mDNSPlatformMemFree(ptr); return; } + + // If the record was created based on a BLE beacon, update the interface index to indicate + // this and thus match BLE specific queries. + if (transportType == D2DBLETransport) + ptr->ar.resrec.InterfaceID = mDNSInterface_BLE; + err = mDNS_Register(m, &ptr->ar); if (err) { @@ -564,17 +619,17 @@ mDNSlocal void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstanc mDNSlocal D2DRecordListElem * xD2DFindInList(mDNS *const m, const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize) { D2DRecordListElem *ptr = D2DRecords; - D2DRecordListElem *arptr; + D2DRecordListElem *arptr = NULL; if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; } - arptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData))); - if (arptr == NULL) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL; } - - if (xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr->ar) != mStatus_NoError) + mStatus err = xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr); + if (err) { - LogMsg("xD2DFindInList: xD2DParse failed for key: %p (%u) value: %p (%u)", key, keySize, value, valueSize); - mDNSPlatformMemFree(arptr); + LogMsg("xD2DFindInList: xD2DParse returned error: %d", err); + PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize); + if (arptr) + mDNSPlatformMemFree(arptr); return NULL; } @@ -589,7 +644,7 @@ mDNSlocal D2DRecordListElem * xD2DFindInList(mDNS *const m, const Byte *const ke return ptr; } -mDNSlocal void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize) +mDNSexport void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize) { (void)transportType; // We don't care about this, yet. (void)instanceHandle; // We don't care about this, yet. @@ -777,23 +832,45 @@ mDNSlocal D2DTransportType xD2DInterfaceToTransportType(mDNSInterfaceID Interfac return D2DTransportMax; } -mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags) +// Similar to callExternalHelpers(), but without the checks for the BLE specific interface or flags. +// It's assumed that the domain was already verified to be .local once we are at this level. +mDNSlocal mDNSBool callInternalHelpers(mDNSInterfaceID InterfaceID, DNSServiceFlags flags) { - domainname lower; + if ( ((InterfaceID == mDNSInterface_Any) && (flags & (kDNSServiceFlagsIncludeP2P | kDNSServiceFlagsIncludeAWDL))) + || mDNSPlatformInterfaceIsD2D(InterfaceID)) + return mDNStrue; + else + return mDNSfalse; +} - if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA) +mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags, DNSQuestion * q) +{ + // BLE support currently not handled by a D2D plugin + if (applyToBLE(InterfaceID, flags)) { - LogInfo("external_start_browsing_for_service: ignoring address record"); - return; + domainname lower; + + DomainnameToLower(typeDomain, &lower); + // pass in the key and keySize + mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype); + start_BLE_browse(q, &lower, qtype, flags, compression_lhs, end - compression_lhs); } + if (callInternalHelpers(InterfaceID, flags)) + internal_start_browsing_for_service(InterfaceID, typeDomain, qtype, flags); +} + +mDNSexport void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags) +{ + domainname lower; + DomainnameToLower(typeDomain, &lower); if (!D2DBrowseListRefCount(&lower, qtype)) { D2DTransportType transportType, excludedTransport; - LogInfo("external_start_browsing_for_service: Starting browse for: %##s %s", lower.c, DNSTypeName(qtype)); + LogInfo("%s: Starting browse for: %##s %s", __func__, lower.c, DNSTypeName(qtype)); mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype); PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0); @@ -817,22 +894,34 @@ mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, mDNSexport void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags) { - domainname lower; - - if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA) + // BLE support currently not handled by a D2D plugin + if (applyToBLE(InterfaceID, flags)) { - LogInfo("external_stop_browsing_for_service: ignoring address record"); - return; + domainname lower; + + // If this is the last instance of this browse, clear any cached records recieved for it. + // We are not guaranteed to get a D2DServiceLost event for all key, value pairs cached over BLE. + DomainnameToLower(typeDomain, &lower); + if (stop_BLE_browse(&lower, qtype, flags)) + xD2DClearCache(&lower, qtype); } + if (callInternalHelpers(InterfaceID, flags)) + internal_stop_browsing_for_service(InterfaceID, typeDomain, qtype, flags); +} + +mDNSexport void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags) +{ + domainname lower; + DomainnameToLower(typeDomain, &lower); - D2DBrowseListRelease(&lower, qtype); - if (!D2DBrowseListRefCount(&lower, qtype)) + // If found in list and this is the last reference to this browse, remove the key from the D2D plugins. + if (D2DBrowseListRelease(&lower, qtype) && !D2DBrowseListRefCount(&lower, qtype)) { D2DTransportType transportType, excludedTransport; - LogInfo("external_stop_browsing_for_service: Stopping browse for: %##s %s", lower.c, DNSTypeName(qtype)); + LogInfo("%s: Stopping browse for: %##s %s", __func__, lower.c, DNSTypeName(qtype)); mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype); PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0); @@ -860,13 +949,24 @@ mDNSexport void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { + // Note, start_BLE_advertise() is currently called directly from external_start_advertising_helper() since + // it needs to pass the ServiceRecordSet so that we can promote the record advertisements to AWDL + // when we see the corresponding browse indication over BLE. + + if (callInternalHelpers(resourceRecord->InterfaceID, flags)) + internal_start_advertising_service(resourceRecord, flags); +} + +mDNSexport void internal_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) +{ domainname lower; mDNSu8 *rhs = NULL; mDNSu8 *end = NULL; D2DTransportType transportType, excludedTransport; DomainnameToLower(resourceRecord->name, &lower); - LogInfo("external_start_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord)); + LogInfo("%s: %s", __func__, RRDisplayString(&mDNSStorage, resourceRecord)); + // For SRV records, update packet filter if p2p interface already exists, otherwise, // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface. if (resourceRecord->rrtype == kDNSType_SRV) @@ -894,14 +994,30 @@ mDNSexport void external_start_advertising_service(const ResourceRecord *const r mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { + // BLE support currently not handled by a D2D plugin + if (applyToBLE(resourceRecord->InterfaceID, flags)) + { + domainname lower; + + DomainnameToLower(resourceRecord->name, &lower); + stop_BLE_advertise(&lower, resourceRecord->rrtype, flags); + } + + if (callInternalHelpers(resourceRecord->InterfaceID, flags)) + internal_stop_advertising_service(resourceRecord, flags); +} + +mDNSexport void internal_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) +{ domainname lower; mDNSu8 *rhs = NULL; mDNSu8 *end = NULL; D2DTransportType transportType, excludedTransport; DomainnameToLower(resourceRecord->name, &lower); - LogInfo("external_stop_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord)); + LogInfo("%s: %s", __func__, RRDisplayString(&mDNSStorage, resourceRecord)); + // For SRV records, update packet filter if p2p interface already exists, otherwise, // For SRV records, update packet filter to to remove this port from list if (resourceRecord->rrtype == kDNSType_SRV) mDNSUpdatePacketFilter(resourceRecord); @@ -969,8 +1085,8 @@ mDNSexport void external_start_resolving_service(mDNSInterfaceID InterfaceID, co if (AWDL_used && AWDLInterfaceID) { LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL"); - external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, 0); - external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, 0); + external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, 0, 0); + external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, 0, 0); } } @@ -1022,7 +1138,12 @@ mDNSexport void external_stop_resolving_service(mDNSInterfaceID InterfaceID, con #elif APPLE_OSX_mDNSResponder -mDNSexport void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;} +mDNSexport void internal_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags } +mDNSexport void internal_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;} +mDNSexport void internal_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;} +mDNSexport void internal_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;} + +mDNSexport void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags; (void)q } mDNSexport void external_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;} mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;} mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;} @@ -1046,14 +1167,12 @@ mDNSexport void external_stop_resolving_service(const domainname *const fqdn, DN // to run up the user's bill sending multicast traffic over a link where there's only a single device at the // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway. -// We also don't want to use multicast on *any* physical interface on very constrained devices. -#if 0 -#define MulticastInterface(i) ((i)->ifa_flags & IFF_LOOPBACK) -#elif TARGET_OS_WATCH -#define MulticastInterface(i) ((i)->m->NumAllInterfaceRecords + (i)->m->NumAllInterfaceQuestions > 0 && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT)) +#if BONJOUR_ON_DEMAND +#define MulticastInterface(i) ((i)->m->BonjourEnabled && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT)) #else #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT)) #endif +#define SPSInterface(i) ((i)->ifinfo.McastTxRx && !((i)->ifa_flags & IFF_LOOPBACK) && !(i)->D2DInterface) mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text { @@ -1065,7 +1184,8 @@ mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both for (i = mDNSStorage.p->InterfaceList; i; i = i->next) if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17) break; - if (!i) return; // If not at Apple, don't show the alert + if (!i) + return; // If not at Apple, don't show the alert } #endif @@ -1075,12 +1195,20 @@ mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both // If we display our alert early in the boot process, then it vanishes once the desktop appears. // To avoid this, we don't try to display alerts in the first three minutes after boot. if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) - { LogMsg("Suppressing notification early in boot: %d", mDNSPlatformRawTime()); return; } + { + LogMsg("Suppressing notification early in boot: %d", mDNSPlatformRawTime()); + return; + } #ifndef NO_CFUSERNOTIFICATION static int notifyCount = 0; // To guard against excessive display of warning notifications - if (notifyCount < 5) { notifyCount++; mDNSNotify(title, msg); } + if (notifyCount < 5) + { + notifyCount++; + mDNSNotify(title, msg); + } #endif /* NO_CFUSERNOTIFICATION */ + } // Write a syslog message and display an alert, then if ForceAlerts is set, generate a stack trace @@ -1249,10 +1377,11 @@ mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropert subkeyCopy[len] = 0; } - dispatch_async(DynamicStoreQueue, ^{ + dispatch_async(dispatch_get_main_queue(), ^{ CFWriteStreamRef stream = NULL; CFDataRef bytes = NULL; CFIndex ret; + KQueueLock(&mDNSStorage); if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL))) { @@ -1274,7 +1403,6 @@ mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropert CFWriteStreamClose(stream); CFRelease(stream); stream = NULL; - LogInfo("mDNSDynamicStoreSetConfig: key %d subkey %s", key, subkeyCopy); DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes)); END: @@ -1288,6 +1416,8 @@ mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropert CFRelease(bytes); if (subkeyCopy) mDNSPlatformMemFree(subkeyCopy); + + KQueueUnlock(&mDNSStorage, "mDNSDynamicStoreSetConfig"); }); } @@ -1303,50 +1433,6 @@ mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const return(NULL); } -#if TARGET_OS_EMBEDDED -mDNSlocal SCPreferencesRef mDNSManagedPrefsGet(void) -{ - SCPreferencesRef smDNSManagedPrefs = NULL; - smDNSManagedPrefs = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("mDNSManagedPrefs"), kmDNSResponderManagedPrefsID); - - return (smDNSManagedPrefs); -} - -mDNSlocal mDNSBool GetmDNSManagedPrefKeyVal(SCPreferencesRef prefs, CFStringRef key) -{ - mDNSBool val = mDNSfalse; - CFBooleanRef val_cf = NULL; - - if (prefs != NULL) - { - val_cf = SCPreferencesGetValue(prefs, key); - if (isA_CFBoolean(val_cf) != NULL) - val = CFBooleanGetValue(val_cf); //When mDNSResponder-Debug-profile is Installed - else - val = mDNSfalse; //When mDNSResponder-Debug-profile is Uninstalled - } - else - { - LogMsg("GetmDNSManagedPrefKeyVal: mDNSManagedPrefs are NULL!"); - val = mDNSfalse; - } - return (val); -} - -mDNSexport mDNSBool GetmDNSManagedPref(CFStringRef key) -{ - SCPreferencesRef managed = NULL; - mDNSBool ret_value; - - managed = mDNSManagedPrefsGet(); - ret_value = GetmDNSManagedPrefKeyVal(managed, key); - - if (managed) - CFRelease(managed); - return (ret_value); -} -#endif //TARGET_OS_EMBEDDED - mDNSlocal int myIfIndexToName(u_short ifindex, char *name) { struct ifaddrs *ifa; @@ -1373,6 +1459,7 @@ mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const { if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly); if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P); + if (ifindex == kDNSServiceInterfaceIndexBLE ) return(mDNSInterface_BLE); if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL); NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex); @@ -1393,9 +1480,11 @@ mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange) { NetworkInterfaceInfoOSX *i; + if (id == mDNSInterface_Any ) return(0); if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly); + if (id == mDNSInterface_Unicast ) return(0); if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P); - if (id == mDNSInterface_Any ) return(0); + if (id == mDNSInterface_BLE ) return(kDNSServiceInterfaceIndexBLE); mDNSu32 scope_id = (mDNSu32)(uintptr_t)id; @@ -1727,62 +1816,74 @@ mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass) (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class)); } -mDNSexport void mDNSPlatformSetuDNSSocktOpt(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q) +mDNSlocal int mDNSPlatformGetSocktFd(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType) { - if (src) + if (transType == mDNSTransport_UDP) + { + UDPSocket* sock = (UDPSocket*) sockCxt; + return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6; + } + else if (transType == mDNSTransport_TCP) { - int s; - char unenc_name[MAX_ESCAPED_DOMAIN_NAME]; - ConvertDomainNameToCString(&q->qname, unenc_name); + TCPSocket* sock = (TCPSocket*) sockCxt; + return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6; + } + else + { + LogInfo("mDNSPlatformGetSocktFd: invalid transport %d", transType); + return kInvalidSocketRef; + } +} - if (dst->type == mDNSAddrType_IPv4) - s = src->ss.sktv4; - else - s = src->ss.sktv6; +mDNSexport void mDNSPlatformSetSocktOpt(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType, DNSQuestion *q) +{ + int sockfd; + char unenc_name[MAX_ESCAPED_DOMAIN_NAME]; - if (q->pid) - { - if (setsockopt(s, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1) - LogInfo("mDNSPlatformSetuDNSSocktOpt: Delegate PID failed %s for PID %d", strerror(errno), q->pid); - } - else - { - if (setsockopt(s, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1) - LogInfo("mDNSPlatformSetuDNSSocktOpt: Delegate UUID failed %s", strerror(errno)); - } - - // set the domain on the UDP socket - if (!(ne_session_set_socket_attributes(s, unenc_name, NULL))) - LogInfo("mDNSPlatformSetuDNSSocktOpt: ne_session_set_socket_attributes()-> setting domain failed for %s", unenc_name); + // verify passed-in arguments exist and that sockfd is valid + if (q == mDNSNULL || sockCxt == mDNSNULL || (sockfd = mDNSPlatformGetSocktFd(sockCxt, transType, addrType)) < 0) + return; -#if defined(SO_NOWAKEFROMSLEEP) - int nowake = 1; - if (setsockopt(s, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1) - LogInfo("mDNSPlatformSetuDNSSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno)); -#endif - - if (q->DenyOnCellInterface || q->DenyOnExpInterface) - { + if (q->pid) + { + if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1) + LogMsg("mDNSPlatformSetSocktOpt: Delegate PID failed %s for PID %d", strerror(errno), q->pid); + } + else + { + if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1) + LogMsg("mDNSPlatformSetSocktOpt: Delegate UUID failed %s", strerror(errno)); + } + + // set the domain on the socket + ConvertDomainNameToCString(&q->qname, unenc_name); + if (!(ne_session_set_socket_attributes(sockfd, unenc_name, NULL))) + LogInfo("mDNSPlatformSetSocktOpt: ne_session_set_socket_attributes()-> setting domain failed for %s", unenc_name); + + int nowake = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1) + LogInfo("mDNSPlatformSetSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno)); + + if ((q->flags & kDNSServiceFlagsDenyCellular) || (q->flags & kDNSServiceFlagsDenyExpensive)) + { #if defined(SO_RESTRICT_DENY_CELLULAR) - if (q->DenyOnCellInterface) - { - int restrictions = 0; - restrictions = SO_RESTRICT_DENY_CELLULAR; - if (setsockopt(s, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1) - LogInfo("mDNSPlatformSetuDNSSocktOpt: SO_RESTRICT_DENY_CELLULAR failed %s", strerror(errno)); - } + if (q->flags & kDNSServiceFlagsDenyCellular) + { + int restrictions = 0; + restrictions = SO_RESTRICT_DENY_CELLULAR; + if (setsockopt(sockfd, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1) + LogMsg("mDNSPlatformSetSocktOpt: SO_RESTRICT_DENY_CELLULAR failed %s", strerror(errno)); + } #endif #if defined(SO_RESTRICT_DENY_EXPENSIVE) - if (q->DenyOnExpInterface) - { - int restrictions = 0; - restrictions = SO_RESTRICT_DENY_EXPENSIVE; - if (setsockopt(s, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1) - LogInfo("mDNSPlatformSetuDNSSocktOpt: SO_RESTRICT_DENY_EXPENSIVE failed %s", strerror(errno)); - } + if (q->flags & kDNSServiceFlagsDenyExpensive) + { + int restrictions = 0; + restrictions = SO_RESTRICT_DENY_EXPENSIVE; + if (setsockopt(sockfd, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1) + LogMsg("mDNSPlatformSetSocktOpt: SO_RESTRICT_DENY_EXPENSIVE failed %s", strerror(errno)); + } #endif - } - } } @@ -1938,7 +2039,10 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu", s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow)); if (!mDNSAddressIsAllDNSLinkGroup(dst)) - if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr); + { + if (errno == EHOSTUNREACH) return(mStatus_HostUnreachErr); + if (errno == EHOSTDOWN || errno == ENETDOWN || errno == ENETUNREACH) return(mStatus_TransientErr); + } // Don't report EHOSTUNREACH in the first three minutes after boot // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>) // but this means that sometimes it starts before configd has finished setting up the multicast routing entries. @@ -1962,14 +2066,6 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms result = mStatus_UnknownErr; } -#ifdef IP_BOUND_IF - if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst)) - { - static const mDNSu32 ifindex = 0; - setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex)); - } -#endif - return(result); } @@ -2089,33 +2185,6 @@ mDNSlocal mDNSInterfaceID FindMyInterface(mDNS *const m, const mDNSAddr *addr) return(mDNSInterface_Any); } -// This is a stupid hack and we should get rid of it. -// The chance of there being a second unicast UDP packet already waiting in the kernel before we’ve -// finished processing the previous one is virtually nil, and will only happen by luck on very rare -// occasions when running on a machine with a fast network connection and a slow or busy processor. -// The idea that we’d rely for correctness on this random chance event occurring is ridiculous. -// -- SC -mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src) -{ - // We should have a DNSMessage header followed by the question and an answer - // which also includes a CNAME (that's when this function is called). To keep it - // simple, we expect at least the size of DNSMessage header(12) and size of "A" - // record (14 bytes). - char buffer[26]; - int ret; - - (void) m; - - if (!src) - return mDNSfalse; - - ret = recv(src->ss.sktv4, buffer, sizeof(buffer), MSG_PEEK); - if (ret > 0) - return mDNStrue; - else - return mDNSfalse; -} - mDNSexport void myKQSocketCallBack(int s1, short filter, void *context) { KQSocketSet *const ss = (KQSocketSet *)context; @@ -2133,7 +2202,7 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context) while (!closed) { - mDNSAddr senderAddr, destAddr; + mDNSAddr senderAddr, destAddr = zeroAddr; mDNSIPPort senderPort; struct sockaddr_storage from; size_t fromlen = sizeof(from); @@ -2680,16 +2749,16 @@ mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort addr.sin_family = AF_INET; addr.sin_port = port->NotAnInteger; err = bind(skt, (struct sockaddr*) &addr, sizeof(addr)); - if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); return err; } + if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); close(skt); return err; } // Receive interface identifiers err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)); - if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); return err; } + if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); close(skt); return err; } mDNSPlatformMemZero(&addr, sizeof(addr)); socklen_t len = sizeof(addr); err = getsockname(skt, (struct sockaddr*) &addr, &len); - if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); return err; } + if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); close(skt); return err; } port->NotAnInteger = addr.sin_port; } @@ -2701,16 +2770,16 @@ mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort addr6.sin6_family = AF_INET6; addr6.sin6_port = port->NotAnInteger; err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6)); - if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); return err; } + if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); close(skt); return err; } // We want to receive destination addresses and receive interface identifiers err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); - if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); return err; } + if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); close(skt); return err; } mDNSPlatformMemZero(&addr6, sizeof(addr6)); socklen_t len = sizeof(addr6); err = getsockname(skt, (struct sockaddr *) &addr6, &len); - if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); return err; } + if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); close(skt); return err; } port->NotAnInteger = addr6.sin6_port; @@ -3106,6 +3175,14 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; } } + // Don't want to wake from sleep for inbound packets on the mDNS sockets + if (mDNSSameIPPort(port, MulticastDNSPort)) + { + int nowake = 1; + if (setsockopt(skt, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1) + LogInfo("SetupSocket: SO_NOWAKEFROMSLEEP failed %s", strerror(errno)); + } + if (sa_family == AF_INET) { // We want to receive destination addresses @@ -3140,7 +3217,7 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa else if (sa_family == AF_INET6) { // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error - if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort;return mStatus_NoError; } + if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; close(skt); return mStatus_NoError; } // We want to receive destination addresses and receive interface identifiers err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); @@ -3329,7 +3406,7 @@ mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i) // Note: MUST NOT close() the underlying native BSD sockets. // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them. - CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode); + CFRunLoopRemoveSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode); CFRelease(i->BPF_rls); CFSocketInvalidate(i->BPF_cfs); CFRelease(i->BPF_cfs); @@ -3407,34 +3484,374 @@ mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIP mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win); } -mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void) +mDNSexport mStatus mDNSPlatformClearSPSData(void) { - CFStringRef entityname = NULL; + CFStringRef spsAddress = NULL; + CFStringRef ownerOPTRec = NULL; - if ((entityname = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyAddress"))) + if ((spsAddress = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyAddress"))) { - if (SCDynamicStoreRemoveValue(NULL, entityname) == false) - LogSPS("mDNSPlatformClearSPSMACAddr: Unable to remove key"); + if (SCDynamicStoreRemoveValue(NULL, spsAddress) == false) + LogSPS("mDNSPlatformClearSPSData: Unable to remove sleep proxy address key"); } - if (entityname) - CFRelease(entityname); + if((ownerOPTRec = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyOPTRecord"))) + { + if (SCDynamicStoreRemoveValue(NULL, ownerOPTRec) == false) + LogSPS("mDNSPlatformClearSPSData: Unable to remove sleep proxy owner option record key"); + } + + if (spsAddress) CFRelease(spsAddress); + if (ownerOPTRec) CFRelease(ownerOPTRec); return KERN_SUCCESS; } +mDNSlocal int getMACAddress(int family, v6addr_t raddr, v6addr_t gaddr, int *gfamily, ethaddr_t eth) +{ + struct + { + struct rt_msghdr m_rtm; + char m_space[512]; + } m_rtmsg; + + struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); + char *cp = m_rtmsg.m_space; + int seq = 6367, sock, rlen, i; + struct sockaddr_in *sin = NULL; + struct sockaddr_in6 *sin6 = NULL; + struct sockaddr_dl *sdl = NULL; + struct sockaddr_storage sins; + struct sockaddr_dl sdl_m; + +#define NEXTADDR(w, s, len) \ +if (rtm->rtm_addrs & (w)) \ +{ \ +bcopy((char *)s, cp, len); \ +cp += len; \ +} + + bzero(&sins, sizeof(struct sockaddr_storage)); + bzero(&sdl_m, sizeof(struct sockaddr_dl)); + bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); + + sock = socket(PF_ROUTE, SOCK_RAW, 0); + if (sock < 0) + { + LogMsg("getMACAddress: Can not open the socket - %s", strerror(errno)); + return errno; + } + + rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY; + rtm->rtm_type = RTM_GET; + rtm->rtm_flags = 0; + rtm->rtm_version = RTM_VERSION; + rtm->rtm_seq = ++seq; + + sdl_m.sdl_len = sizeof(sdl_m); + sdl_m.sdl_family = AF_LINK; + if (family == AF_INET) + { + sin = (struct sockaddr_in*)&sins; + sin->sin_family = AF_INET; + sin->sin_len = sizeof(struct sockaddr_in); + memcpy(&sin->sin_addr, raddr, sizeof(struct in_addr)); + NEXTADDR(RTA_DST, sin, sin->sin_len); + } + else if (family == AF_INET6) + { + sin6 = (struct sockaddr_in6 *)&sins; + sin6->sin6_len = sizeof(struct sockaddr_in6); + sin6->sin6_family = AF_INET6; + memcpy(&sin6->sin6_addr, raddr, sizeof(struct in6_addr)); + NEXTADDR(RTA_DST, sin6, sin6->sin6_len); + } + NEXTADDR(RTA_GATEWAY, &sdl_m, sdl_m.sdl_len); + rtm->rtm_msglen = rlen = cp - (char *)&m_rtmsg; + + if (write(sock, (char *)&m_rtmsg, rlen) < 0) + { + LogMsg("getMACAddress: writing to routing socket: %s", strerror(errno)); + close(sock); + return errno; + } + + do + { + rlen = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg)); + } + while (rlen > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid())); + + if (rlen < 0) + LogMsg("getMACAddress: Read from routing socket failed"); + + if (family == AF_INET) + { + sin = (struct sockaddr_in *) (rtm + 1); + sdl = (struct sockaddr_dl *) (sin->sin_len + (char *) sin); + } + else if (family == AF_INET6) + { + sin6 = (struct sockaddr_in6 *) (rtm +1); + sdl = (struct sockaddr_dl *) (sin6->sin6_len + (char *) sin6); + } + + if (!sdl) + { + LogMsg("getMACAddress: sdl is NULL for family %d", family); + close(sock); + return -1; + } + + // If the address is not on the local net, we get the IP address of the gateway. + // We would have to repeat the process to get the MAC address of the gateway + *gfamily = sdl->sdl_family; + if (sdl->sdl_family == AF_INET) + { + if (sin) + { + struct sockaddr_in *new_sin = (struct sockaddr_in *)(sin->sin_len +(char*) sin); + memcpy(gaddr, &new_sin->sin_addr, sizeof(struct in_addr)); + } + else + { + LogMsg("getMACAddress: sin is NULL"); + } + close(sock); + return -1; + } + else if (sdl->sdl_family == AF_INET6) + { + if (sin6) + { + struct sockaddr_in6 *new_sin6 = (struct sockaddr_in6 *)(sin6->sin6_len +(char*) sin6); + memcpy(gaddr, &new_sin6->sin6_addr, sizeof(struct in6_addr)); + } + else + { + LogMsg("getMACAddress: sin6 is NULL"); + } + close(sock); + return -1; + } + + unsigned char *ptr = (unsigned char *)LLADDR(sdl); + for (i = 0; i < ETHER_ADDR_LEN; i++) + (eth)[i] = *(ptr +i); + + close(sock); + + return KERN_SUCCESS; +} + +mDNSlocal int GetRemoteMacinternal(int family, v6addr_t raddr, ethaddr_t eth) +{ + int ret = 0; + v6addr_t gateway; + int gfamily = 0; + int count = 0; + + do + { + ret = getMACAddress(family, raddr, gateway, &gfamily, eth); + if (ret == -1) + { + memcpy(raddr, gateway, sizeof(family)); + family = gfamily; + count++; + } + } + while ((ret == -1) && (count < 5)); + return ret; +} + +mDNSlocal int StoreSPSMACAddressinternal(int family, v6addr_t spsaddr, const char *ifname) +{ + ethaddr_t eth; + char spsip[INET6_ADDRSTRLEN]; + int ret = 0; + CFStringRef sckey = NULL; + SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL, NULL); + SCDynamicStoreRef ipstore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL, NULL); + CFMutableDictionaryRef dict = NULL; + CFStringRef entityname = NULL; + CFDictionaryRef ipdict = NULL; + CFArrayRef addrs = NULL; + + if ((store == NULL) || (ipstore == NULL)) + { + LogMsg("StoreSPSMACAddressinternal: Unable to accesss SC Dynamic Store"); + ret = -1; + goto fin; + } + + // Get the MAC address of the Sleep Proxy Server + memset(eth, 0, sizeof(eth)); + ret = GetRemoteMacinternal(family, spsaddr, eth); + if (ret != 0) + { + LogMsg("StoreSPSMACAddressinternal: Failed to determine the MAC address"); + goto fin; + } + + // Create/Update the dynamic store entry for the specified interface + sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyAddress"); + dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!dict) + { + LogMsg("StoreSPSMACAddressinternal: SPSCreateDict() Could not create CFDictionary dict"); + ret = -1; + goto fin; + } + + CFStringRef macaddr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]); + CFDictionarySetValue(dict, CFSTR("MACAddress"), macaddr); + if (NULL != macaddr) + CFRelease(macaddr); + + if( NULL == inet_ntop(family, (void *)spsaddr, spsip, sizeof(spsip))) + { + LogMsg("StoreSPSMACAddressinternal: inet_ntop failed: %s", strerror(errno)); + ret = -1; + goto fin; + } + + CFStringRef ipaddr = CFStringCreateWithCString(NULL, spsip, kCFStringEncodingUTF8); + CFDictionarySetValue(dict, CFSTR("IPAddress"), ipaddr); + if (NULL != ipaddr) + CFRelease(ipaddr); + + // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup + if ((entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/IPv6"), ifname)) != NULL) + { + if ((ipdict = SCDynamicStoreCopyValue(ipstore, entityname)) != NULL) + { + if((addrs = CFDictionaryGetValue(ipdict, CFSTR("Addresses"))) != NULL) + { + addrs = CFRetain(addrs); + CFDictionarySetValue(dict, CFSTR("RegisteredAddresses"), addrs); + } + } + } + SCDynamicStoreSetValue(store, sckey, dict); + +fin: + if (store) CFRelease(store); + if (ipstore) CFRelease(ipstore); + if (sckey) CFRelease(sckey); + if (dict) CFRelease(dict); + if (ipdict) CFRelease(ipdict); + if (entityname) CFRelease(entityname); + if (addrs) CFRelease(addrs); + + return ret; +} + +mDNSlocal void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname) +{ + struct + { + v6addr_t saddr; + } addr; + int err = 0; + + mDNSPlatformMemCopy(addr.saddr, spsaddr, sizeof(v6addr_t)); + + err = StoreSPSMACAddressinternal(family, (uint8_t *)addr.saddr, ifname); + if (err != 0) + LogMsg("mDNSStoreSPSMACAddress : failed"); +} + mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname) { int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6; - LogSPS("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname); + + LogInfo("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname); mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname); + return KERN_SUCCESS; } + +mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage* msg, int length) +{ + int ret = 0; + CFStringRef sckey = NULL; + SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreOwnerOPTRecord"), NULL, NULL); + CFMutableDictionaryRef dict = NULL; + + if (store == NULL) + { + LogMsg("mDNSPlatformStoreOwnerOptRecord: Unable to accesss SC Dynamic Store"); + ret = -1; + goto fin; + } + + // Create/Update the dynamic store entry for the specified interface + sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyOPTRecord"); + dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!dict) + { + LogMsg("mDNSPlatformStoreOwnerOptRecord: Could not create CFDictionary dictionary to store OPT Record"); + ret =-1; + goto fin; + } + + CFDataRef optRec = NULL; + optRec = CFDataCreate(NULL, (const uint8_t *)msg, (CFIndex)length); + CFDictionarySetValue(dict, CFSTR("OwnerOPTRecord"), optRec); + if (NULL != optRec) CFRelease(optRec); + + SCDynamicStoreSetValue(store, sckey, dict); + +fin: + if (NULL != store) CFRelease(store); + if (NULL != sckey) CFRelease(sckey); + if (NULL != dict) CFRelease(dict); + return ret; +} + +mDNSlocal void mDNSGet_RemoteMAC(mDNS *const m, int family, v6addr_t raddr) +{ + ethaddr_t eth; + IPAddressMACMapping *addrMapping; + int kr = KERN_FAILURE; + struct + { + v6addr_t addr; + } dst; + + mDNSPlatformMemCopy(dst.addr, raddr, sizeof(v6addr_t)); + + kr = GetRemoteMacinternal(family, (uint8_t *)dst.addr, eth); + + // If the call to get the remote MAC address succeeds, allocate and copy + // the values and schedule a task to update the MAC address in the TCP Keepalive record. + if (kr == 0) + { + addrMapping = mDNSPlatformMemAllocate(sizeof(IPAddressMACMapping)); + snprintf(addrMapping->ethaddr, sizeof(addrMapping->ethaddr), "%02x:%02x:%02x:%02x:%02x:%02x", + eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]); + if (family == AF_INET) + { + addrMapping->ipaddr.type = mDNSAddrType_IPv4; + mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, raddr, sizeof(v6addr_t)); + } + else + { + addrMapping->ipaddr.type = mDNSAddrType_IPv6; + mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v6.b, raddr, sizeof(v6addr_t)); + } + UpdateRMAC(m, addrMapping); + } +} + mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr) { int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6; - - mDNSGetRemoteMAC(m, family, raddr->ip.v6.b); + + LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC"); + mDNSGet_RemoteMAC(m, family, raddr->ip.v6.b); + return KERN_SUCCESS; } @@ -3485,7 +3902,7 @@ mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID NetworkInterfaceInfoOSX *x; // 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; + for (x = m->p->InterfaceList; x; x = x->next) if ((x->ifinfo.InterfaceID == InterfaceID) && (x->BPF_fd >= 0)) break; if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; } @@ -3711,7 +4128,7 @@ mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd) i->BPF_fd = fd; i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext); i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0); - CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode); + CFRunLoopAddSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode); #endif mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID); } @@ -3999,8 +4416,8 @@ mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf) mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i) { - if (!MulticastInterface(i) ) return(mDNSfalse); // We only use Sleep Proxy Service on multicast-capable interfaces - if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse); // except loopback + // We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D. + if (!SPSInterface(i)) return(mDNSfalse); // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability @@ -4140,6 +4557,7 @@ exit: // Return true if the interface is associate to a CarPlay hosted SSID. mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name) { + static WiFiManagerClientRef manager = NULL; mDNSBool rvalue = mDNSfalse; if (!MobileWiFiLibLoad()) @@ -4148,10 +4566,15 @@ mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name) // If we have associated with a CarPlay hosted SSID, then use the same // optimizations that are used if an interface has the IFEF_DIRECTLINK flag set. - WiFiManagerClientRef manager; + // Get one WiFiManagerClientRef to use for all calls. + if (manager == NULL) + manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal); - manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal); - if (manager != NULL) + if (manager == NULL) + { + LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!"); + } + else { CFArrayRef devices; @@ -4174,7 +4597,6 @@ mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name) } CFRelease(devices); } - CFRelease(manager); } return rvalue; @@ -4263,6 +4685,8 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad i->ifinfo.Loopback = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse; i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue; + // Setting DirectLink indicates we can do the optimization of skipping the probe phase + // for the interface address records since they should be unique. if (eflags & IFEF_DIRECTLINK) i->ifinfo.DirectLink = mDNStrue; else @@ -4281,6 +4705,7 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad // Bonjour requests over the AWDL interface. i->ifinfo.SupportsUnicastMDNSResponse = mDNSfalse; AWDLInterfaceID = i->ifinfo.InterfaceID; + i->ifinfo.DirectLink = mDNStrue; LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID); } else @@ -4555,7 +4980,7 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut else if (llqStatus == mStatus_NoSuchRecord) { status = llqStatus; - mDNS_snprintf(buffer, sizeof(buffer), llqBuffer); + mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer); } else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT)) { @@ -4582,7 +5007,7 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut else { status = llqStatus; - mDNS_snprintf(buffer, sizeof(buffer), llqBuffer); + mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer); LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer); } @@ -4649,8 +5074,7 @@ mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we if (info != AnonymousRacoonConfig) { AnonymousRacoonConfig = info; - // Create or revert configuration file, and start (or SIGHUP) Racoon - (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, AnonymousRacoonConfig ? btmmprefix : mDNSNULL, AnonymousRacoonConfig ? &AnonymousRacoonConfig->domain : mDNSNULL); + LogInfo("UpdateAnonymousRacoonConfig need not be done in mDNSResponder"); } } @@ -5388,8 +5812,6 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q) p->q.ForceMCast = mDNSfalse; p->q.ReturnIntermed = mDNStrue; p->q.SuppressUnusable = mDNSfalse; - p->q.DenyOnCellInterface = mDNSfalse; - p->q.DenyOnExpInterface = mDNSfalse; p->q.SearchListIndex = 0; p->q.AppendSearchDomains = 0; p->q.RetryWithSearchDomains = mDNSfalse; @@ -5507,7 +5929,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6); } - if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY))) + if (!(ifru_flags6 & (IN6_IFF_TENTATIVE | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY))) { if (ifa->ifa_flags & IFF_LOOPBACK) { @@ -5634,6 +6056,9 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) { NetworkInterfaceInfoOSX *i; int count = 0; + + // Recalculate SuppressProbes time based on the current set of active interfaces. + m->SuppressProbes = 0; for (i = m->p->InterfaceList; i; i = i->next) if (i->Exists) { @@ -5687,8 +6112,8 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) if (!n->McastTxRx) { 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); -#if TARGET_OS_WATCH - // We join the Bonjour multicast group on the watch only when a client request is active, +#if TARGET_OS_EMBEDDED + // We join the Bonjour multicast group on Apple embedded platforms ONLY when a client request is active, // so we leave the multicast group here to clear any residual group membership. if (i->sa_family == AF_INET) { @@ -5719,7 +6144,7 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); } } -#endif // TARGET_OS_WATCH +#endif // TARGET_OS_EMBEDDED } else { @@ -5963,21 +6388,38 @@ mDNSexport const char *DNSScopeToString(mDNSu32 scope) } } -mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNSInterfaceID interface, mDNSu32 scope, MD5_CTX *sdc) +mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNSInterfaceID interfaceId, mDNSu32 scope, MD5_CTX *sdc, uint64_t generation) { const char *scopeString = DNSScopeToString(scope); int j; + domainname d; + + if (scope == kScopeNone) + interfaceId = mDNSInterface_Any; - if (scope != kScopeNone) + if (scope == kScopeNone || scope == kScopeInterfaceID) { - LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for Interface %p", scopeString, interface); - return; + for (j = 0; j < resolver->n_search; j++) + { + if (MakeDomainNameFromDNSNameString(&d, resolver->search[j]) != NULL) + { + static char interface_buf[32]; + mDNS_snprintf(interface_buf, sizeof(interface_buf), "for interface %s", InterfaceNameForID(m, interfaceId)); + LogInfo("ConfigSearchDomains: (%s) configuring search domain %s %s (generation= %llu)", scopeString, + resolver->search[j], (interfaceId == mDNSInterface_Any) ? "" : interface_buf, generation); + UpdateSearchDomainHash(m, sdc, resolver->search[j], interfaceId); + mDNS_AddSearchDomain_CString(resolver->search[j], interfaceId); + } + else + { + LogInfo("ConfigSearchDomains: An invalid search domain was detected for %s domain %s n_nameserver %d, (generation= %llu)", + DNSScopeToString(scope), resolver->domain, resolver->n_nameserver, generation); + } + } } - for (j = 0; j < resolver->n_search; j++) + else { - LogInfo("ConfigSearchDomains: (%s) configuring search list %s", scopeString, resolver->search[j]); - UpdateSearchDomainHash(m, sdc, resolver->search[j], NULL); - mDNS_AddSearchDomain_CString(resolver->search[j], NULL); + LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString, InterfaceNameForID(m,interfaceId)); } } @@ -6140,7 +6582,8 @@ mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSu32 scop if (setsearch) { - ConfigSearchDomains(m, resolver[i], interface, scope, sdc); + ConfigSearchDomains(m, resolver[i], interface, scope, sdc, config->generation); + // Parse other scoped resolvers for search lists if (!setservers) continue; @@ -6522,9 +6965,8 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, } else { - LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu", config->n_resolver, config->generation); - // SameDomainName check below is to fix <rdar://problem/18059009> Dynamic DNS hostname changes not noticed - if (m->p->LastConfigGeneration == config->generation && (!fqdn || (SameDomainName(fqdn, &m->FQDN)))) + LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config->n_resolver, config->generation, m->p->LastConfigGeneration); + if (m->p->LastConfigGeneration == config->generation) { LogInfo("mDNSPlatformSetDNSConfig: generation number %llu same, not processing", config->generation); dns_configuration_free(config); @@ -6855,7 +7297,7 @@ mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m) else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect"); } } -#else +#elif !TARGET_OS_EMBEDDED mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m) { (void) m; // Unused @@ -6863,12 +7305,14 @@ mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m) } #endif // ! NO_AWACS +#if !TARGET_OS_EMBEDDED mDNSlocal void ProcessConndConfigChanges(mDNS *const m); +#endif #endif // APPLE_OSX_mDNSResponder // MUST be called holding the lock -mDNSexport void SetDomainSecrets(mDNS *m) +mDNSlocal void SetDomainSecrets_internal(mDNS *m) { #ifdef NO_SECURITYFRAMEWORK (void) m; @@ -7134,6 +7578,15 @@ mDNSexport void SetDomainSecrets(mDNS *m) #endif /* NO_SECURITYFRAMEWORK */ } +mDNSexport void SetDomainSecrets(mDNS *m) +{ +#if DEBUG + // Don't get secrets for BTMM if running in debug mode + if (!IsDebugSocketInUse()) +#endif + SetDomainSecrets_internal(m); +} + mDNSlocal void SetLocalDomains(void) { CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); @@ -7303,6 +7756,7 @@ mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const Resou CFRelease(ifname); } +#if !TARGET_OS_EMBEDDED mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void) { mDNSs32 val = -1; @@ -7365,6 +7819,7 @@ mDNSlocal void SetSPS(mDNS *const m) mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures); } +#endif // !TARGET_OS_EMBEDDED // The definitions below should eventually come from some externally-supplied header file. // However, since these definitions can't really be changed without breaking binary compatibility, @@ -7396,14 +7851,28 @@ typedef struct mDNSlocal mDNSu16 GetPortArray(mDNS *const m, int trans, mDNSIPPort *portarray) { const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp"; - int count = 0; + int count = 0; + AuthRecord *rr; for (rr = m->ResourceRecords; rr; rr=rr->next) + { if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c)) { - if (portarray) portarray[count] = rr->resrec.rdata->u.srv.port; - count++; + if (!portarray) + count++; + else + { + int i; + for (i = 0; i < count; i++) + if (mDNSSameIPPort(portarray[i], rr->resrec.rdata->u.srv.port)) + break; + + // Add it into the port list only if it not already present in the list + if (i >= count) + portarray[count++] = rr->resrec.rdata->u.srv.port; + } } + } // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500) if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext) @@ -7546,7 +8015,7 @@ mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf) { if(!UseInternalSleepProxy) { - LogSPS("SupportsInNICProxy: Internal Sleep Proxy is disabled"); + LogMsg("SupportsInNICProxy: Internal Sleep Proxy is disabled"); return mDNSfalse; } return CheckInterfaceSupport(intf, mDNS_IOREG_KEY); @@ -7607,10 +8076,10 @@ mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const cmd.numRRRecords = CountProxyRecords(m, &cmd.rrBufferSize, intf, TCPKAOnly, supportsTCPKA); cmd.compression = sizeof(DNSMessageHeader); - DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize); - cmd.rrRecords.ptr = mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr)); - cmd.udpPorts.ptr = mallocL("mDNSOffloadCmd udpPorts", cmd.numUDPPorts * sizeof(mDNSIPPort)); - cmd.tcpPorts.ptr = mallocL("mDNSOffloadCmd tcpPorts", cmd.numTCPPorts * sizeof(mDNSIPPort)); + DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize); + cmd.rrRecords.ptr = cmd.numRRRecords ? mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr)) : NULL; + cmd.udpPorts.ptr = cmd.numUDPPorts ? mallocL("mDNSOffloadCmd udpPorts" , cmd.numUDPPorts * sizeof(mDNSIPPort)) : NULL; + cmd.tcpPorts.ptr = cmd.numTCPPorts ? mallocL("mDNSOffloadCmd tcpPorts" , cmd.numTCPPorts * sizeof(mDNSIPPort)) : NULL; LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d", msg, cmd.rrBufferSize, @@ -7618,23 +8087,15 @@ mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const cmd.udpPorts.ptr, cmd.numUDPPorts, cmd.tcpPorts.ptr, cmd.numTCPPorts); - if (!msg || !cmd.rrRecords.ptr || !cmd.udpPorts.ptr || !cmd.tcpPorts.ptr) - LogMsg("ActivateLocalProxy: Failed to allocate memory: msg %p %d RR %p %d, UDP %p %d, TCP %p %d", - msg, cmd.rrBufferSize, - cmd.rrRecords.ptr, cmd.numRRRecords, - cmd.udpPorts.ptr, cmd.numUDPPorts, - cmd.tcpPorts.ptr, cmd.numTCPPorts); - else - { - GetProxyRecords(m, msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA); - GetPortArray(m, mDNSTransport_UDP, cmd.udpPorts.ptr); - GetPortArray(m, mDNSTransport_TCP, cmd.tcpPorts.ptr); - char outputData[2]; - size_t outputDataSize = sizeof(outputData); - kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize); - LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr); - if (kr == KERN_SUCCESS) result = mStatus_NoError; - } + if (msg && cmd.rrRecords.ptr) GetProxyRecords(m, msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA); + if (cmd.udpPorts.ptr) cmd.numUDPPorts = GetPortArray(m, mDNSTransport_UDP, cmd.udpPorts.ptr); + if (cmd.tcpPorts.ptr) cmd.numTCPPorts = GetPortArray(m, mDNSTransport_TCP, cmd.tcpPorts.ptr); + + char outputData[2]; + size_t outputDataSize = sizeof(outputData); + kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize); + LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr); + if (kr == KERN_SUCCESS) result = mStatus_NoError; if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts.ptr); if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts.ptr); @@ -7683,10 +8144,15 @@ mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void) mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void) { mDNSs32 val = 0; - GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val); + // PrioritizeNetworkReachabilityOverSleep has been deprecated. + // GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val); + // Statically set the PrioritizeNetworkReachabilityOverSleep value to 1 for AppleTV + if (IsAppleTV()) + val = 1; return val != 0 ? mDNStrue : mDNSfalse; } + #if APPLE_OSX_mDNSResponder // When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay) // gets deregistered, so that older peers are forced to connect over direct UDP instead of @@ -7744,6 +8210,7 @@ mDNSexport void RemoveAutoTunnel6Record(mDNS *const m) UpdateAutoTunnel6Record(m, info); } +#if !TARGET_OS_EMBEDDED mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname) { struct ifaddrs *ifa; @@ -7978,6 +8445,7 @@ mDNSlocal void ProcessConndConfigChanges(mDNS *const m) // If awacsd crashes or exits for some reason, restart it UpdateBTMMRelayConnection(m); } +#endif // !TARGET_OS_EMBEDDED #endif /* APPLE_OSX_mDNSResponder */ mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m) @@ -8027,11 +8495,11 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m) m->NetworkChanged ? "" : " (no scheduled configuration change)"); m->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it - // If we have any NOTREADY IPv6 addresses, wait until they've finished configuring + // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0); if (InfoSocket > 0) { - mDNSBool notready = mDNSfalse; + mDNSBool tentative = mDNSfalse; struct ifaddrs *ifa = myGetIfAddrs(1); while (ifa) { @@ -8046,25 +8514,29 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m) // We can expect that an IN6_IFF_TENTATIVE address will shortly become ready, // but an IN6_IFF_DUPLICATED address may not. if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1) + { if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE) { LogInfo("*** Network Configuration Change *** IPv6 address %.16a TENTATIVE, will retry", &ifr6.ifr_addr.sin6_addr); - notready = mDNStrue; + tentative = mDNStrue; + // no need to check other interfaces if we already found out that one interface is TENTATIVE + break; } + } } ifa = ifa->ifa_next; } close(InfoSocket); - if (notready) + if (tentative) { mDNS_Lock(m); SetNetworkChanged(m, mDNSPlatformOneSecond / 2); mDNS_Unlock(m); return; } - LogInfo("*** Network Configuration Change *** No IPv6 address NOTREADY, will continue"); + LogInfo("*** Network Configuration Change *** No IPv6 address TENTATIVE, will continue"); } - + mDNSs32 utc = mDNSPlatformUTC(); m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess(); m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN(); @@ -8073,7 +8545,7 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m) ClearInactiveInterfaces(m, utc); SetupActiveInterfaces(m, utc); -#if APPLE_OSX_mDNSResponder +#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED mDNS_Lock(m); ProcessConndConfigChanges(m); @@ -8129,14 +8601,19 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m) NetworkInterfaceInfoOSX *i; for (i = m->p->InterfaceList; i; i = i->next) { - if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds + if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds { - if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) CloseBPF(i); + if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) + CloseBPF(i); } - else // else, we're Sleep Proxy Server; open BPF fds + else // else, we're Sleep Proxy Server; open BPF fds { - if (i->Exists && i->Registered == i && i->ifinfo.McastTxRx && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1) - { LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); } + if (i->Exists && (i->Registered == i) && SPSInterface(i) && i->BPF_fd == -1) + { + LogMsg("%s mDNSMacOSXNetworkChanged: requesting BPF", i->ifinfo.ifname); + i->BPF_fd = -2; + mDNSRequestBPF(); + } } } @@ -8411,6 +8888,8 @@ mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info) mDNS *const m = (mDNS *const)info; (void)store; + KQueueLock(m); // serialize with KQueueLoop() + LogInfo("DynamicStoreReconnected: Reconnected"); // State:/Network/MulticastDNS @@ -8429,15 +8908,14 @@ mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info) mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray); #if APPLE_OSX_mDNSResponder - mDNS_Lock(m); // State:/Network/BackToMyMac UpdateAutoTunnelDomainStatuses(m); - mDNS_Unlock(m); // State:/Network/Interface/en0/SleepProxyServers if (spsStatusDict) CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL); #endif + KQueueUnlock(m, "DynamicStoreReconnected"); } mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m) @@ -8474,7 +8952,7 @@ mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m) #else m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0); if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; } - CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode); + CFRunLoopAddSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode); #endif SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected); m->p->Store = store; @@ -8521,7 +8999,7 @@ mDNSlocal void mDNSSetPacketFilterRules(mDNS *const m, char * ifname, const Reso continue; } - LogInfo("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr)); + LogMsg("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr)); portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger; @@ -8529,13 +9007,21 @@ mDNSlocal void mDNSSetPacketFilterRules(mDNS *const m, char * ifname, const Reso p = rr->resrec.name->c; // Skip to App Protocol - if (p[0]) p += 1 + p[0]; + if (p[0]) + p += 1 + p[0]; // Skip to Transport Protocol - if (p[0]) p += 1 + p[0]; + if (p[0]) + p += 1 + p[0]; - if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) protocolArray[count] = IPPROTO_TCP; - else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) protocolArray[count] = IPPROTO_UDP; + if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) + { + protocolArray[count] = IPPROTO_TCP; + } + else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) + { + protocolArray[count] = IPPROTO_UDP; + } else { LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service"); @@ -8651,12 +9137,8 @@ mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op) return mDNStrue; } -// mDNS_Reconfirm_internal() adds 33% to this interval, so the records should -// be removed in 4 seconds. -#define kAWDLReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 3) - // Mark records from this peer for deletion from the cache. -mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr *ap) +mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr *ap, bool purgeNow) { mDNSu32 slot; CacheGroup *cg; @@ -8680,7 +9162,11 @@ mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr { LogInfo("removeCachedPeerRecords: %s %##s marking for deletion", DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c); - mDNS_Reconfirm_internal(m, cr, kAWDLReconfirmTime); + + if (purgeNow) + mDNS_PurgeCacheResourceRecord(m, cr); + else + mDNS_Reconfirm_internal(m, cr, 0); // use default minimum reconfirm time } } } @@ -8705,8 +9191,8 @@ mDNSlocal void nodePresence(mDNS *const m, struct kev_dl_node_presence * p) peerAddr.type = mDNSAddrType_IPv6; peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr; - LogInfo("nodePresence: ssth is all zeroes, delete cached records from this peer"); - removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr); + LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer"); + removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr, false); } } @@ -8724,8 +9210,8 @@ mDNSlocal void nodeAbsence(mDNS *const m, struct kev_dl_node_absence * p) peerAddr.type = mDNSAddrType_IPv6; peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr; - LogInfo("nodeAbsence: delete cached records from this peer"); - removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr); + LogInfo("nodeAbsence: immediately purge cached records from this peer"); + removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr, true); } mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context) @@ -8922,25 +9408,20 @@ mDNSlocal void PowerOn(mDNS *const m) { mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake; - // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities. - // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc. - // We will clear this assertion as soon as we think the mainenance activities are done. - mDNSPlatformPreventSleep(m, DARK_WAKE_TIME, "mDNSResponder:maintenance"); - if (m->p->WakeAtUTC) { long utc = mDNSPlatformUTC(); mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake if (m->p->WakeAtUTC - utc > 30) - { + { LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc); } - else if (utc - m->p->WakeAtUTC > 30) + else if (utc - m->p->WakeAtUTC > 30) { LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC); } else if (IsAppleTV()) - { + { LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC); } else @@ -8949,6 +9430,12 @@ mDNSlocal void PowerOn(mDNS *const m) m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond; } } + + // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities. + // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc. + // We will clear this assertion as soon as we think the mainenance activities are done. + mDNSPlatformPreventSleep(m, DARK_WAKE_TIME, "mDNSResponder:maintenance"); + } mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument) @@ -8969,7 +9456,7 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m); break; case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260 - case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270 + case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep"); break; // E0000270 case kIOMessageSystemWillSleep: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280 mDNSCoreMachineSleep(m, true); break; @@ -9004,8 +9491,11 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag default: LogSPS("PowerChanged unknown message %X", messageType); break; } - if (messageType == kIOMessageSystemWillSleep) m->p->SleepCookie = (long)messageArgument; - else IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument); + if ((messageType == kIOMessageSystemWillSleep) || (messageType== kIOMessageCanSystemSleep)) + { + m->p->SleepCookie = (long)messageArgument; + IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument); + } KQueueUnlock(m, "PowerChanged Sleep/Wake"); } @@ -9329,93 +9819,77 @@ mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost". // When we parse again below, EtchHostsParseOneName would return -1 and we will end up // doing the right thing. + if (!MakeDomainNameFromDNSNameString(&first, name1)) { LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1); freeaddrinfo(gairesults); return; } + mDNSMacOSXCreateEtcHostsEntry(m, &first, gairesults->ai_addr, mDNSNULL, ifname, auth); + + // /etc/hosts alias discussion: + // // If the /etc/hosts has an entry like this // - // 1.2.3.4 sun star bright + // ip_address cname [aliases...] + // 1.2.3.4 sun star bright // // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun") // // To achieve this, we need to add the entry like this: // - // star CNAME bright - // bright CNAME sun // sun A 1.2.3.4 + // star CNAME sun + // bright CNAME sun // - // We store the first name we parsed in "first". Then we parse additional names adding CNAME records - // till we reach the end. When we reach the end, we wrap around and add one final CNAME with the last - // entry and the first entry. Finally, we add the Address (A/AAAA) record. + // We store the first name we parsed in "first" and add the address (A/AAAA) record. + // Then we parse additional names adding CNAME records till we reach the end. + aliasIndex = 0; - while (i <= length) + while (i < length) { - // Parse a name. If there are no names, we need to know whether we - // parsed CNAMEs before or not. If we parsed CNAMEs before, then we - // add a CNAME with the last name and the first name. Otherwise, this - // is same as the common case above where the line has just one name - // but with trailing white spaces. + // Continue to parse additional aliases until we reach end of the line and + // for each "alias" parsed, add a CNAME record where "alias" points to the first "name". + // See also /etc/hosts alias discussion above + i = EtcHostsParseOneName(i + 1, length, buffer, &name2); + if (name2) { + if ((aliasIndex) && (*buffer == *name2)) + break; // break out of the loop if we wrap around + if (!MakeDomainNameFromDNSNameString(&name2d, name2)) { LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2); freeaddrinfo(gairesults); return; } - aliasIndex++; - } - else if (!aliasIndex) - { - // We have never parsed any aliases. This case happens if there - // is just one name and some extra white spaces at the end. - LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c); - break; - } - else - { - // We have parsed at least one alias before and we reached the end of the line. - // Setup a CNAME for the last name with "first" name as its RDATA - name2d.c[0] = 0; - AssignDomainName(&name2d, &first); - } - - // Don't add a CNAME for the first alias we parse (see the example above). - // As we parse more, we might discover that there are no more aliases, in - // which case we would have set "name2d" to "first" above. We need to add - // the CNAME in that case. - - if (aliasIndex > 1 || SameDomainName(&name2d, &first)) - { // Ignore if it points to itself - if (!SameDomainName(&name1d, &name2d)) + if (!SameDomainName(&first, &name2d)) { - if (!mDNSMacOSXCreateEtcHostsEntry(m, &name1d, mDNSNULL, &name2d, ifname, auth)) + if (!mDNSMacOSXCreateEtcHostsEntry(m, &name2d, mDNSNULL, &first, ifname, auth)) { freeaddrinfo(gairesults); return; } } else - LogMsg("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names name1 %##s, name2 %##s", name1d.c, name2d.c); + { + LogInfo("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names first %##s, name2 %##s", first.c, name2d.c); + } + aliasIndex++; + } + else if (!aliasIndex) + { + // We have never parsed any aliases. This case happens if there + // is just one name and some extra white spaces at the end. + LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c); + break; } - - // If we have already wrapped around, we just need to add the A/AAAA record alone - // which is done below - if (SameDomainName(&name2d, &first)) break; - - // Remember the current name so that we can set the CNAME record if we parse one - // more name - name1d.c[0] = 0; - AssignDomainName(&name1d, &name2d); } - // Added all the CNAMEs if any, add the "A/AAAA" record - mDNSMacOSXCreateEtcHostsEntry(m, &first, gairesults->ai_addr, mDNSNULL, ifname, auth); } freeaddrinfo(gairesults); } @@ -9813,9 +10287,9 @@ mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m) if (!EtcHostsDeleteOldEntries(m, &newhosts, mDNStrue)) { LogInfo("mDNSMacOSXUpdateEtcHosts: No work"); + FreeNewHosts(&newhosts); mDNS_Unlock(m); KQueueUnlock(m, "/etc/hosts changed"); - FreeNewHosts(&newhosts); return; } } @@ -9838,10 +10312,9 @@ mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m) // is called back where we do the Registration of the record. This results in RMV followed by ADD which // looks normal. mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts); + FreeNewHosts(&newhosts); mDNS_Unlock(m); - KQueueUnlock(m, "/etc/hosts changed"); - FreeNewHosts(&newhosts); } #if COMPILER_LIKES_PRAGMA_MARK @@ -9988,7 +10461,6 @@ mDNSlocal void SetupLocalHostRecords(mDNS *const m) mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) { mStatus err; - m->p->CFRunLoop = CFRunLoopGetCurrent(); char HINFO_SWstring[256] = ""; mDNSMacOSXSystemBuildNumber(HINFO_SWstring); @@ -9997,13 +10469,6 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) if (err) return err; - DynamicStoreQueue = dispatch_queue_create("com.apple.mDNSResponder.DynamicStoreQueue", NULL); - if (DynamicStoreQueue == NULL) - { - LogMsg("dispatch_queue_create: DynamicStoreQueue NULL!"); - return mStatus_NoMemoryErr; - } - // Store mDNSResponder Platform if (OSXVers) { @@ -10170,7 +10635,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue()); LogInfo("IOPMConnectionSetDispatchQueue is now running"); #else - iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetMain(), kCFRunLoopDefaultMode); if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr); LogInfo("IOPMConnectionScheduleWithRunLoop is now running"); #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */ @@ -10187,7 +10652,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue()); #else - CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode); + CFRunLoopAddSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode); #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */ } } @@ -10252,7 +10717,7 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m) // We only initialize if mDNSCore successfully initialized. if (D2DInitialize) { - D2DStatus ds = D2DInitialize(m->p->CFRunLoop, xD2DServiceCallback, m) ; + D2DStatus ds = D2DInitialize(CFRunLoopGetMain(), xD2DServiceCallback, m) ; if (ds != kD2DSuccess) LogMsg("D2DInitialiize failed: %d", ds); else @@ -10272,7 +10737,7 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL); #else - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode); + CFRunLoopRemoveSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode); #endif // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call // to IORegisterForSystemPower creates *three* objects that need to be disposed individually: @@ -10288,7 +10753,7 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL)) LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed"); #else - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode); + CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode); CFRunLoopSourceInvalidate(m->p->StoreRLS); CFRelease(m->p->StoreRLS); m->p->StoreRLS = NULL; @@ -10299,7 +10764,7 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) if (m->p->PMRLS) { - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode); + CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->PMRLS, kCFRunLoopDefaultMode); CFRunLoopSourceInvalidate(m->p->PMRLS); CFRelease(m->p->PMRLS); m->p->PMRLS = NULL; @@ -10338,8 +10803,7 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) if (AnonymousRacoonConfig) { AnonymousRacoonConfig = mDNSNULL; - LogInfo("mDNSPlatformClose: Deconfiguring autotunnel"); - (void)mDNSConfigureServer(kmDNSDown, mDNSNULL, mDNSNULL); + LogInfo("mDNSPlatformClose: Deconfiguring autotunnel need not be done in mDNSResponder"); } #endif // APPLE_OSX_mDNSResponder } @@ -10416,8 +10880,9 @@ mDNSexport mDNSs32 mDNSPlatformUTC(void) // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; } mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; } -mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); } -mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); } +mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (const char *)src); } +mDNSexport mDNSu32 mDNSPlatformStrLCopy( void *dst, const void *src, mDNSu32 dstlen) { return (strlcpy((char *)dst, (const char *)src, dstlen)); } +mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((const char*)src)); } mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); } mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); } mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); } @@ -10513,6 +10978,11 @@ mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID) if (InterfaceID == mDNSInterface_P2P) return mDNStrue; + // mDNSInterface_BLE not considered a D2D interface for the purpose of this + // routine, since it's not implemented via a D2D plugin. + if (InterfaceID == mDNSInterface_BLE) + return mDNSfalse; + if ( (InterfaceID == mDNSInterface_Any) || (InterfaceID == mDNSInterfaceMark) || (InterfaceID == mDNSInterface_LocalOnly) @@ -10536,18 +11006,18 @@ mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID) // Filter records send over P2P (D2D) type interfaces // Note that the terms P2P and D2D are used synonymously in the current code and comments. -mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf) +mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID) { // For an explicit match to a valid interface ID, return true. - if (rr->resrec.InterfaceID == intf->InterfaceID) + if (rr->resrec.InterfaceID == InterfaceID) return mDNStrue; // Only filtering records for D2D type interfaces, return true for all other interface types. - if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID)) + if (!mDNSPlatformInterfaceIsD2D(InterfaceID)) return mDNStrue; // If it's an AWDL interface the record must be explicitly marked to include AWDL. - if (intf->InterfaceID == AWDLInterfaceID) + if (InterfaceID == AWDLInterfaceID) { if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P) return mDNStrue; @@ -10600,11 +11070,7 @@ mDNSexport mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *c return mDNStrue; if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL)) - { - LogInfo("mDNSPlatformValidRecordForQuestion: Record recieved over AWDL not returned for %s %##s query", - DNSTypeName(q->qtype), q->qname.c); return mDNSfalse; - } return mDNStrue; } |