From e9410223a0ed22fd5356221cb6647607b80a57db Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 28 May 2020 16:02:55 +0000 Subject: [PATCH] mDNSResponder-1096.40.7.tar.gz --- Clients/dnssdutil/dnssdutil.c | 8 +- Makefile | 2 +- mDNSCore/DNSCommon.c | 2 +- mDNSCore/mDNS.c | 136 ++++-- mDNSCore/mDNSEmbeddedAPI.h | 9 +- mDNSMacOSX/ApplePlatformFeatures.h | 15 + .../Tests/BATS Scripts/bats_test_proxy.sh | 2 +- .../Tests/{ => Unit Tests}/CNameRecordTest.m | 26 +- mDNSMacOSX/Tests/Unit Tests/CacheOrderTest.m | 282 +++++++++++ .../Tests/{ => Unit Tests}/DNSMessageTest.m | 0 .../{ => Unit Tests}/HelperFunctionTest.m | 0 mDNSMacOSX/Tests/{ => Unit Tests}/Info.plist | 0 .../{ => Unit Tests}/LocalOnlyTimeoutTest.m | 0 .../Unit Tests/LocalOnlyWithInterfacesTest.m | 399 +++++++++++++++ .../{ => Unit Tests}/ResourceRecordTest.m | 0 .../Tests/Unit Tests/SuspiciousReplyTest.m | 242 +++++++++ .../{ => Unit Tests}/mDNSCoreReceiveTest.m | 1 - mDNSMacOSX/Tests/mDNSResponder.plist | 459 ++++++++++++++++++ mDNSMacOSX/mDNSMacOSX.c | 14 +- .../mDNSResponder.xcodeproj/project.pbxproj | 40 +- mDNSShared/dns_sd.h | 2 +- mDNSShared/uds_daemon.c | 7 +- unittests/unittest_common.c | 86 +++- unittests/unittest_common.h | 4 + 24 files changed, 1663 insertions(+), 73 deletions(-) rename mDNSMacOSX/Tests/{ => Unit Tests}/CNameRecordTest.m (96%) create mode 100644 mDNSMacOSX/Tests/Unit Tests/CacheOrderTest.m rename mDNSMacOSX/Tests/{ => Unit Tests}/DNSMessageTest.m (100%) rename mDNSMacOSX/Tests/{ => Unit Tests}/HelperFunctionTest.m (100%) rename mDNSMacOSX/Tests/{ => Unit Tests}/Info.plist (100%) rename mDNSMacOSX/Tests/{ => Unit Tests}/LocalOnlyTimeoutTest.m (100%) create mode 100644 mDNSMacOSX/Tests/Unit Tests/LocalOnlyWithInterfacesTest.m rename mDNSMacOSX/Tests/{ => Unit Tests}/ResourceRecordTest.m (100%) create mode 100644 mDNSMacOSX/Tests/Unit Tests/SuspiciousReplyTest.m rename mDNSMacOSX/Tests/{ => Unit Tests}/mDNSCoreReceiveTest.m (99%) diff --git a/Clients/dnssdutil/dnssdutil.c b/Clients/dnssdutil/dnssdutil.c index ef67036..5ab8596 100644 --- a/Clients/dnssdutil/dnssdutil.c +++ b/Clients/dnssdutil/dnssdutil.c @@ -1973,7 +1973,7 @@ static CLIOption kXPCSendOpts[] = }; #endif // TARGET_OS_DARWIN -#if ( MDNSRESPONDER_PROJECT ) +#if( MDNSRESPONDER_PROJECT ) //=========================================================================================================================== // InterfaceMonitor //=========================================================================================================================== @@ -2002,6 +2002,7 @@ static CLIOption kDNSProxyOpts[] = StringOption( 'o', "outputInterface", &gDNSProxy_OutputInterface, "name or index", "Interface to forward queries over. Use '0' for primary interface. (default: 0)", false ), CLI_OPTION_END() }; + #endif // MDNSRESPONDER_PROJECT //=========================================================================================================================== @@ -2070,7 +2071,7 @@ static CLIOption kGlobalOpts[] = Command( "dnsconfig", NULL, kDNSConfigOpts, "Add/remove a supplemental resolver entry to/from the system's DNS configuration.", true ), Command( "xpcsend", XPCSendCmd, kXPCSendOpts, "Sends a message to an XPC service.", true ), #endif -#if ( MDNSRESPONDER_PROJECT ) +#if( MDNSRESPONDER_PROJECT ) Command( "interfaceMonitor", InterfaceMonitorCmd, kInterfaceMonitorOpts, "mDNSResponder's interface monitor.", true ), Command( "dnsproxy", DNSProxyCmd, kDNSProxyOpts, "Enables mDNSResponder's DNS proxy.", true ), #endif @@ -14520,6 +14521,7 @@ static Boolean expensiveConstrainedEndsWith( const char *str, const char *suffix //=========================================================================================================================== // ExpensiveConstrainedTestCmd //=========================================================================================================================== + static void ExpensiveConstrainedTestCmd( void ) { OSStatus err; @@ -15356,7 +15358,7 @@ static Boolean expensiveConstrainedEndsWith( const char *str, const char *suffix } //=========================================================================================================================== -// RegistrationTestCmd +// RegistrationTestCmd //=========================================================================================================================== typedef struct RegistrationSubtest RegistrationSubtest; diff --git a/Makefile b/Makefile index 4e38d77..88f9942 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ include $(MAKEFILEPATH)/pb_makefiles/platform.make -MVERS = "mDNSResponder-1096.0.2" +MVERS = "mDNSResponder-1096.40.7" VER = ifneq ($(strip $(GCC_VERSION)),) diff --git a/mDNSCore/DNSCommon.c b/mDNSCore/DNSCommon.c index 2c4e97e..1e70883 100644 --- a/mDNSCore/DNSCommon.c +++ b/mDNSCore/DNSCommon.c @@ -1827,7 +1827,7 @@ mDNSexport mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const ar, const D if (rr->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly && ((q->InterfaceID && rr->InterfaceID != q->InterfaceID) || - (!q->InterfaceID && rr->InterfaceID != mDNSInterface_LocalOnly))) return(mDNSfalse); + (!q->InterfaceID && !LocalOnlyOrP2PInterface(rr->InterfaceID)))) return(mDNSfalse); // Entries in /etc/hosts are added as LocalOnly resource records. The LocalOnly resource records // may have a scope e.g., fe80::1%en0. The question may be scoped or not: the InterfaceID may be set diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c index 4ec1934..2fbea04 100755 --- a/mDNSCore/mDNS.c +++ b/mDNSCore/mDNS.c @@ -7357,8 +7357,7 @@ mDNSlocal const AuthRecord *FindRRSet(const mDNS *const m, const CacheRecord *co { if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec)) { - while (rr->RRSet && rr != rr->RRSet) rr = rr->RRSet; - return(rr); + return(rr->RRSet ? rr->RRSet : rr); } } return(mDNSNULL); @@ -8140,7 +8139,18 @@ mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, if (mDNSSameOpaque16(q->TargetQID, id)) return(q); else { - if (!tcp && suspiciousQ) *suspiciousQ = q; + // Everything but the QIDs match up, should we be suspicious? + if (!tcp && suspiciousQ) + { +#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE) + if (mDNSSameOpaque16(q->LastTargetQID, id)) // Only be suspicious if this is also not the "last" used QID (on a DNS server set change) + { + LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, "Ignored but not suspicious LastTargetQID %d TargetQID %d", mDNSVal16(q->LastTargetQID), mDNSVal16(q->TargetQID)); + } + else +#endif + *suspiciousQ = q; + } return(mDNSNULL); } } @@ -8281,6 +8291,25 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C return(rr); } +mDNSlocal void RefreshCacheRecordCacheGroupOrder(CacheGroup *cg, CacheRecord *cr) +{ // Move the cache record to the tail of the cache group to maintain a fresh ordering + if (cg->rrcache_tail != &cr->next) // If not already at the tail + { + CacheRecord **rp; + for (rp = &cg->members; *rp; rp = &(*rp)->next) + { + if (*rp == cr) // This item points to this record + { + *rp = cr->next; // Remove this record + break; + } + } + cr->next = mDNSNULL; // This record is now last + *(cg->rrcache_tail) = cr; // Append this record to tail of cache group + cg->rrcache_tail = &(cr->next); // Advance tail pointer + } +} + mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl) { rr->TimeRcvd = m->timenow; @@ -8862,6 +8891,9 @@ mDNSexport CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessag if (cr->resrec.rroriginalttl == 0) debugf("uDNS rescuing %s", CRDisplayString(m, cr)); RefreshCacheRecord(m, cr, m->rec.r.resrec.rroriginalttl); + // RefreshCacheRecordCacheGroupOrder will modify the cache group member list that is currently being iterated over in this for-loop. + // It is safe to call because the else-if body will unconditionally break out of the for-loop now that it has found the entry to update. + RefreshCacheRecordCacheGroupOrder(cg, cr); cr->responseFlags = response->h.flags; // If we may have NSEC records returned with the answer (which we don't know yet as it @@ -8898,7 +8930,7 @@ mDNSexport CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessag } } } - break; + break; // Check usage of RefreshCacheRecordCacheGroupOrder before removing (See note above) } else { @@ -12024,6 +12056,9 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu #ifndef UNICAST_DISABLED question->TargetQID = Question_uDNS(question) ? mDNS_NewMessageID(m) : zeroID; +#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE) + question->LastTargetQID = zeroID; +#endif #else question->TargetQID = zeroID; #endif @@ -12570,13 +12605,30 @@ mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatu mDNSlocal void mDNS_RandomizedHostNameCallback(mDNS *m, AuthRecord *rr, mStatus result); #endif -mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m) +mDNSlocal AuthRecord *GetInterfaceAddressRecord(NetworkInterfaceInfo *intf, mDNSBool forRandHostname) +{ +#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME) + return(forRandHostname ? &intf->RR_AddrRand : &intf->RR_A); +#else + (void)forRandHostname; // Unused. + return(&intf->RR_A); +#endif +} + +mDNSlocal AuthRecord *GetFirstAddressRecordEx(const mDNS *const m, const mDNSBool forRandHostname) { NetworkInterfaceInfo *intf; for (intf = m->HostInterfaces; intf; intf = intf->next) - if (intf->Advertise) break; - return(intf); + { + if (!intf->Advertise) continue; +#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME) + if (mDNSPlatformInterfaceIsAWDL(intf->InterfaceID)) continue; +#endif + return(GetInterfaceAddressRecord(intf, forRandHostname)); + } + return(mDNSNULL); } +#define GetFirstAddressRecord(M) GetFirstAddressRecordEx(M, mDNSfalse) // The parameter "set" here refers to the set of AuthRecords used to advertise this interface. // (It's a set of records, not a set of interfaces.) @@ -12586,7 +12638,6 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNS mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) #endif { - NetworkInterfaceInfo *primary; const domainname *hostname; mDNSRecordCallback *hostnameCallback; AuthRecord *addrAR; @@ -12676,22 +12727,15 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) ptrAR->ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server } - primary = FindFirstAdvertisedInterface(m); - if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary - // We should never have primary be NULL, because even if there is - // no other interface yet, we should always find ourself in the list. - #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME) - if (!interfaceIsAWDL && useRandomizedHostname) - { - addrAR->RRSet = &primary->RR_AddrRand; - } - else + addrAR->RRSet = interfaceIsAWDL ? addrAR : GetFirstAddressRecordEx(m, useRandomizedHostname); +#else + addrAR->RRSet = GetFirstAddressRecord(m); #endif - { - addrAR->RRSet = &primary->RR_A; - } + if (!addrAR->RRSet) addrAR->RRSet = addrAR; mDNS_Register_internal(m, addrAR); + LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "Initialized RRSet for " PRI_S, ARDisplayString(m, addrAR)); + LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "RRSet: " PRI_S, ARDisplayString(m, addrAR->RRSet)); if (ptrAR) mDNS_Register_internal(m, ptrAR); #if MDNSRESPONDER_SUPPORTS(APPLE, D2D) @@ -13171,6 +13215,36 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s return(mStatus_NoError); } +mDNSlocal void AdjustAddressRecordSetsEx(mDNS *const m, NetworkInterfaceInfo *removedIntf, mDNSBool forRandHostname) +{ + NetworkInterfaceInfo *intf; + const AuthRecord *oldAR; + AuthRecord *newAR; +#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME) + if (mDNSPlatformInterfaceIsAWDL(removedIntf->InterfaceID)) return; +#endif + oldAR = GetInterfaceAddressRecord(removedIntf, forRandHostname); + newAR = GetFirstAddressRecordEx(m, forRandHostname); + for (intf = m->HostInterfaces; intf; intf = intf->next) + { + AuthRecord *ar; +#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME) + if (mDNSPlatformInterfaceIsAWDL(intf->InterfaceID)) continue; +#endif + ar = GetInterfaceAddressRecord(intf, forRandHostname); + if (ar->RRSet == oldAR) + { + ar->RRSet = newAR ? newAR : ar; + LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "Changed RRSet for " PRI_S, ARDisplayString(m, ar)); + LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "New RRSet: " PRI_S, ARDisplayString(m, ar->RRSet)); + } + } +} +#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME) +#define AdjustAddressRecordSetsForRandHostname(M, REMOVED_INTF) AdjustAddressRecordSetsEx(M, REMOVED_INTF, mDNStrue) +#endif +#define AdjustAddressRecordSets(M, REMOVED_INTF) AdjustAddressRecordSetsEx(M, REMOVED_INTF, mDNSfalse) + // Note: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change // the record list and/or question list. // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. @@ -13181,9 +13255,7 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se #endif NetworkInterfaceInfo **p = &m->HostInterfaces; mDNSBool revalidate = mDNSfalse; - NetworkInterfaceInfo *primary; NetworkInterfaceInfo *intf; - AuthRecord *A; mDNS_Lock(m); @@ -13291,12 +13363,11 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se // If we still have address records referring to this one, update them. // This is safe, because this NetworkInterfaceInfo has already been unlinked from the list, - // so the call to FindFirstAdvertisedInterface() won’t accidentally find it. - primary = FindFirstAdvertisedInterface(m); - A = primary ? &primary->RR_A : mDNSNULL; - for (intf = m->HostInterfaces; intf; intf = intf->next) - if (intf->RR_A.RRSet == &set->RR_A) - intf->RR_A.RRSet = A; + // so the call to AdjustAddressRecordSets*() won’t accidentally find it. + AdjustAddressRecordSets(m, set); +#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME) + AdjustAddressRecordSetsForRandHostname(m, set); +#endif // If we were advertising on this interface, deregister those address and reverse-lookup records now if (set->Advertise) DeadvertiseInterface(m, set, kDeadvertiseFlag_All); @@ -14838,6 +14909,10 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) LogInfo("uDNS_SetupDNSConfig: No configuration change"); return mStatus_NoError; } +#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE) + // Reset suspicious mode on any DNS configuration change + m->NextSuspiciousTimeout = 0; +#endif // For now, we just delete the mcast resolvers. We don't deal with cache or // questions here. Neither question nor cache point to mcast resolvers. Questions @@ -14957,6 +15032,9 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) q->Suppressed = ShouldSuppressUnicastQuery(q, s); q->unansweredQueries = 0; +#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE) + q->LastTargetQID = q->TargetQID; +#endif q->TargetQID = mDNS_NewMessageID(m); if (!q->Suppressed) ActivateUnicastQuery(m, q, mDNStrue); } diff --git a/mDNSCore/mDNSEmbeddedAPI.h b/mDNSCore/mDNSEmbeddedAPI.h index 041772a..78d957b 100755 --- a/mDNSCore/mDNSEmbeddedAPI.h +++ b/mDNSCore/mDNSEmbeddedAPI.h @@ -2052,6 +2052,9 @@ struct DNSQuestion_struct mDNSQuestionCallback *QuestionCallback; mDNSQuestionResetHandler ResetHandler; void *QuestionContext; +#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE) + mDNSOpaque16 LastTargetQID; // Last used QID, to help determine suspicion with valid in-flight replies. +#endif #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS) uDNSMetrics metrics; // Data used for collecting unicast DNS query metrics. #endif @@ -2538,7 +2541,7 @@ extern const mDNSInterfaceID mDNSInterface_P2P; // Special value extern const mDNSInterfaceID uDNSInterfaceMark; // Special value extern const mDNSInterfaceID mDNSInterface_BLE; // Special value -#define LocalOnlyOrP2PInterface(INTERFACE) ((INTERFACE == mDNSInterface_LocalOnly) || (INTERFACE == mDNSInterface_P2P) || (INTERFACE == mDNSInterface_BLE)) +#define LocalOnlyOrP2PInterface(INTERFACE) (((INTERFACE) == mDNSInterface_LocalOnly) || ((INTERFACE) == mDNSInterface_P2P) || ((INTERFACE) == mDNSInterface_BLE)) extern const mDNSIPPort DiscardPort; extern const mDNSIPPort SSHPort; @@ -3636,13 +3639,13 @@ struct CompileTimeAssertionChecks_mDNS char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1168) ? 1 : -1]; char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 232) ? 1 : -1]; char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 232) ? 1 : -1]; - char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 1128) ? 1 : -1]; + char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 1136) ? 1 : -1]; char sizecheck_ZoneData [(sizeof(ZoneData) <= 2000) ? 1 : -1]; char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 200) ? 1 : -1]; char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3050) ? 1 : -1]; char sizecheck_DNSServer [(sizeof(DNSServer) <= 328) ? 1 : -1]; - char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 8240) ? 1 : -1]; + char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 8272) ? 1 : -1]; char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 4728) ? 1 : -1]; char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 944) ? 1 : -1]; #if APPLE_OSX_mDNSResponder diff --git a/mDNSMacOSX/ApplePlatformFeatures.h b/mDNSMacOSX/ApplePlatformFeatures.h index 77f3eab..a4586af 100644 --- a/mDNSMacOSX/ApplePlatformFeatures.h +++ b/mDNSMacOSX/ApplePlatformFeatures.h @@ -103,6 +103,21 @@ #endif #endif +// Feature: No system wake for network access. +// Radar: +// Enabled: Yes, but only for iOS and watchOS, which shouldn't act as sleep-proxy clients. + +#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_NO_WAKE_FOR_NET_ACCESS) + #if (!defined(TARGET_OS_IOS) || !defined(TARGET_OS_WATCH)) + #error "Expected TARGET_OS_IOS and TARGET_OS_WATCH to be defined." + #endif + #if (TARGET_OS_IOS || TARGET_OS_WATCH) + #define MDNSRESPONDER_SUPPORTS_APPLE_NO_WAKE_FOR_NET_ACCESS 1 + #else + #define MDNSRESPONDER_SUPPORTS_APPLE_NO_WAKE_FOR_NET_ACCESS 0 + #endif +#endif + // Feature: Support for having finer granularity of log redaction, by using os_log based-log routine. // Radar: // Enabled: Yes. diff --git a/mDNSMacOSX/Tests/BATS Scripts/bats_test_proxy.sh b/mDNSMacOSX/Tests/BATS Scripts/bats_test_proxy.sh index 03e0bdf..c1bcebd 100755 --- a/mDNSMacOSX/Tests/BATS Scripts/bats_test_proxy.sh +++ b/mDNSMacOSX/Tests/BATS Scripts/bats_test_proxy.sh @@ -47,7 +47,7 @@ function test_proxy_on { local dnssdutil_pid=$! # See if that worked - sleep 1 + sleep 5 local dnssdutil_pid_now=$(ps xa |sed -n -e 's/^ *\([0-9][0-9]*\).*$/\1/' -e "/$dnssdutil_pid/p") if [ $dnssdutil_pid != "$dnssdutil_pid_now" ]; then echo "Failed to enable DNS proxy $dnssdutil_pid $dnssdutil_pid_now." diff --git a/mDNSMacOSX/Tests/CNameRecordTest.m b/mDNSMacOSX/Tests/Unit Tests/CNameRecordTest.m similarity index 96% rename from mDNSMacOSX/Tests/CNameRecordTest.m rename to mDNSMacOSX/Tests/Unit Tests/CNameRecordTest.m index 873561d..f96d4ad 100644 --- a/mDNSMacOSX/Tests/CNameRecordTest.m +++ b/mDNSMacOSX/Tests/Unit Tests/CNameRecordTest.m @@ -50,7 +50,7 @@ uint8_t query_response_msgbuf[108] = { #define uDNS_TargetQID 16745 char udns_original_domainname_cstr[] = "123server.dotbennu.com."; char udns_cname_domainname_cstr[] = "test212.dotbennu.com."; -//static const mDNSv4Addr dns_response_ipv4 = {{ 10, 100, 0, 1 }}; +static const mDNSv4Addr dns_response_ipv4 = {{ 10, 100, 0, 1 }}; @interface CNameRecordTest : XCTestCase { @@ -105,13 +105,20 @@ char udns_cname_domainname_cstr[] = "test212.dotbennu.com."; } } +- (void)testCNameRecordTestSeries +{ + [self _startClientQueryRequest]; + [self _populateCacheWithClientResponseRecords]; + [self _simulateNetworkChangeAndVerify]; +} + // This test simulates a uds client request by setting up a client request and then // calling mDNSResponder's handle_client_request. The handle_client_request function // processes the request and starts a query. This unit test verifies // the client request and query were setup as expected. This unit test also calls // mDNS_execute which determines the cache does not contain the new question's // answer. -- (void)testStartClientQueryRequest +- (void)_startClientQueryRequest { mDNS *const m = &mDNSStorage; request_state* req = client_request_message; @@ -189,19 +196,19 @@ char udns_cname_domainname_cstr[] = "test212.dotbennu.com."; XCTAssertEqual(m->rrcache_totalused, 0); XCTAssertNil((__bridge id)req->replies); } -#if 0 + // This unit test receives a canned uDNS response message by calling the mDNSCoreReceive() function. // It then verifies cache entries were added for the CNAME and A records that were contained in the // answers of the canned response, query_response_msgbuf. This unit test also verifies that // 2 add events were generated for the client. -- (void)testPopulateCacheWithClientResponseRecords +- (void)_populateCacheWithClientResponseRecords { mDNS *const m = &mDNSStorage; DNSMessage *msgptr = (DNSMessage *)query_response_msgbuf; size_t msgsz = sizeof(query_response_msgbuf); struct reply_state *reply; request_state* req = client_request_message; - DNSQuestion *q = &req->u.queryrecord.q; + DNSQuestion *q = &req->u.queryrecord.op.q; const char *data; const char *end; char name[kDNSServiceMaxDomainName]; @@ -300,11 +307,11 @@ char udns_cname_domainname_cstr[] = "test212.dotbennu.com."; // 1.) The restart of query for A record. // 2.) The cache is empty after mDNS_Execute removes the cache entres. // 3.) The remove event is verified by examining the request's reply data. -- (void)testSimulateNetworkChangeAndVerify +- (void)_simulateNetworkChangeAndVerify { mDNS *const m = &mDNSStorage; request_state* req = client_request_message; - DNSQuestion* q = &req->u.queryrecord.q; + DNSQuestion* q = &req->u.queryrecord.op.q; mDNSu32 CacheUsed =0, notUsed =0; const char *data; const char *end; char name[kDNSServiceMaxDomainName]; @@ -314,8 +321,8 @@ char udns_cname_domainname_cstr[] = "test212.dotbennu.com."; // The uDNS_SetupDNSConfig reconfigures the resolvers so the A record query is restarted and // both the CNAME and A record are purged. - uDNS_SetupDNSConfig(m); - + force_uDNS_SetupDNSConfig_ut(m); + // Verify the A record query was restarted. This is done indirectly by noticing the transaction id and interval have changed. XCTAssertEqual(q->ThisQInterval, InitialQuestionInterval); XCTAssertNotEqual(q->TargetQID.NotAnInteger, uDNS_TargetQID); @@ -363,6 +370,5 @@ char udns_cname_domainname_cstr[] = "test212.dotbennu.com."; XCTAssertEqual(rdata[2], dns_response_ipv4.b[2]); XCTAssertEqual(rdata[3], dns_response_ipv4.b[3]); } -#endif @end diff --git a/mDNSMacOSX/Tests/Unit Tests/CacheOrderTest.m b/mDNSMacOSX/Tests/Unit Tests/CacheOrderTest.m new file mode 100644 index 0000000..facd79b --- /dev/null +++ b/mDNSMacOSX/Tests/Unit Tests/CacheOrderTest.m @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2017-2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unittest_common.h" +#import + +struct UDPSocket_struct +{ + mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port +}; +typedef struct UDPSocket_struct UDPSocket; + +// This client request was generated using the following command: "dns-sd -Q web.mydomain.test". +uint8_t test_order_query_msgbuf[30] = { + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x65, 0x62, 0x2e, 0x6d, 0x79, 0x64, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x01, 0x00, 0x01 +}; +#if 0 +0000 10 c1 01 00 00 01 00 00 00 00 00 00 03 77 65 62 +0010 08 6d 79 64 6f 6d 61 69 6e 04 74 65 73 74 00 00 +0020 01 00 01 + +0000 ef 53 01 00 00 01 00 00 00 00 00 00 03 77 65 62 +0010 08 6d 79 64 6f 6d 61 69 6e 04 74 65 73 74 00 00 +0020 01 00 01 + +uint8_t test_query_client_msgbuf[35] = { + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, + 0x01, 0x00, 0x01 +}; +#endif +// This uDNS message is a canned response that was originally captured by wireshark. +uint8_t test_order_response1_msgbuf[228] = { + 0x0f, 0x98, // transaction id + 0x85, 0x80, // flags + 0x00, 0x01, // 1 query: web.mydomain.test: type A, class IN + 0x00, 0x04, // 4 anwsers: Addr 10.0.0.101, Addr 10.0.0.105, Addr 10.0.0.104, Addr 10.0.0.102 + 0x00, 0x01, // 1 authoritative nameservers: mydomain.test: type NS, class IN, ns ns.mydomain.test + 0x00, 0x01, // 1 additional: ns.mydomain.test: type A, class IN, addr 192.168.0.23 + 0x03, 0x77, 0x65, 0x62, + 0x08, 0x6d, 0x79, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, + 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a, + 0x00, 0x00, 0x65, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a, + 0x00, 0x00, 0x69, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a, + 0x00, 0x00, 0x68, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a, + 0x00, 0x00, 0x66, 0xc0, 0x10, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x05, 0x02, + 0x6e, 0x73, 0xc0, 0x10, 0xc0, 0x6f, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x04, + 0xc0, 0xa8, 0x00, 0x17 +}; + +// This uDNS message is a canned response that was originally captured by wireshark, then modified to match above (other than Addr order). +uint8_t test_order_response2_msgbuf[228] = { + 0x0f, 0x98, // transaction id + 0x85, 0x80, // flags + 0x00, 0x01, // 1 query: web.mydomain.test: type A, class IN + 0x00, 0x04, // 4 anwsers: Addr 10.0.0.102, Addr 10.0.0.101, Addr 10.0.0.104, Addr 10.0.0.105 + 0x00, 0x01, // 1 authoritative nameservers: mydomain.test: type NS, class IN, ns ns.mydomain.test + 0x00, 0x01, // 1 additional: ns.mydomain.test: type A, class IN, addr 192.168.0.23 + 0x03, 0x77, 0x65, 0x62, + 0x08, 0x6d, 0x79, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, + 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a, + 0x00, 0x00, 0x66, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a, + 0x00, 0x00, 0x65, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a, + 0x00, 0x00, 0x68, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a, + 0x00, 0x00, 0x69, 0xc0, 0x10, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x05, 0x02, + 0x6e, 0x73, 0xc0, 0x10, 0xc0, 0x6f, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x04, + 0xc0, 0xa8, 0x00, 0x17 +}; + +// Variables associated with contents of the above uDNS message +char test_order_domainname_cstr[] = "web.mydomain.test."; + +@interface CacheOrderTest : XCTestCase +{ + UDPSocket* local_socket; + request_state* client_request_message;} +@end + +@implementation CacheOrderTest + +// The InitThisUnitTest() initializes the mDNSResponder environment as well as +// a DNSServer. It also allocates memory for a local_socket and client request. +// Note: This unit test does not send packets on the wire and it does not open sockets. +- (void)setUp +{ + mDNSPlatformMemZero(&mDNSStorage, sizeof(mDNS)); + + // Init unit test environment and verify no error occurred. + mStatus result = init_mdns_environment(mDNStrue); + XCTAssertEqual(result, mStatus_NoError); + + // Add one DNS server and verify it was added. + AddDNSServer_ut(); + XCTAssertEqual(CountOfUnicastDNSServers(&mDNSStorage), 1); + + // Create memory for a socket that is never used or opened. + local_socket = (UDPSocket *) mDNSPlatformMemAllocateClear(sizeof(*local_socket)); + + // Create memory for a request that is used to make this unit test's client request. + client_request_message = calloc(1, sizeof(request_state)); +} + +- (void)tearDown +{ + mDNS *m = &mDNSStorage; + request_state* req = client_request_message; + DNSServer *ptr, **p = &m->DNSServers; + + while (req->replies) + { + reply_state *reply = req->replies; + req->replies = req->replies->next; + mDNSPlatformMemFree(reply); + } + mDNSPlatformMemFree(req); + + mDNSPlatformMemFree(local_socket); + + while (*p) + { + ptr = *p; + *p = (*p)->next; + LogInfo("FinalizeUnitTest: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c); + mDNSPlatformMemFree(ptr); + } +} + +- (void)testSuspiciousReplyTestSeries +{ + [self _clientQueryRequest]; + [self _verifyCacheOrderBehavior]; +} + +// Simulate a uds client request by setting up a client request and then +// calling mDNSResponder's handle_client_request. The handle_client_request function +// processes the request and starts a query. This unit test verifies +// the client request and query were setup as expected. This unit test also calls +// mDNS_execute which determines the cache does not contain the new question's +// answer. +- (void)_clientQueryRequest +{ + mDNS *const m = &mDNSStorage; + request_state* req = client_request_message; + char *msgptr = (char *)test_order_query_msgbuf; + size_t msgsz = sizeof(test_order_query_msgbuf); + mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4; + DNSQuestion *q; + mStatus err = mStatus_NoError; + char qname_cstr[MAX_ESCAPED_DOMAIN_NAME]; + + // Process the unit test's client request + start_client_request(req, msgptr, msgsz, query_request, local_socket); + XCTAssertEqual(err, mStatus_NoError); + + // Verify the request fields were set as expected + XCTAssertNil((__bridge id)req->next); + XCTAssertNil((__bridge id)req->primary); + XCTAssertEqual(req->sd, client_req_sd); + XCTAssertEqual(req->process_id, client_req_process_id); + XCTAssertFalse(strcmp(req->pid_name, client_req_pid_name)); + XCTAssertEqual(req->validUUID, mDNSfalse); + XCTAssertEqual(req->errsd, 0); + XCTAssertEqual(req->uid, client_req_uid); + XCTAssertEqual(req->ts, t_complete); + XCTAssertGreaterThan((mDNSs32)req->data_bytes, min_size); + XCTAssertEqual(req->msgend, msgptr+msgsz); + XCTAssertNil((__bridge id)(void*)req->msgbuf); + XCTAssertEqual(req->hdr.version, VERSION); + XCTAssertNil((__bridge id)req->replies); + XCTAssertNotEqual(req->terminate, (req_termination_fn)0); + XCTAssertEqual(req->flags, kDNSServiceFlagsReturnIntermediates); + XCTAssertEqual(req->interfaceIndex, kDNSServiceInterfaceIndexAny); + + // Verify the query fields were set as expected + q = &req->u.queryrecord.op.q; + XCTAssertNotEqual(q, (DNSQuestion *)mDNSNULL); + XCTAssertEqual(q, m->Questions); + XCTAssertEqual(q, m->NewQuestions); + XCTAssertEqual(q->SuppressUnusable, mDNSfalse); + XCTAssertEqual(q->ReturnIntermed, mDNStrue); + XCTAssertEqual(q->Suppressed, mDNSfalse); + + ConvertDomainNameToCString(&q->qname, qname_cstr); + XCTAssertFalse(strcmp(qname_cstr, test_order_domainname_cstr)); + XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname)); + + XCTAssertEqual(q->InterfaceID, mDNSInterface_Any); + XCTAssertEqual(q->flags, req->flags); + XCTAssertEqual(q->qtype, 1); + XCTAssertEqual(q->qclass, 1); + XCTAssertEqual(q->LongLived, 0); + XCTAssertEqual(q->ExpectUnique, mDNSfalse); + XCTAssertEqual(q->ForceMCast, 0); + XCTAssertEqual(q->TimeoutQuestion, 0); + XCTAssertEqual(q->WakeOnResolve, 0); + XCTAssertEqual(q->UseBackgroundTraffic, 0); + XCTAssertEqual(q->ValidationRequired, 0); + XCTAssertEqual(q->ValidatingResponse, 0); + XCTAssertEqual(q->ProxyQuestion, 0); + XCTAssertNotEqual((void*)q->QuestionCallback, (void*)mDNSNULL); + XCTAssertNil((__bridge id)q->DNSSECAuthInfo); + XCTAssertNil((__bridge id)(void*)q->DAIFreeCallback); + XCTAssertEqual(q->AppendSearchDomains, 0); + XCTAssertNil((__bridge id)q->DuplicateOf); + + // Call mDNS_Execute to see if the new question, q, has an answer in the cache. + // It won't be yet because the cache is empty. + m->NextScheduledEvent = mDNS_TimeNow_NoLock(m); + mDNS_Execute(m); + + // Verify mDNS_Execute processed the new question. + XCTAssertNil((__bridge id)m->NewQuestions); + + // Verify the cache is empty and the request got no reply. + XCTAssertEqual(m->rrcache_totalused, 0); + XCTAssertNil((__bridge id)req->replies); +} + +// This unit test performs two queries and verifies the cache oredr is updated on a new response. +// 1) Verify response is ordered in the cache as expected +// 2) Test again with new response, and verify cache order is updated +- (void)_verifyCacheOrderBehavior +{ + mDNS *const m = &mDNSStorage; + DNSMessage *msgptr; + size_t msgsz; + request_state* req = client_request_message; + DNSQuestion *q = &req->u.queryrecord.op.q; + mStatus status; + + // 1) + // Process first response + // Verify response cache count & order + + msgptr = (DNSMessage *)test_order_response1_msgbuf; + msgsz = sizeof(test_order_response1_msgbuf); + receive_response(req, msgptr, msgsz); + + // Verify records received + mDNSu32 CacheUsed =0, notUsed =0; + LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, ¬Used); + XCTAssertEqual(CacheUsed, 5); // Verify 4 records received + Cache Group + + // Verify record order + mDNSu8 lastoctet1[4] = {101, 105, 104, 102}; + status = verify_cache_addr_order_for_domain_ut(m, lastoctet1, 4, &q->qname); + XCTAssertEqual(status, mStatus_NoError, @"Cache order test 1 failed"); + + // 2) + // Process second response + // Verify response cache count & order + + msgptr = (DNSMessage *)test_order_response2_msgbuf; + msgsz = sizeof(test_order_response2_msgbuf); + receive_response(req, msgptr, msgsz); + + // Verify records received + LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, ¬Used); + XCTAssertEqual(CacheUsed, 5); // Verify 4 records received + Cache Group + + // Verify record order + mDNSu8 lastoctet2[4] = {102, 101, 104, 105}; + status = verify_cache_addr_order_for_domain_ut(m, lastoctet2, 4, &q->qname); + XCTAssertEqual(status, mStatus_NoError, @"Cache order test 2 failed"); +} + + +@end diff --git a/mDNSMacOSX/Tests/DNSMessageTest.m b/mDNSMacOSX/Tests/Unit Tests/DNSMessageTest.m similarity index 100% rename from mDNSMacOSX/Tests/DNSMessageTest.m rename to mDNSMacOSX/Tests/Unit Tests/DNSMessageTest.m diff --git a/mDNSMacOSX/Tests/HelperFunctionTest.m b/mDNSMacOSX/Tests/Unit Tests/HelperFunctionTest.m similarity index 100% rename from mDNSMacOSX/Tests/HelperFunctionTest.m rename to mDNSMacOSX/Tests/Unit Tests/HelperFunctionTest.m diff --git a/mDNSMacOSX/Tests/Info.plist b/mDNSMacOSX/Tests/Unit Tests/Info.plist similarity index 100% rename from mDNSMacOSX/Tests/Info.plist rename to mDNSMacOSX/Tests/Unit Tests/Info.plist diff --git a/mDNSMacOSX/Tests/LocalOnlyTimeoutTest.m b/mDNSMacOSX/Tests/Unit Tests/LocalOnlyTimeoutTest.m similarity index 100% rename from mDNSMacOSX/Tests/LocalOnlyTimeoutTest.m rename to mDNSMacOSX/Tests/Unit Tests/LocalOnlyTimeoutTest.m diff --git a/mDNSMacOSX/Tests/Unit Tests/LocalOnlyWithInterfacesTest.m b/mDNSMacOSX/Tests/Unit Tests/LocalOnlyWithInterfacesTest.m new file mode 100644 index 0000000..07656c4 --- /dev/null +++ b/mDNSMacOSX/Tests/Unit Tests/LocalOnlyWithInterfacesTest.m @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unittest_common.h" +#import + +struct UDPSocket_struct +{ + mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port +}; +typedef struct UDPSocket_struct UDPSocket; + +// This client request was generated using the following command: "dns-sd -Q 123server.dotbennu.com. A". +char test_query_any_msgbuf[35] = { + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, + 0x01, 0x00, 0x01 +}; + +// Modified for different scopes +char test_query_local_msgbuf[35] = { + 0x00, 0x00, 0x10, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, + 0x01, 0x00, 0x01 +}; + +char test_query_interface_msgbuf[35] = { + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, + 0x01, 0x00, 0x01 +}; + +// Variables associated with contents of the above uDNS message +mDNSlocal char test_domainname_cstr[] = "123server.dotbennu.com."; + +mDNSlocal mDNSBool _TestCreateEtcHostsEntryWithInterfaceID(const domainname *domain, const struct sockaddr *sa, const domainname *cname, mDNSInterfaceID interfaceID, AuthHash *auth) +{ // Copied from mDNSMacOSXCreateEtcHostsEntry + AuthRecord *rr; + mDNSu32 namehash; + AuthGroup *ag; + mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly; + mDNSu16 rrtype; + + if (!domain) + { + LogMsg("_TestCreateEtcHostsEntryWithInterfaceID: ERROR!! name NULL"); + return mDNSfalse; + } + if (!sa && !cname) + { + LogMsg("_TestCreateEtcHostsEntryWithInterfaceID: ERROR!! sa and cname both NULL"); + return mDNSfalse; + } + + if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6) + { + LogMsg("_TestCreateEtcHostsEntryWithInterfaceID: ERROR!! sa with bad family %d", sa->sa_family); + return mDNSfalse; + } + + + if (interfaceID) + { + InterfaceID = interfaceID; + } + + if (sa) + rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA); + else + rrtype = kDNSType_CNAME; + + // Check for duplicates. See whether we parsed an entry before like this ? + namehash = DomainNameHashValue(domain); + ag = AuthGroupForName(auth, namehash, domain); + if (ag) + { + rr = ag->members; + while (rr) + { + if (rr->resrec.rrtype == rrtype) + { + if (rrtype == kDNSType_A) + { + mDNSv4Addr ip; + ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr; + if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip) && InterfaceID == rr->resrec.InterfaceID) + { + LogInfo("_TestCreateEtcHostsEntryWithInterfaceID: Same IPv4 address and InterfaceID for name %##s ID %d", domain->c, IIDPrintable(InterfaceID)); + return mDNSfalse; + } + } + else if (rrtype == kDNSType_AAAA) + { + mDNSv6Addr ip6; + ip6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0]; + ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1]; + ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2]; + ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3]; + if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6) && InterfaceID == rr->resrec.InterfaceID) + { + LogInfo("_TestCreateEtcHostsEntryWithInterfaceID: Same IPv6 address and InterfaceID for name %##s ID %d", domain->c, IIDPrintable(InterfaceID)); + return mDNSfalse; + } + } + else if (rrtype == kDNSType_CNAME) + { + if (SameDomainName(&rr->resrec.rdata->u.name, cname)) + { + LogInfo("_TestCreateEtcHostsEntryWithInterfaceID: Same cname %##s for name %##s", cname->c, domain->c); + return mDNSfalse; + } + } + } + rr = rr->next; + } + } + rr = (AuthRecord *) callocL("etchosts", sizeof(*rr)); + if (rr == NULL) return mDNSfalse; + mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL); + AssignDomainName(&rr->namestorage, domain); + + if (sa) + { + rr->resrec.rdlength = sa->sa_family == AF_INET ? sizeof(mDNSv4Addr) : sizeof(mDNSv6Addr); + if (sa->sa_family == AF_INET) + rr->resrec.rdata->u.ipv4.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr; + else + { + rr->resrec.rdata->u.ipv6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0]; + rr->resrec.rdata->u.ipv6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1]; + rr->resrec.rdata->u.ipv6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2]; + rr->resrec.rdata->u.ipv6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3]; + } + } + else + { + rr->resrec.rdlength = DomainNameLength(cname); + rr->resrec.rdata->u.name.c[0] = 0; + AssignDomainName(&rr->resrec.rdata->u.name, cname); + } + rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); + SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us + LogInfo("_TestCreateEtcHostsEntryWithInterfaceID: Adding resource record %s ID %d", ARDisplayString(&mDNSStorage, rr), IIDPrintable(rr->resrec.InterfaceID)); + InsertAuthRecord(&mDNSStorage, auth, rr); + return mDNStrue; +} + +mDNSlocal mStatus InitEtcHostsRecords(void) +{ + mDNS *m = &mDNSStorage; + struct sockaddr_storage hostaddr; + domainname domain; + + AuthHash newhosts; + mDNSPlatformMemZero(&newhosts, sizeof(AuthHash)); + + memset(&hostaddr, 0, sizeof(hostaddr)); + get_ip("10.0.0.201", &hostaddr); + MakeDomainNameFromDNSNameString(&domain, "123server.dotbennu.com"); + _TestCreateEtcHostsEntryWithInterfaceID(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSInterface_P2P, &newhosts); + + memset(&hostaddr, 0, sizeof(hostaddr)); + get_ip("10.0.0.202", &hostaddr); + MakeDomainNameFromDNSNameString(&domain, "123server.dotbennu.com"); + mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts); + + memset(&hostaddr, 0, sizeof(hostaddr)); + get_ip("10.0.0.203", &hostaddr); + MakeDomainNameFromDNSNameString(&domain, "123server.dotbennu.com"); + _TestCreateEtcHostsEntryWithInterfaceID(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, primary_interfaceID, &newhosts); + + UpdateEtcHosts_ut(&newhosts); + m->NextScheduledEvent = mDNS_TimeNow_NoLock(m); + mDNS_Execute(m); + + return mStatus_NoError; +} + +mDNSlocal mDNSs32 NumReplies(reply_state * reply) +{ + mDNSs32 result = 0; + reply_state * nextreply = reply; + while(nextreply) { result++; nextreply = nextreply->next;} + return result; +} + +mDNSlocal mDNSBool HasReplyWithInterfaceIndex(reply_state * reply, mDNSu32 interfaceIndex) +{ + mDNSBool result = mDNSfalse; + reply_state * nextreply = reply; + while(nextreply) + { + result = (ntohl(nextreply->rhdr[0].ifi) == interfaceIndex); + if (result) break; + nextreply = nextreply->next; + } + return result; +} + +@interface LocalOnlyWithInterfacesTest : XCTestCase +{ + UDPSocket* local_socket; + request_state* client_request_message;} +@end + +@implementation LocalOnlyWithInterfacesTest + +// The InitThisUnitTest() initializes the mDNSResponder environment as well as +// a DNSServer. It also allocates memory for a local_socket and client request. +// Note: This unit test does not send packets on the wire and it does not open sockets. +- (void)setUp +{ + mDNSPlatformMemZero(&mDNSStorage, sizeof(mDNS)); + + // Init unit test environment and verify no error occurred. + mStatus result = init_mdns_environment(mDNStrue); + XCTAssertEqual(result, mStatus_NoError); + + // Add one DNS server and verify it was added. + AddDNSServer_ut(); + XCTAssertEqual(CountOfUnicastDNSServers(&mDNSStorage), 1); + + AddDNSServerScoped_ut(primary_interfaceID, kScopeInterfaceID); + XCTAssertEqual(CountOfUnicastDNSServers(&mDNSStorage), 2); + + // Populate /etc/hosts + result = InitEtcHostsRecords(); + XCTAssertEqual(result, mStatus_NoError); + + int count = LogEtcHosts_ut(&mDNSStorage); + XCTAssertEqual(count, 3); + + // Create memory for a socket that is never used or opened. + local_socket = (UDPSocket *) mDNSPlatformMemAllocateClear(sizeof(*local_socket)); + + // Create memory for a request that is used to make this unit test's client request. + client_request_message = calloc(1, sizeof(request_state)); +} + +- (void)tearDown +{ + mDNS *m = &mDNSStorage; + request_state* req = client_request_message; + DNSServer *ptr, **p = &m->DNSServers; + + while (req->replies) + { + reply_state *reply = req->replies; + req->replies = req->replies->next; + mDNSPlatformMemFree(reply); + } + mDNSPlatformMemFree(req); + + mDNSPlatformMemFree(local_socket); + + while (*p) + { + ptr = *p; + *p = (*p)->next; + LogInfo("FinalizeUnitTest: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c); + mDNSPlatformMemFree(ptr); + } +} + +// This unit test tries 3 different local cache queries +// 1) Test the Any query does not receive the entry scoped to the primary interface, but does received the local and P2P entries +// 2) Test the LocalOnly query receives all the entries +// 3) Test the interface scoped query receives the interface scoped entry +- (void)testLocalOnlyWithInterfacesTestSeries +{ + request_state* req = client_request_message; + + // Verify Any index returns 2 results. + [self _executeClientQueryRequest: req andMsgBuf: test_query_any_msgbuf]; + XCTAssertEqual(NumReplies(req->replies), 2); + XCTAssertTrue(HasReplyWithInterfaceIndex(req->replies, kDNSServiceInterfaceIndexP2P)); + XCTAssertTrue(HasReplyWithInterfaceIndex(req->replies, kDNSServiceInterfaceIndexLocalOnly)); + + // Verify LocalOnly index returns 3 results. + [self _executeClientQueryRequest: req andMsgBuf: test_query_local_msgbuf]; + XCTAssertEqual(NumReplies(req->replies), 3); + XCTAssertTrue(HasReplyWithInterfaceIndex(req->replies, kDNSServiceInterfaceIndexP2P)); + XCTAssertTrue(HasReplyWithInterfaceIndex(req->replies, kDNSServiceInterfaceIndexLocalOnly)); + XCTAssertTrue(HasReplyWithInterfaceIndex(req->replies, primary_interfaceID)); + + // Verify en0 index returns 1 result. + test_query_interface_msgbuf[7] = primary_interfaceID; + [self _executeClientQueryRequest: req andMsgBuf: test_query_interface_msgbuf]; + XCTAssertEqual(NumReplies(req->replies), 1); + XCTAssertTrue(HasReplyWithInterfaceIndex(req->replies, primary_interfaceID)); + +} + +// Simulate a uds client request by setting up a client request and then +// calling mDNSResponder's handle_client_request. The handle_client_request function +// processes the request and starts a query. This unit test verifies +// the client request and query were setup as expected. This unit test also calls +// mDNS_execute which determines the cache does not contain the new question's +// answer. +- (void)_executeClientQueryRequest: (request_state*)req andMsgBuf: (char*)msgbuf +{ + mDNS *const m = &mDNSStorage; + char *msgptr = msgbuf; + size_t msgsz = sizeof(test_query_local_msgbuf); + mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4; + DNSQuestion *q; + mStatus err = mStatus_NoError; + char qname_cstr[MAX_ESCAPED_DOMAIN_NAME]; + + // Process the unit test's client request + start_client_request(req, msgptr, msgsz, query_request, local_socket); + XCTAssertEqual(err, mStatus_NoError); + + // Verify the request fields were set as expected + XCTAssertNil((__bridge id)req->next); + XCTAssertNil((__bridge id)req->primary); + XCTAssertEqual(req->sd, client_req_sd); + XCTAssertEqual(req->process_id, client_req_process_id); + XCTAssertFalse(strcmp(req->pid_name, client_req_pid_name)); + XCTAssertEqual(req->validUUID, mDNSfalse); + XCTAssertEqual(req->errsd, 0); + XCTAssertEqual(req->uid, client_req_uid); + XCTAssertEqual(req->ts, t_complete); + XCTAssertGreaterThan((mDNSs32)req->data_bytes, min_size); + XCTAssertEqual(req->msgend, msgptr+msgsz); + XCTAssertNil((__bridge id)(void*)req->msgbuf); + XCTAssertEqual(req->hdr.version, VERSION); + XCTAssertNil((__bridge id)req->replies); + XCTAssertNotEqual(req->terminate, (req_termination_fn)0); + XCTAssertEqual(req->flags, kDNSServiceFlagsReturnIntermediates); + + // Verify the query fields were set as expected + q = &req->u.queryrecord.op.q; + XCTAssertNotEqual(q, (DNSQuestion *)mDNSNULL); + if (m->Questions) + { + XCTAssertEqual(q, m->Questions); + XCTAssertEqual(q, m->NewQuestions); + XCTAssertTrue(q->InterfaceID == mDNSInterface_Any || q->InterfaceID == primary_interfaceID); + } + else + { + XCTAssertEqual(q, m->LocalOnlyQuestions); + XCTAssertEqual(q, m->NewLocalOnlyQuestions); + XCTAssertEqual(q->InterfaceID, mDNSInterface_LocalOnly); + } + XCTAssertEqual(q->SuppressUnusable, mDNSfalse); + XCTAssertEqual(q->ReturnIntermed, mDNStrue); + XCTAssertEqual(q->Suppressed, mDNSfalse); + + ConvertDomainNameToCString(&q->qname, qname_cstr); + XCTAssertFalse(strcmp(qname_cstr, test_domainname_cstr)); + XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname)); + + XCTAssertEqual(q->flags, req->flags); + XCTAssertEqual(q->qtype, 1); + XCTAssertEqual(q->qclass, 1); + XCTAssertEqual(q->LongLived, 0); + XCTAssertEqual(q->ExpectUnique, mDNSfalse); + XCTAssertEqual(q->ForceMCast, 0); + XCTAssertEqual(q->TimeoutQuestion, 0); + XCTAssertEqual(q->WakeOnResolve, 0); + XCTAssertEqual(q->UseBackgroundTraffic, 0); + XCTAssertEqual(q->ValidationRequired, 0); + XCTAssertEqual(q->ValidatingResponse, 0); + XCTAssertEqual(q->ProxyQuestion, 0); + XCTAssertNotEqual((void*)q->QuestionCallback, (void*)mDNSNULL); + XCTAssertNil((__bridge id)q->DNSSECAuthInfo); + XCTAssertNil((__bridge id)(void*)q->DAIFreeCallback); + XCTAssertEqual(q->AppendSearchDomains, 0); + XCTAssertNil((__bridge id)q->DuplicateOf); + + // Call mDNS_Execute to see if the new question, q, has an answer in the cache. + // It won't be yet because the cache is empty. + m->NextScheduledEvent = mDNS_TimeNow_NoLock(m); + mDNS_Execute(m); + + // Verify mDNS_Execute processed the new question. + XCTAssertNil((__bridge id)m->NewQuestions); + XCTAssertNil((__bridge id)m->NewLocalOnlyQuestions); + XCTAssertEqual(m->rrcache_totalused, 0); + m->Questions = nil; // Reset +} + + +@end diff --git a/mDNSMacOSX/Tests/ResourceRecordTest.m b/mDNSMacOSX/Tests/Unit Tests/ResourceRecordTest.m similarity index 100% rename from mDNSMacOSX/Tests/ResourceRecordTest.m rename to mDNSMacOSX/Tests/Unit Tests/ResourceRecordTest.m diff --git a/mDNSMacOSX/Tests/Unit Tests/SuspiciousReplyTest.m b/mDNSMacOSX/Tests/Unit Tests/SuspiciousReplyTest.m new file mode 100644 index 0000000..534bbb8 --- /dev/null +++ b/mDNSMacOSX/Tests/Unit Tests/SuspiciousReplyTest.m @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2017-2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unittest_common.h" +#import + +struct UDPSocket_struct +{ + mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port +}; +typedef struct UDPSocket_struct UDPSocket; + +// This client request was generated using the following command: "dns-sd -Q 123server.dotbennu.com. A". +uint8_t test_query_client_msgbuf[35] = { + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, + 0x01, 0x00, 0x01 +}; + +// This uDNS message is a canned response that was originally captured by wireshark. +uint8_t test_query_response_msgbuf[108] = { + 0x69, 0x41, // transaction id + 0x85, 0x80, // flags + 0x00, 0x01, // 1 question for 123server.dotbennu.com. Addr + 0x00, 0x02, // 2 anwsers: 123server.dotbennu.com. CNAME test212.dotbennu.com., test212.dotbennu.com. Addr 10.100.0.1, + 0x00, 0x01, // 1 authorities anwser: dotbennu.com. NS cardinal2.apple.com. + 0x00, 0x00, 0x09, 0x31, 0x32, 0x33, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x08, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, + 0x02, 0x56, 0x00, 0x0a, 0x07, 0x74, 0x65, 0x73, 0x74, 0x32, 0x31, 0x32, 0xc0, 0x16, 0xc0, 0x34, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x04, 0x0a, 0x64, 0x00, 0x01, 0xc0, 0x16, + 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x12, 0x09, 0x63, 0x61, 0x72, 0x64, 0x69, + 0x6e, 0x61, 0x6c, 0x32, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x65, 0xc0, 0x1f +}; + +// Variables associated with contents of the above uDNS message +#define uDNS_TargetQID 16745 +char test_original_domainname_cstr[] = "123server.dotbennu.com."; +char test_cname_domainname_cstr[] = "test212.dotbennu.com."; + +@interface SuspiciousReplyTest : XCTestCase +{ + UDPSocket* local_socket; + request_state* client_request_message;} +@end + +@implementation SuspiciousReplyTest + +// The InitThisUnitTest() initializes the mDNSResponder environment as well as +// a DNSServer. It also allocates memory for a local_socket and client request. +// Note: This unit test does not send packets on the wire and it does not open sockets. +- (void)setUp +{ + mDNSPlatformMemZero(&mDNSStorage, sizeof(mDNS)); + + // Init unit test environment and verify no error occurred. + mStatus result = init_mdns_environment(mDNStrue); + XCTAssertEqual(result, mStatus_NoError); + + // Add one DNS server and verify it was added. + AddDNSServer_ut(); + XCTAssertEqual(CountOfUnicastDNSServers(&mDNSStorage), 1); + + // Create memory for a socket that is never used or opened. + local_socket = (UDPSocket *) mDNSPlatformMemAllocateClear(sizeof(*local_socket)); + + // Create memory for a request that is used to make this unit test's client request. + client_request_message = calloc(1, sizeof(request_state)); +} + +- (void)tearDown +{ + mDNS *m = &mDNSStorage; + request_state* req = client_request_message; + DNSServer *ptr, **p = &m->DNSServers; + + while (req->replies) + { + reply_state *reply = req->replies; + req->replies = req->replies->next; + mDNSPlatformMemFree(reply); + } + mDNSPlatformMemFree(req); + + mDNSPlatformMemFree(local_socket); + + while (*p) + { + ptr = *p; + *p = (*p)->next; + LogInfo("FinalizeUnitTest: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c); + mDNSPlatformMemFree(ptr); + } +} + +- (void)testSuspiciousReplyTestSeries +{ + [self _clientQueryRequest]; + [self _verifySuspiciousResponseBehavior]; +} + +// Simulate a uds client request by setting up a client request and then +// calling mDNSResponder's handle_client_request. The handle_client_request function +// processes the request and starts a query. This unit test verifies +// the client request and query were setup as expected. This unit test also calls +// mDNS_execute which determines the cache does not contain the new question's +// answer. +- (void)_clientQueryRequest +{ + mDNS *const m = &mDNSStorage; + request_state* req = client_request_message; + char *msgptr = (char *)test_query_client_msgbuf; + size_t msgsz = sizeof(test_query_client_msgbuf); + mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4; + DNSQuestion *q; + mStatus err = mStatus_NoError; + char qname_cstr[MAX_ESCAPED_DOMAIN_NAME]; + + // Process the unit test's client request + start_client_request(req, msgptr, msgsz, query_request, local_socket); + XCTAssertEqual(err, mStatus_NoError); + + // Verify the request fields were set as expected + XCTAssertNil((__bridge id)req->next); + XCTAssertNil((__bridge id)req->primary); + XCTAssertEqual(req->sd, client_req_sd); + XCTAssertEqual(req->process_id, client_req_process_id); + XCTAssertFalse(strcmp(req->pid_name, client_req_pid_name)); + XCTAssertEqual(req->validUUID, mDNSfalse); + XCTAssertEqual(req->errsd, 0); + XCTAssertEqual(req->uid, client_req_uid); + XCTAssertEqual(req->ts, t_complete); + XCTAssertGreaterThan((mDNSs32)req->data_bytes, min_size); + XCTAssertEqual(req->msgend, msgptr+msgsz); + XCTAssertNil((__bridge id)(void*)req->msgbuf); + XCTAssertEqual(req->hdr.version, VERSION); + XCTAssertNil((__bridge id)req->replies); + XCTAssertNotEqual(req->terminate, (req_termination_fn)0); + XCTAssertEqual(req->flags, kDNSServiceFlagsReturnIntermediates); + XCTAssertEqual(req->interfaceIndex, kDNSServiceInterfaceIndexAny); + + // Verify the query fields were set as expected + q = &req->u.queryrecord.op.q; + XCTAssertNotEqual(q, (DNSQuestion *)mDNSNULL); + XCTAssertEqual(q, m->Questions); + XCTAssertEqual(q, m->NewQuestions); + XCTAssertEqual(q->SuppressUnusable, mDNSfalse); + XCTAssertEqual(q->ReturnIntermed, mDNStrue); + XCTAssertEqual(q->Suppressed, mDNSfalse); + + ConvertDomainNameToCString(&q->qname, qname_cstr); + XCTAssertFalse(strcmp(qname_cstr, test_original_domainname_cstr)); + XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname)); + + XCTAssertEqual(q->InterfaceID, mDNSInterface_Any); + XCTAssertEqual(q->flags, req->flags); + XCTAssertEqual(q->qtype, 1); + XCTAssertEqual(q->qclass, 1); + XCTAssertEqual(q->LongLived, 0); + XCTAssertEqual(q->ExpectUnique, mDNSfalse); + XCTAssertEqual(q->ForceMCast, 0); + XCTAssertEqual(q->TimeoutQuestion, 0); + XCTAssertEqual(q->WakeOnResolve, 0); + XCTAssertEqual(q->UseBackgroundTraffic, 0); + XCTAssertEqual(q->ValidationRequired, 0); + XCTAssertEqual(q->ValidatingResponse, 0); + XCTAssertEqual(q->ProxyQuestion, 0); + XCTAssertNotEqual((void*)q->QuestionCallback, (void*)mDNSNULL); + XCTAssertNil((__bridge id)q->DNSSECAuthInfo); + XCTAssertNil((__bridge id)(void*)q->DAIFreeCallback); + XCTAssertEqual(q->AppendSearchDomains, 0); + XCTAssertNil((__bridge id)q->DuplicateOf); + + // Call mDNS_Execute to see if the new question, q, has an answer in the cache. + // It won't be yet because the cache is empty. + m->NextScheduledEvent = mDNS_TimeNow_NoLock(m); + mDNS_Execute(m); + + // Verify mDNS_Execute processed the new question. + XCTAssertNil((__bridge id)m->NewQuestions); + + // Verify the cache is empty and the request got no reply. + XCTAssertEqual(m->rrcache_totalused, 0); + XCTAssertNil((__bridge id)req->replies); +} + +// This unit test tries to receive a response but changes the QID so it is ignored and can trigger suspicious mode +// 1) Test a suspicious response is ignored, but if it was previously requested, then don't go into suspicious mode +// 2) Test a suspicious response is ignored, and it does trigger suspicious mode +// 3) Test a configuration change event will reset suspicious mode +- (void)_verifySuspiciousResponseBehavior +{ + mDNS *const m = &mDNSStorage; + DNSMessage *msgptr = (DNSMessage *)test_query_response_msgbuf; + size_t msgsz = sizeof(test_query_response_msgbuf); + request_state* req = client_request_message; + mDNSOpaque16 suspiciousQID; + + // 1) + // Receive and verify it is suspicious (ignored response) + // But not too suspicious (did NOT go into suspicious mode) + + suspiciousQID.NotAnInteger = 0xDEAD; + receive_suspicious_response_ut(req, msgptr, msgsz, suspiciousQID, true); + + // Verify 0 records recevied + mDNSu32 CacheUsed =0, notUsed =0; + LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, ¬Used); + XCTAssertEqual(CacheUsed, 0); // Verify 0 records recevied + XCTAssertFalse(m->NextSuspiciousTimeout); // And NOT in suspicious mode + + // 2) + // Receive and verify it is suspicious (ignored response) + // And put itself in suspicious mode (did go into suspicious mode) + + receive_suspicious_response_ut(req, msgptr, msgsz, suspiciousQID, false); + LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, ¬Used); + XCTAssertEqual(CacheUsed, 0); // Verify 0 records recevied + XCTAssertTrue(m->NextSuspiciousTimeout); // And IS in suspicious mode + + // 3) + // Verify suspicious mode is stopped when a configuration change occurs. + + force_uDNS_SetupDNSConfig_ut(m); + XCTAssertFalse(m->NextSuspiciousTimeout); +} + + +@end diff --git a/mDNSMacOSX/Tests/mDNSCoreReceiveTest.m b/mDNSMacOSX/Tests/Unit Tests/mDNSCoreReceiveTest.m similarity index 99% rename from mDNSMacOSX/Tests/mDNSCoreReceiveTest.m rename to mDNSMacOSX/Tests/Unit Tests/mDNSCoreReceiveTest.m index e2c3245..96b546f 100644 --- a/mDNSMacOSX/Tests/mDNSCoreReceiveTest.m +++ b/mDNSMacOSX/Tests/Unit Tests/mDNSCoreReceiveTest.m @@ -152,7 +152,6 @@ mDNSlocal void InitmDNSStorage(mDNS *const m) XCTAssertEqual(m->MPktNum, 1); } - #if 0 - (void)testPerformanceExample { // This is an example of a performance test case. diff --git a/mDNSMacOSX/Tests/mDNSResponder.plist b/mDNSMacOSX/Tests/mDNSResponder.plist index 025d212..7c6d648 100644 --- a/mDNSMacOSX/Tests/mDNSResponder.plist +++ b/mDNSMacOSX/Tests/mDNSResponder.plist @@ -13,6 +13,25 @@ Tests + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName GAIPerf Advanced @@ -40,6 +59,25 @@ --skipPathEval + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery 1-1-1 @@ -77,6 +115,25 @@ --flushCache + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery 1-1-1 (No Additionals) @@ -115,6 +172,25 @@ --flushCache + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery 10-100-2 @@ -152,6 +228,25 @@ --flushCache + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery 10-100-2 (No Additionals) @@ -190,6 +285,25 @@ --flushCache + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery 100-500-2 @@ -227,6 +341,25 @@ --flushCache + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery 100-500-2 (No Additionals) @@ -265,6 +398,25 @@ --flushCache + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery 1-1-1 (No Cache Flush) @@ -301,6 +453,25 @@ json + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery 1-1-1 (No Cache Flush, No Additionals) @@ -338,6 +509,25 @@ --noAdditionals + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery 10-100-2 (No Cache Flush) @@ -374,6 +564,25 @@ json + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery 10-100-2 (No Cache Flush, No Additionals) @@ -411,6 +620,25 @@ --noAdditionals + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery 100-500-2 (No Cache Flush) @@ -447,6 +675,25 @@ json + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery 100-500-2 (No Cache Flush, No Additionals) @@ -484,6 +731,25 @@ json + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery w/Packet Drops 10 @@ -526,6 +792,25 @@ --flushCache + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName mDNS Discovery w/Packet Drops 100 @@ -568,6 +853,25 @@ --flushCache + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName DotLocal Queries @@ -592,6 +896,25 @@ json + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName Service Registration @@ -615,6 +938,25 @@ --bats + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName Probe Conflicts @@ -639,6 +981,25 @@ json + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName TCP Fallback @@ -667,6 +1028,25 @@ --badUDPMode + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName State Dump @@ -689,6 +1069,25 @@ /AppleInternal/Tests/mDNSResponder/bats_test_state_dump.sh + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName DNS Proxy @@ -708,6 +1107,25 @@ /AppleInternal/Tests/mDNSResponder/bats_test_proxy.sh + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName Expensive/Constrained Interface @@ -779,6 +1197,47 @@ Tests.xctest + + TestName + Fix Verification #1 + Description + Fix Verification #1 + AsRoot + + RequiresWiFi + + Timeout + 45 + IgnoreOutput + + Command + + /usr/local/bin/dnssdutil + verifyFix + earlyAWDL + --format + json + + + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + diff --git a/mDNSMacOSX/mDNSMacOSX.c b/mDNSMacOSX/mDNSMacOSX.c index 2c7ee95..3236966 100644 --- a/mDNSMacOSX/mDNSMacOSX.c +++ b/mDNSMacOSX/mDNSMacOSX.c @@ -5477,9 +5477,9 @@ mDNSlocal void SetLocalDomains(void) CFRelease(sa); } +#if !MDNSRESPONDER_SUPPORTS(APPLE, NO_WAKE_FOR_NET_ACCESS) mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val) { - CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_PowerSettings); if (!dict) { @@ -5492,8 +5492,8 @@ mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val) *val = 0; CFRelease(dict); } - } +#endif #if APPLE_OSX_mDNSResponder @@ -5998,14 +5998,13 @@ mDNSexport mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void) { +#if MDNSRESPONDER_SUPPORTS(APPLE, NO_WAKE_FOR_NET_ACCESS) + LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG, "SystemWakeForNetworkAccess: compile-time disabled"); + return ((mDNSu8)mDNS_NoWake); +#else mDNSs32 val = 0; mDNSu8 ret = (mDNSu8)mDNS_NoWake; -#if TARGET_OS_IOS - LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client always disabled on TARGET_OS_IOS"); - return ret; -#endif - if (DisableSleepProxyClient) { LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option"); @@ -6025,6 +6024,7 @@ mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void) LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret); return ret; +#endif } mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void) diff --git a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj index b89ec2c..8423ab6 100644 --- a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj +++ b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj @@ -257,6 +257,8 @@ B7473E981EC3C78300D31B9D /* _CNDomainBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA5E1D107573005E24CF /* _CNDomainBrowser.m */; }; B7473E991EC3C86600D31B9D /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; }; B74A96261DD4EDE60084A8C5 /* Preferences.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B74A96251DD4EDE60084A8C5 /* Preferences.framework */; }; + B74BF92E2322E97400E35354 /* SuspiciousReplyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B74BF92D2322E97400E35354 /* SuspiciousReplyTest.m */; }; + B74BF931232701F600E35354 /* CacheOrderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B74BF930232701F600E35354 /* CacheOrderTest.m */; }; B74F16F4211BA55400BEBE84 /* DNSMessageTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B74F16F3211BA55400BEBE84 /* DNSMessageTest.m */; }; B74F2B461E82FEAE0084960E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; }; B74F2B471E82FEFE0084960E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; }; @@ -306,6 +308,7 @@ B7D6CA7A1D107714005E24CF /* CNDomainBrowserView.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA691D1076C6005E24CF /* CNDomainBrowserView.m */; }; B7E06B0D1DBA9DFE00E4580C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; }; B7E06B0E1DBA9E9700E4580C /* DomainBrowser.strings in Resources */ = {isa = PBXBuildFile; fileRef = B7016F4F1D5D0D1900107E7C /* DomainBrowser.strings */; }; + B7E06CE12329B0480021401F /* LocalOnlyWithInterfacesTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B7E06CDF2329AA7B0021401F /* LocalOnlyWithInterfacesTest.m */; }; B7EEF7C1212601460093828F /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; }; B7EEF7C2212602EC0093828F /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; }; B7EEF7C4212603B20093828F /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD893CE4206C0D980055F9E7 /* SystemConfiguration.framework */; }; @@ -1002,6 +1005,8 @@ B7473E8A1EC395C300D31B9D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; B7473E8B1EC395C300D31B9D /* script.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = script.js; sourceTree = ""; }; B74A96251DD4EDE60084A8C5 /* Preferences.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Preferences.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.Internal.sdk/System/Library/PrivateFrameworks/Preferences.framework; sourceTree = DEVELOPER_DIR; }; + B74BF92D2322E97400E35354 /* SuspiciousReplyTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SuspiciousReplyTest.m; sourceTree = ""; }; + B74BF930232701F600E35354 /* CacheOrderTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CacheOrderTest.m; sourceTree = ""; }; B74EC1161D47FC7700A1D155 /* BonjourSettings.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BonjourSettings.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; B74EC11B1D47FC7800A1D155 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../SettingsBundle/Info.plist; sourceTree = ""; }; B74EC1271D494C5800A1D155 /* DomainBrowser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DomainBrowser.h; sourceTree = ""; }; @@ -1074,6 +1079,7 @@ B7D6CA681D1076C6005E24CF /* CNDomainBrowserView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNDomainBrowserView.h; sourceTree = ""; }; B7D6CA691D1076C6005E24CF /* CNDomainBrowserView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CNDomainBrowserView.m; sourceTree = ""; }; B7D6CA701D1076F3005E24CF /* DomainBrowser.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DomainBrowser.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B7E06CDF2329AA7B0021401F /* LocalOnlyWithInterfacesTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LocalOnlyWithInterfacesTest.m; sourceTree = ""; }; BD03E88C1AD31278005E8A81 /* SymptomReporter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SymptomReporter.c; sourceTree = ""; }; BD11266D21DB1AFE006115E6 /* dnssd_xpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dnssd_xpc.h; sourceTree = ""; }; BD11266E21DB1AFE006115E6 /* dnssd_xpc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dnssd_xpc.c; sourceTree = ""; }; @@ -1722,6 +1728,23 @@ name = "Supporting Files"; sourceTree = ""; }; + B74BF92F2322E99700E35354 /* Unit Tests */ = { + isa = PBXGroup; + children = ( + B74F16EF2114E49D00BEBE84 /* Info.plist */, + B7A86198212B074500E81CC3 /* LocalOnlyTimeoutTest.m */, + B7A861962127845700E81CC3 /* CNameRecordTest.m */, + B7A8618A21274FA200E81CC3 /* mDNSCoreReceiveTest.m */, + B7A8618821274BFC00E81CC3 /* ResourceRecordTest.m */, + B74F16F3211BA55400BEBE84 /* DNSMessageTest.m */, + D459F0D3222862BA0056AC5B /* HelperFunctionTest.m */, + B74BF92D2322E97400E35354 /* SuspiciousReplyTest.m */, + B74BF930232701F600E35354 /* CacheOrderTest.m */, + B7E06CDF2329AA7B0021401F /* LocalOnlyWithInterfacesTest.m */, + ); + path = "Unit Tests"; + sourceTree = ""; + }; B74EC11A1D47FC7800A1D155 /* SettingsBundle */ = { isa = PBXGroup; children = ( @@ -1743,16 +1766,10 @@ B74F16EC2114E49D00BEBE84 /* Tests */ = { isa = PBXGroup; children = ( - B74F16EF2114E49D00BEBE84 /* Info.plist */, BD98A796213A3EAE0002EC47 /* mDNSResponder.plist */, - B7A86198212B074500E81CC3 /* LocalOnlyTimeoutTest.m */, - B7A861962127845700E81CC3 /* CNameRecordTest.m */, - B7A8618A21274FA200E81CC3 /* mDNSCoreReceiveTest.m */, - B7A8618821274BFC00E81CC3 /* ResourceRecordTest.m */, - B74F16F3211BA55400BEBE84 /* DNSMessageTest.m */, - D459F0D3222862BA0056AC5B /* HelperFunctionTest.m */, D448F7A6222DA98E0069E1D2 /* BATS Scripts */, 37DDE9241BA382280092AC61 /* Unit Test Utilities */, + B74BF92F2322E99700E35354 /* Unit Tests */, ); path = Tests; sourceTree = ""; @@ -3177,7 +3194,9 @@ files = ( 898E98392203633800812DC6 /* dnssd_clientshim.c in Sources */, D459F0D4222862BA0056AC5B /* HelperFunctionTest.m in Sources */, + B74BF931232701F600E35354 /* CacheOrderTest.m in Sources */, 898E983A2203633800812DC6 /* dso-transport.c in Sources */, + B7E06CE12329B0480021401F /* LocalOnlyWithInterfacesTest.m in Sources */, 898E983B2203633800812DC6 /* dso.c in Sources */, B7EEF7C1212601460093828F /* mDNSMacOSX.c in Sources */, B7EEF7CC212604A80093828F /* LegacyNATTraversal.c in Sources */, @@ -3186,6 +3205,7 @@ B7EEF7D6212606F50093828F /* uDNSPathEvalulation.c in Sources */, B7EEF7EA212613260093828F /* uds_daemon.c in Sources */, B7A861952127806600E81CC3 /* unittest_common.c in Sources */, + B74BF92E2322E97400E35354 /* SuspiciousReplyTest.m in Sources */, B7EEF7E921260E4C0093828F /* CryptoSupport.c in Sources */, B7EEF7D9212607C40093828F /* nsec.c in Sources */, D40123912272B6E3006C9BBE /* mdns_object.m in Sources */, @@ -4930,6 +4950,7 @@ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; @@ -4954,7 +4975,7 @@ "$(SDKROOT)/usr/include/libxml2", "${CONFIGURATION_TEMP_DIR}", ); - INFOPLIST_FILE = Tests/Info.plist; + INFOPLIST_FILE = "Tests/Unit Tests/Info.plist"; INSTALL_PATH = /AppleInternal/XCTests/com.apple.mDNSResponder/; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MTL_FAST_MATH = YES; @@ -5011,6 +5032,7 @@ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -5035,7 +5057,7 @@ "$(SDKROOT)/usr/include/libxml2", "${CONFIGURATION_TEMP_DIR}", ); - INFOPLIST_FILE = Tests/Info.plist; + INFOPLIST_FILE = "Tests/Unit Tests/Info.plist"; INSTALL_PATH = /AppleInternal/XCTests/com.apple.mDNSResponder/; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MTL_FAST_MATH = YES; diff --git a/mDNSShared/dns_sd.h b/mDNSShared/dns_sd.h index 9132306..f208d28 100644 --- a/mDNSShared/dns_sd.h +++ b/mDNSShared/dns_sd.h @@ -66,7 +66,7 @@ */ #ifndef _DNS_SD_H -#define _DNS_SD_H 10960002 +#define _DNS_SD_H 10964007 #ifdef __cplusplus extern "C" { diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c index e6224a2..1982982 100644 --- a/mDNSShared/uds_daemon.c +++ b/mDNSShared/uds_daemon.c @@ -541,10 +541,6 @@ mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, i LogMsg("ERROR: Bad resource record flags (must be one of either kDNSServiceFlagsShared, kDNSServiceFlagsUnique or kDNSServiceFlagsKnownUnique)"); return NULL; } - - rr = (AuthRecord *) callocL("AuthRecord/read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size); - if (!rr) FatalError("ERROR: calloc"); - InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex); // The registration is scoped to a specific interface index, but the interface is not currently on our list. @@ -561,6 +557,9 @@ mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, i return NULL; #endif } + rr = (AuthRecord *) callocL("AuthRecord/read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size); + if (!rr) FatalError("ERROR: calloc"); + if (InterfaceID == mDNSInterface_LocalOnly) artype = AuthRecordLocalOnly; else if (InterfaceID == mDNSInterface_P2P || InterfaceID == mDNSInterface_BLE) diff --git a/unittests/unittest_common.c b/unittests/unittest_common.c index 774b8e9..66216c4 100644 --- a/unittests/unittest_common.c +++ b/unittests/unittest_common.c @@ -117,6 +117,48 @@ mDNSexport void receive_response(const request_state* req, DNSMessage *msg, size mDNSCoreReceive(m, msg, end, &srcaddr, srcport, &primary_v4, dstport, primary_interfaceID); } +mDNSexport void receive_suspicious_response_ut(const request_state* req, DNSMessage *msg, size_t msgSize, mDNSOpaque16 suspiciousqid, mDNSBool goodLastQID) +{ + mDNS *m = &mDNSStorage; + mDNSAddr srcaddr; + mDNSIPPort srcport, dstport; + const mDNSu8 * end; + DNSQuestion *q = (DNSQuestion *)&req->u.queryrecord.op.q; + UInt8* data = (UInt8*)msg; + + // Used same values for DNS server as specified during init of unit test + srcaddr.type = mDNSAddrType_IPv4; + srcaddr.ip.v4.NotAnInteger = dns_server_ipv4.NotAnInteger; + srcport.NotAnInteger = client_resp_src_port; + + // Used random value for dstport + dstport.NotAnInteger = swap16((mDNSu16)client_resp_dst_port); + + // Set DNS message (that was copied from a WireShark packet) + end = (const mDNSu8 *)msg + msgSize; + + // Set socket info that mDNSCoreReceive uses to verify socket context + q->LocalSocket->ss.port.NotAnInteger = swap16((mDNSu16)client_resp_dst_port); + if (suspiciousqid.NotAnInteger) + { + q->TargetQID.NotAnInteger = swap16(suspiciousqid.NotAnInteger); + if (goodLastQID) + { + q->LastTargetQID.b[0] = data[0]; + q->LastTargetQID.b[1] = data[1]; + } + else q->LastTargetQID.NotAnInteger = 0; + } + else + { + q->TargetQID.b[0] = data[0]; + q->TargetQID.b[1] = data[1]; + } + + // Execute mDNSCoreReceive which copies two DNS records into the cache + mDNSCoreReceive(m, msg, end, &srcaddr, srcport, &primary_v4, dstport, primary_interfaceID); +} + mDNSexport size_t get_reply_len(char* name, uint16_t rdlen) { size_t len = sizeof(DNSServiceFlags); @@ -156,7 +198,7 @@ mDNSexport void get_ip(const char *const name, struct sockaddr_storage *result) } // The AddDNSServer_ut function adds a dns server to mDNSResponder's list. -mDNSexport mStatus AddDNSServer_ut(void) +mDNSexport mStatus AddDNSServerScoped_ut(mDNSInterfaceID interfaceID, ScopeType scoped) { mDNS *m = &mDNSStorage; m->timenow = 0; @@ -165,7 +207,6 @@ mDNSexport mStatus AddDNSServer_ut(void) mDNSAddr addr; mDNSIPPort port; mDNSs32 serviceID = 0; - mDNSu32 scoped = 0; mDNSu32 timeout = dns_server_timeout; mDNSBool cellIntf = 0; mDNSBool isExpensive = 0; @@ -179,9 +220,48 @@ mDNSexport mStatus AddDNSServer_ut(void) addr.type = mDNSAddrType_IPv4; addr.ip.v4.NotAnInteger = dns_server_ipv4.NotAnInteger; port.NotAnInteger = client_resp_src_port; - mDNS_AddDNSServer(m, &d, primary_interfaceID, serviceID, &addr, port, scoped, timeout, + mDNS_AddDNSServer(m, &d, interfaceID, serviceID, &addr, port, scoped, timeout, cellIntf, isExpensive, isConstrained, isCLAT46, resGroupID, reqA, reqAAAA, reqDO); mDNS_Unlock(m); return mStatus_NoError; } + +mDNSexport mStatus AddDNSServer_ut(void) +{ + return AddDNSServerScoped_ut(primary_interfaceID, kScopeNone); +} + +mDNSexport mStatus force_uDNS_SetupDNSConfig_ut(mDNS *const m) +{ + m->p->LastConfigGeneration = 0; + return uDNS_SetupDNSConfig(m); +} + +mDNSexport mStatus verify_cache_addr_order_for_domain_ut(mDNS *const m, mDNSu8* octet, mDNSu32 count, const domainname *const name) +{ + mStatus result = mStatus_NoError; + const CacheGroup *cg = CacheGroupForName(m, DomainNameHashValue(name), name); + if (cg) + { + mDNSu32 i; + CacheRecord **rp = (CacheRecord **)&cg->members; + for (i = 0 ; *rp && i < count ; i++ ) + { + if ((*rp)->resrec.rdata->u.ipv4.b[3] != octet[i]) + { + LogInfo ("Octet %d compare failed %d != %d", i, (*rp)->resrec.rdata->u.ipv4.b[3], octet[i]); + break; + } + rp = &(*rp)->next; + } + if (i != count) result = mStatus_Invalid; + } + else + { + LogInfo ("Cache group not found"); + result = mStatus_Invalid; + } + + return result; +} diff --git a/unittests/unittest_common.h b/unittests/unittest_common.h index b22c104..3ab4b4f 100644 --- a/unittests/unittest_common.h +++ b/unittests/unittest_common.h @@ -37,6 +37,7 @@ extern mStatus init_mdns_storage(void); extern size_t get_reply_len(char* name, uint16_t rdlen); extern mStatus start_client_request(request_state* req, char *msgbuf, size_t msgsz, uint32_t op, UDPSocket* socket); extern void receive_response(const request_state* req, DNSMessage *msg, size_t msgSize); +extern void receive_suspicious_response_ut(const request_state* req, DNSMessage *msg, size_t msgSize, mDNSOpaque16 suspiciousqid, mDNSBool goodLastQID); extern void get_ip(const char *const name, struct sockaddr_storage *result); extern void free_req(request_state* req); @@ -53,6 +54,9 @@ extern mDNSBool mDNSMacOSXCreateEtcHostsEntry_ut(const domainname *domain, const const domainname *cname, char *ifname, AuthHash *auth); extern void UpdateEtcHosts_ut(void *context); extern mStatus AddDNSServer_ut(void); +extern mStatus AddDNSServerScoped_ut(mDNSInterfaceID interfaceID, ScopeType scoped); +extern mStatus force_uDNS_SetupDNSConfig_ut(mDNS *const m); +extern mStatus verify_cache_addr_order_for_domain_ut(mDNS *const m, mDNSu8* octet, mDNSu32 count, const domainname *const name); // HelperFunctionTest extern void mDNSDomainLabelFromCFString_ut(CFStringRef cfs, domainlabel *const namelabel); -- 2.45.2