147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt/* -*- Mode: C; tab-width: 4 -*- 247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved. 447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Licensed under the Apache License, Version 2.0 (the "License"); 647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * you may not use this file except in compliance with the License. 747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * You may obtain a copy of the License at 847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * http://www.apache.org/licenses/LICENSE-2.0 1047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 1147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Unless required by applicable law or agreed to in writing, software 1247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * distributed under the License is distributed on an "AS IS" BASIS, 1347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * See the License for the specific language governing permissions and 1547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * limitations under the License. 1647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 1747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * This code is completely 100% portable C. It does not depend on any external header files 1847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * from outside the mDNS project -- all the types it expects to find are defined right here. 1947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * 2047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * The previous point is very important: This file does not depend on any external 2147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * header files. It should compile on *any* platform that has a C compiler, without 2247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * making *any* assumptions about availability of so-called "standard" C functions, 2347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * routines, or types (which may or may not be present on any given platform). 2447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 2547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Formatting notes: 2647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion 2747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>, 2847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * but for the sake of brevity here I will say just this: Curly braces are not syntactially 2947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * part of an "if" statement; they are the beginning and ending markers of a compound statement; 3047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * therefore common sense dictates that if they are part of a compound statement then they 3147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * should be indented to the same level as everything else in that compound statement. 3247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Indenting curly braces at the same level as the "if" implies that curly braces are 3347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * part of the "if", which is false. (This is as misleading as people who write "char* x,y;" 3447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * thinking that variables x and y are both of type "char*" -- and anyone who doesn't 3547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * understand why variable y is not of type "char*" just proves the point that poor code 3647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * layout leads people to unfortunate misunderstandings about how the C language really works.) 3747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt */ 3847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 3947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "DNSCommon.h" // Defines general DNS untility routines 4047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "uDNS.h" // Defines entry points into unicast-specific routines 4147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 4247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Disable certain benign warnings with Microsoft compilers 4347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if(defined(_MSC_VER)) 4447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Disable "conditional expression is constant" warning for debug macros. 4547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Otherwise, this generates warnings for the perfectly natural construct "while(1)" 4647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know 4747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #pragma warning(disable:4127) 4847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 4947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Disable "assignment within conditional expression". 5047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Other compilers understand the convention that if you place the assignment expression within an extra pair 5147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary. 5247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal 5347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to the compiler that the assignment is intentional, we have to just turn this warning off completely. 5447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #pragma warning(disable:4706) 5547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 5647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 5747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder 5847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 5947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <WebFilterDNS/WebFilterDNS.h> 6047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 6147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ! NO_WCF 6247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltWCFConnection *WCFConnectionNew(void) __attribute__((weak_import)); 6347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import)); 6447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 6547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Do we really need to define a macro for "if"? 6647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define CHECK_WCF_FUNCTION(X) if (X) 6747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif // ! NO_WCF 6847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 6947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#else 7047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 7147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define NO_WCF 1 7247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif // APPLE_OSX_mDNSResponder 7347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 7447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Forward declarations 7547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void BeginSleepProcessing(mDNS *const m); 7647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void RetrySPSRegistrations(mDNS *const m); 7747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password); 7847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q); 7947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q); 8047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q); 8147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 8247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// *************************************************************************** 8347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK 8447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Program Constants 8547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 8647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 8747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define NO_HINFO 1 8847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 8947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 9047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any records bigger than this are considered 'large' records 9147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define SmallRecordLimit 1024 9247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 9347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define kMaxUpdateCredits 10 9447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6) 9547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 9647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const char *const mDNS_DomainTypeNames[] = 9747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 9847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "b._dns-sd._udp.", // Browse 9947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "db._dns-sd._udp.", // Default Browse 10047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "lb._dns-sd._udp.", // Automatic Browse 10147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "r._dns-sd._udp.", // Registration 10247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "dr._dns-sd._udp." // Default Registration 10347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt }; 10447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 10547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifdef UNICAST_DISABLED 10647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define uDNS_IsActiveQuery(q, u) mDNSfalse 10747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 10847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 10947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// *************************************************************************** 11047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK 11147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - 11247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - General Utility Functions 11347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 11447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 11547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If there is a authoritative LocalOnly record that answers questions of type A, AAAA and CNAME 11647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// this returns true. Main use is to handle /etc/hosts records. 11747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define LORecordAnswersAddressType(rr) ((rr)->ARType == AuthRecordLocalOnly && \ 11847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rr)->resrec.RecordType & kDNSRecordTypeUniqueMask && \ 11947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((rr)->resrec.rrtype == kDNSType_A || (rr)->resrec.rrtype == kDNSType_AAAA || \ 12047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rr)->resrec.rrtype == kDNSType_CNAME)) 12147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 12247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define FollowCNAME(q, rr, AddRecord) (AddRecord && (q)->qtype != kDNSType_CNAME && \ 12347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rr)->RecordType != kDNSRecordTypePacketNegative && \ 12447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rr)->rrtype == kDNSType_CNAME) 12547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 12647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SetNextQueryStopTime(mDNS *const m, const DNSQuestion *const q) 12747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 12847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->mDNS_busy != m->mDNS_reentrancy+1) 12947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); 13047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 13147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ForceAlerts 13247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0; 13347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 13447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 13547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextScheduledStopTime - q->StopTime > 0) 13647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledStopTime = q->StopTime; 13747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 13847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 13947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q) 14047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 14147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->mDNS_busy != m->mDNS_reentrancy+1) 14247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); 14347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 14447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ForceAlerts 14547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0; 14647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 14747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 14847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ActiveQuestion(q)) 14947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 15047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Depending on whether this is a multicast or unicast question we want to set either: 15147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // m->NextScheduledQuery = NextQSendTime(q) or 15247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // m->NextuDNSEvent = NextQSendTime(q) 15347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 *const timer = mDNSOpaque16IsZero(q->TargetQID) ? &m->NextScheduledQuery : &m->NextuDNSEvent; 15447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*timer - NextQSendTime(q) > 0) 15547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *timer = NextQSendTime(q); 15647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 15747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 15847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 15947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ReleaseAuthEntity(AuthHash *r, AuthEntity *e) 16047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 16147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 16247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt unsigned int i; 16347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF; 16447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 16547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt e->next = r->rrauth_free; 16647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r->rrauth_free = e; 16747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r->rrauth_totalused--; 16847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 16947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 17047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ReleaseAuthGroup(AuthHash *r, AuthGroup **cp) 17147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 17247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthEntity *e = (AuthEntity *)(*cp); 17347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("ReleaseAuthGroup: Releasing AuthGroup %##s", (*cp)->name->c); 17447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((*cp)->rrauth_tail != &(*cp)->members) 17547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrauth_tail != &(*cp)->members)"); 17647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name); 17747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (*cp)->name = mDNSNULL; 17847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *cp = (*cp)->next; // Cut record from list 17947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ReleaseAuthEntity(r, e); 18047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 18147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 18247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal AuthEntity *GetAuthEntity(AuthHash *r, const AuthGroup *const PreserveAG) 18347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 18447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthEntity *e = mDNSNULL; 18547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 18647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r->rrauth_lock) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); } 18747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r->rrauth_lock = 1; 18847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 18947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!r->rrauth_free) 19047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 19147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We allocate just one AuthEntity at a time because we need to be able 19247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // free them all individually which normally happens when we parse /etc/hosts into 19347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // AuthHash where we add the "new" entries and discard (free) the already added 19447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // entries. If we allocate as chunks, we can't free them individually. 19547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthEntity *storage = mDNSPlatformMemAllocate(sizeof(AuthEntity)); 19647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt storage->next = mDNSNULL; 19747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r->rrauth_free = storage; 19847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 19947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 20047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we still have no free records, recycle all the records we can. 20147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Enumerating the entire auth is moderately expensive, so when we do it, we reclaim all the records we can in one pass. 20247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!r->rrauth_free) 20347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 20447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 oldtotalused = r->rrauth_totalused; 20547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 20647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) 20747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 20847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup **cp = &r->rrauth_hash[slot]; 20947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*cp) 21047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 21147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((*cp)->members || (*cp)==PreserveAG) cp=&(*cp)->next; 21247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else ReleaseAuthGroup(r, cp); 21347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 21447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 21547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("GetAuthEntity: Recycled %d records to reduce auth cache from %d to %d", 21647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt oldtotalused - r->rrauth_totalused, oldtotalused, r->rrauth_totalused); 21747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 21847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 21947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r->rrauth_free) // If there are records in the free list, take one 22047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 22147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt e = r->rrauth_free; 22247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r->rrauth_free = e->next; 22347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (++r->rrauth_totalused >= r->rrauth_report) 22447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 22547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("RR Auth now using %ld objects", r->rrauth_totalused); 22647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r->rrauth_report < 100) r->rrauth_report += 10; 22747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (r->rrauth_report < 1000) r->rrauth_report += 100; 22847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else r->rrauth_report += 1000; 22947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 23047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemZero(e, sizeof(*e)); 23147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 23247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 23347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r->rrauth_lock = 0; 23447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 23547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(e); 23647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 23747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 23847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name) 23947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 24047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *ag; 24147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (ag = r->rrauth_hash[slot]; ag; ag=ag->next) 24247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ag->namehash == namehash && SameDomainName(ag->name, name)) 24347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 24447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(ag); 24547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 24647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 24747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport AuthGroup *AuthGroupForRecord(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr) 24847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 24947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(AuthGroupForName(r, slot, rr->namehash, rr->name)); 25047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 25147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 25247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr) 25347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 25447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu16 namelen = DomainNameLength(rr->name); 25547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *ag = (AuthGroup*)GetAuthEntity(r, mDNSNULL); 25647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ag) { LogMsg("GetAuthGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); } 25747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag->next = r->rrauth_hash[slot]; 25847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag->namehash = rr->namehash; 25947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag->members = mDNSNULL; 26047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag->rrauth_tail = &ag->members; 26147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag->name = (domainname*)ag->namestorage; 26247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag->NewLocalOnlyRecords = mDNSNULL; 26347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (namelen > InlineCacheGroupNameSize) ag->name = mDNSPlatformMemAllocate(namelen); 26447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ag->name) 26547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 26647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("GetAuthGroup: Failed to allocate name storage for %##s", rr->name->c); 26747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ReleaseAuthEntity(r, (AuthEntity*)ag); 26847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSNULL); 26947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 27047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(ag->name, rr->name); 27147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 27247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (AuthGroupForRecord(r, slot, rr)) LogMsg("GetAuthGroup: Already have AuthGroup for %##s", rr->name->c); 27347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r->rrauth_hash[slot] = ag; 27447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (AuthGroupForRecord(r, slot, rr) != ag) LogMsg("GetAuthGroup: Not finding AuthGroup for %##s", rr->name->c); 27547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 27647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(ag); 27747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 27847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 27947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Returns the AuthGroup in which the AuthRecord was inserted 28047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr) 28147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 28247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *ag; 28347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = AuthHashSlot(rr->resrec.name); 28447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag = AuthGroupForRecord(r, slot, &rr->resrec); 28547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ag) ag = GetAuthGroup(r, slot, &rr->resrec); // If we don't have a AuthGroup for this name, make one now 28647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ag) 28747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 28847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("InsertAuthRecord: inserting auth record %s from table", ARDisplayString(m, rr)); 28947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *(ag->rrauth_tail) = rr; // Append this record to tail of cache slot list 29047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag->rrauth_tail = &(rr->next); // Advance tail pointer 29147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 29247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return ag; 29347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 29447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 29547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr) 29647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 29747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *a; 29847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup **ag = &a; 29947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord **rp; 30047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = AuthHashSlot(rr->resrec.name); 30147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 30247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt a = AuthGroupForRecord(r, slot, &rr->resrec); 30347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!a) { LogMsg("RemoveAuthRecord: ERROR!! AuthGroup not found for %s", ARDisplayString(m, rr)); return mDNSNULL; } 30447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp = &(*ag)->members; 30547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*rp) 30647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 30747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*rp != rr) 30847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp=&(*rp)->next; 30947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 31047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 31147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We don't break here, so that we can set the tail below without tracking "prev" pointers 31247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 31347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("RemoveAuthRecord: removing auth record %s from table", ARDisplayString(m, rr)); 31447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *rp = (*rp)->next; // Cut record from list 31547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 31647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 31747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // TBD: If there are no more members, release authgroup ? 31847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (*ag)->rrauth_tail = rp; 31947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return a; 32047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 32147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 32247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name) 32347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 32447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg; 32547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (cg = m->rrcache_hash[slot]; cg; cg=cg->next) 32647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cg->namehash == namehash && SameDomainName(cg->name, name)) 32747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 32847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(cg); 32947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 33047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 33147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr) 33247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 33347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(CacheGroupForName(m, slot, rr->namehash, rr->name)); 33447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 33547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 33647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr) 33747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 33847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf; 33947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 34047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (addr->type == mDNSAddrType_IPv4) 34147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 34247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception 34347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSv4AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue); 34447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = m->HostInterfaces; intf; intf = intf->next) 34547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) 34647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0) 34747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNStrue); 34847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 34947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 35047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (addr->type == mDNSAddrType_IPv6) 35147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 35247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSv6AddressIsLinkLocal(&addr->ip.v6)) return(mDNStrue); 35347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = m->HostInterfaces; intf; intf = intf->next) 35447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) 35547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) && 35647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) && 35747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) && 35847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0)) 35947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNStrue); 36047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 36147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 36247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSfalse); 36347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 36447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 36547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID) 36647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 36747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf = m->HostInterfaces; 36847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (intf && intf->InterfaceID != InterfaceID) intf = intf->next; 36947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(intf); 37047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 37147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 37247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID) 37347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 37447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); 37547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(intf ? intf->ifname : mDNSNULL); 37647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 37747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 37847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Caller should hold the lock 37947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void GenerateNegativeResponse(mDNS *const m) 38047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 38147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 38247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->CurrentQuestion) { LogMsg("GenerateNegativeResponse: ERROR!! CurrentQuestion not set"); return; } 38347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q = m->CurrentQuestion; 38447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("GenerateNegativeResponse: Generating negative response for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 38547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 38647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, mDNSNULL); 38747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache); 38847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion == q) { q->ThisQInterval = 0; } // Deactivate this question 38947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't touch the question after this 39047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 39147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 39247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 39347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, ResourceRecord *rr) 39447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 39547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSBool selfref = SameDomainName(&q->qname, &rr->rdata->u.name); 39647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->CNAMEReferrals >= 10 || selfref) 39747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("AnswerQuestionByFollowingCNAME: %p %##s (%s) NOT following CNAME referral %d%s for %s", 39847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", RRDisplayString(m, rr)); 39947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 40047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 40147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 c = q->CNAMEReferrals + 1; // Stash a copy of the new q->CNAMEReferrals value 40247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 40347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The SameDomainName check above is to ignore bogus CNAME records that point right back at 40447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // themselves. Without that check we can get into a case where we have two duplicate questions, 40547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // A and B, and when we stop question A, UpdateQuestionDuplicates copies the value of CNAMEReferrals 40647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // from A to B, and then A is re-appended to the end of the list as a duplicate of B (because 40747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the target name is still the same), and then when we stop question B, UpdateQuestionDuplicates 40847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // copies the B's value of CNAMEReferrals back to A, and we end up not incrementing CNAMEReferrals 40947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // for either of them. This is not a problem for CNAME loops of two or more records because in 41047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // those cases the newly re-appended question A has a different target name and therefore cannot be 41147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // a duplicate of any other question ('B') which was itself a duplicate of the previous question A. 41247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 41347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect, 41447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and track CNAMEs coming and going, we should really create a subordinate query here, 41547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which we would subsequently cancel and retract if the CNAME referral record were removed. 41647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In reality this is such a corner case we'll ignore it until someone actually needs it. 41747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 41847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("AnswerQuestionByFollowingCNAME: %p %##s (%s) following CNAME referral %d for %s", 41947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, RRDisplayString(m, rr)); 42047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 42147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopQuery_internal(m, q); // Stop old query 42247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&q->qname, &rr->rdata->u.name); // Update qname 42347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qnamehash = DomainNameHashValue(&q->qname); // and namehash 42447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If a unicast query results in a CNAME that points to a .local, we need to re-try 42547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // this as unicast. Setting the mDNSInterface_Unicast tells mDNS_StartQuery_internal 42647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to try this as unicast query even though it is a .local name 42747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(q->TargetQID) && IsLocalDomain(&q->qname)) 42847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 42947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("AnswerQuestionByFollowingCNAME: Resolving a .local CNAME %p %##s (%s) Record %s", 43047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q, q->qname.c, DNSTypeName(q->qtype), RRDisplayString(m, rr)); 43147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->InterfaceID = mDNSInterface_Unicast; 43247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 43347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StartQuery_internal(m, q); // start new query 43447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Record how many times we've done this. We need to do this *after* mDNS_StartQuery_internal, 43547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero 43647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->CNAMEReferrals = c; 43747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 43847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 43947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 44047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// For a single given DNSQuestion pointed to by CurrentQuestion, deliver an add/remove result for the single given AuthRecord 44147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: All the callers should use the m->CurrentQuestion to see if the question is still valid or not 44247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) 44347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 44447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q = m->CurrentQuestion; 44547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool followcname; 44647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 44747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q) 44847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 44947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("AnswerLocalQuestionWithLocalAuthRecord: ERROR!! CurrentQuestion NULL while answering with %s", ARDisplayString(m, rr)); 45047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 45147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 45247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 45347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt followcname = FollowCNAME(q, &rr->resrec, AddRecord); 45447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 45547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We should not be delivering results for record types Unregistered, Deregistering, and (unverified) Unique 45647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!(rr->resrec.RecordType & kDNSRecordTypeActiveMask)) 45747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 45847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("AnswerLocalQuestionWithLocalAuthRecord: *NOT* delivering %s event for local record type %X %s", 45947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AddRecord ? "Add" : "Rmv", rr->resrec.RecordType, ARDisplayString(m, rr)); 46047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 46147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 46247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 46347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it 46447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (AddRecord) rr->AnsweredLocalQ = mDNStrue; 46547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 46647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->QuestionCallback && !q->NoAnswer) 46747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 46847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->CurrentAnswers += AddRecord ? 1 : -1; 46947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (LORecordAnswersAddressType(rr)) 47047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 47147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!followcname || q->ReturnIntermed) 47247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 47347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't send this packet on the wire as we answered from /etc/hosts 47447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval = 0; 47547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LOAddressAnswers += AddRecord ? 1 : -1; 47647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->QuestionCallback(m, q, &rr->resrec, AddRecord); 47747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 47847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 47947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The callback above could have caused the question to stop. Detect that 48047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // using m->CurrentQuestion 48147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (followcname && m->CurrentQuestion == q) 48247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerQuestionByFollowingCNAME(m, q, &rr->resrec); 48347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 48447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 48547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 48647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->QuestionCallback(m, q, &rr->resrec, AddRecord); 48747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 48847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 48947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 49047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 49147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) 49247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 49347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 49447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("AnswerInterfaceAnyQuestionsWithLocalAuthRecord: ERROR m->CurrentQuestion already set: %##s (%s)", 49547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 49647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = m->Questions; 49747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 49847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 49947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool answered; 50047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q = m->CurrentQuestion; 50147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRAny(rr)) 50247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt answered = ResourceRecordAnswersQuestion(&rr->resrec, q); 50347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 50447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt answered = LocalOnlyRecordAnswersQuestion(rr, q); 50547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (answered) 50647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again 50747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 50847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = q->next; 50947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 51047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 51147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 51247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 51347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord() 51447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// delivers the appropriate add/remove events to listening questions: 51547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 1. It runs though all our LocalOnlyQuestions delivering answers as appropriate, 51647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion(). 51747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 2. If the AuthRecord is marked mDNSInterface_LocalOnly or mDNSInterface_P2P, then it also runs though 51847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// our main question list, delivering answers to mDNSInterface_Any questions as appropriate, 51947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// stopping if it reaches a NewQuestion -- brand-new questions are handled by AnswerNewQuestion(). 52047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 52147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// AnswerAllLocalQuestionsWithLocalAuthRecord is used by the m->NewLocalRecords loop in mDNS_Execute(), 52247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// and by mDNS_Deregister_internal() 52347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 52447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) 52547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 52647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 52747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)", 52847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 52947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 53047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = m->LocalOnlyQuestions; 53147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions) 53247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 53347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool answered; 53447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q = m->CurrentQuestion; 53547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We are called with both LocalOnly/P2P record or a regular AuthRecord 53647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRAny(rr)) 53747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt answered = ResourceRecordAnswersQuestion(&rr->resrec, q); 53847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 53947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt answered = LocalOnlyRecordAnswersQuestion(rr, q); 54047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (answered) 54147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again 54247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 54347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = q->next; 54447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 54547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 54647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 54747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 54847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this AuthRecord is marked LocalOnly or P2P, then we want to deliver it to all local 'mDNSInterface_Any' questions 54947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P) 55047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerInterfaceAnyQuestionsWithLocalAuthRecord(m, rr, AddRecord); 55147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 55247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 55347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 55447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// *************************************************************************** 55547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK 55647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - 55747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Resource Record Utility Functions 55847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 55947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 56047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA) 56147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 56247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \ 56347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \ 56447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \ 56547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) ) 56647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 56747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \ 56847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (ResourceRecordIsValidAnswer(RR) && \ 56947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID))) 57047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 57147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define DefaultProbeCountForTypeUnique ((mDNSu8)3) 57247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0) 57347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 57447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define InitialAnnounceCount ((mDNSu8)8) 57547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 57647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// For goodbye packets we set the count to 3, and for wakeups we set it to 18 57747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (which will be up to 15 wakeup attempts over the course of 30 seconds, 57847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// and then if the machine fails to wake, 3 goodbye packets). 57947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define GoodbyeCount ((mDNSu8)3) 58047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define WakeupCount ((mDNSu8)18) 58147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 58247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Number of wakeups we send if WakeOnResolve is set in the question 58347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define InitialWakeOnResolveCount ((mDNSu8)3) 58447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 58547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not. 58647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// This means that because the announce interval is doubled after sending the first packet, the first 58747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// observed on-the-wire inter-packet interval between announcements is actually one second. 58847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent. 58947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4) 59047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2) 59147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2) 59247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 59347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define DefaultAPIntervalForRecordType(X) ((X) & kDNSRecordTypeActiveSharedMask ? DefaultAnnounceIntervalForTypeShared : \ 59447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (X) & kDNSRecordTypeUnique ? DefaultProbeIntervalForTypeUnique : \ 59547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (X) & kDNSRecordTypeActiveUniqueMask ? DefaultAnnounceIntervalForTypeUnique : 0) 59647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 59747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0) 59847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR)) 59947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond) 60047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR)) 60147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 60247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define MaxUnansweredQueries 4 60347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 60447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent 60547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match). 60647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// TTL and rdata may differ. 60747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// This is used for cache flush management: 60847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent 60947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed 61047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 61147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match 61247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 61347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B)) 61447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 61547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool SameResourceRecordNameClassInterface(const AuthRecord *const r1, const AuthRecord *const r2) 61647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 61747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); } 61847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); } 61947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r1->resrec.InterfaceID && 62047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->resrec.InterfaceID && 62147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r1->resrec.InterfaceID != r2->resrec.InterfaceID) return(mDNSfalse); 62247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSBool)( 62347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r1->resrec.rrclass == r2->resrec.rrclass && 62447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r1->resrec.namehash == r2->resrec.namehash && 62547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameDomainName(r1->resrec.name, r2->resrec.name)); 62647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 62747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 62847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our 62947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// authoratative record is unique (as opposed to shared). For unique records, we are supposed to have 63047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// complete ownership of *all* types for this name, so *any* record type with the same name is a conflict. 63147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In addition, when probing we send our questions with the wildcard type kDNSQType_ANY, 63247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// so a response of any type should match, even if it is not actually the type the client plans to use. 63347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 63447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records, 63547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// and require the rrtypes to match for the rdata to be considered potentially conflicting 63647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr) 63747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 63847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!pktrr) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); } 63947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); } 64047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (pktrr->resrec.InterfaceID && 64147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt authrr->resrec.InterfaceID && 64247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse); 64347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) || authrr->WakeUp.HMAC.l[0]) 64447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse); 64547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSBool)( 64647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt pktrr->resrec.rrclass == authrr->resrec.rrclass && 64747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt pktrr->resrec.namehash == authrr->resrec.namehash && 64847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameDomainName(pktrr->resrec.name, authrr->resrec.name)); 64947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 65047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 65147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// CacheRecord *ka is the CacheRecord from the known answer list in the query. 65247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// This is the information that the requester believes to be correct. 65347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// AuthRecord *rr is the answer we are proposing to give, if not suppressed. 65447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// This is the information that we believe to be correct. 65547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// We've already determined that we plan to give this answer on this interface 65647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (either the record is non-specific, or it is specific to this interface) 65747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// so now we just need to check the name, type, class, rdata and TTL. 65847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr) 65947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 66047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If RR signature is different, or data is different, then don't suppress our answer 66147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse); 66247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 66347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the requester's indicated TTL is less than half the real TTL, 66447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we need to give our answer before the requester's copy expires. 66547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the requester's indicated TTL is at least half the real TTL, 66647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then we can suppress our answer this time. 66747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the requester's indicated TTL is greater than the TTL we believe, 66847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then that's okay, and we don't need to do anything about it. 66947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (If two responders on the network are offering the same information, 67047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that's okay, and if they are offering the information with different TTLs, 67147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the one offering the lower TTL should defer to the one offering the higher TTL.) 67247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2); 67347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 67447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 67547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr) 67647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 67747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeUnique) 67847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 67947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((rr->LastAPTime + rr->ThisAPInterval) - m->timenow > mDNSPlatformOneSecond * 10) 68047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 68147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SetNextAnnounceProbeTime: ProbeCount %d Next in %d %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr)); 68247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SetNextAnnounceProbeTime: m->SuppressProbes %d m->timenow %d diff %d", m->SuppressProbes, m->timenow, m->SuppressProbes - m->timenow); 68347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 68447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 68547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval); 68647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Some defensive code: 68747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If (rr->LastAPTime + rr->ThisAPInterval) happens to be far in the past, we don't want to allow 68847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // NextScheduledProbe to be set excessively in the past, because that can cause bad things to happen. 68947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // See: <rdar://problem/7795434> mDNS: Sometimes advertising stops working and record interval is set to zero 69047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextScheduledProbe - m->timenow < 0) 69147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledProbe = m->timenow; 69247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 69347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->AnnounceCount && (ResourceRecordIsValidAnswer(rr) || rr->resrec.RecordType == kDNSRecordTypeDeregistering)) 69447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 69547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 69647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval); 69747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 69847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 69947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 70047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) 70147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 70247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For reverse-mapping Sleep Proxy PTR records, probe interval is one second 70347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ThisAPInterval = rr->AddressProxy.type ? mDNSPlatformOneSecond : DefaultAPIntervalForRecordType(rr->resrec.RecordType); 70447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 70547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // * If this is a record type that's going to probe, then we use the m->SuppressProbes time. 70647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // * Otherwise, if it's not going to probe, but m->SuppressProbes is set because we have other 70747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // records that are going to probe, then we delay its first announcement so that it will 70847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // go out synchronized with the first announcement for the other records that *are* probing. 70947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This is a minor performance tweak that helps keep groups of related records synchronized together. 71047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The addition of "interval / 2" is to make sure that, in the event that any of the probes are 71147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete. 71247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated, 71347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // because they will meet the criterion of being at least half-way to their scheduled announcement time. 71447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // * If it's not going to probe and m->SuppressProbes is not already set then we should announce immediately. 71547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 71647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ProbeCount) 71747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 71847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we have no probe suppression time set, or it is in the past, set it now 71947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0) 72047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 72147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // To allow us to aggregate probes when a group of services are registered together, 72247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the first probe is delayed 1/4 second. This means the common-case behaviour is: 72347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1/4 second wait; probe 72447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1/4 second wait; probe 72547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1/4 second wait; probe 72647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered) 72747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2)); 72847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 72947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation 73047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SuppressProbes - m->NextScheduledProbe >= 0) 73147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressProbes = NonZeroTime(m->NextScheduledProbe); 73247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past 73347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressProbes = m->timenow; 73447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 73547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation 73647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SuppressProbes - m->NextScheduledQuery >= 0) 73747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressProbes = NonZeroTime(m->NextScheduledQuery); 73847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past 73947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressProbes = m->timenow; 74047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 74147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // except... don't expect to be able to send before the m->SuppressSending timer fires 74247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SuppressSending && m->SuppressProbes - m->SuppressSending < 0) 74347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressProbes = NonZeroTime(m->SuppressSending); 74447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 74547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SuppressProbes - m->timenow > mDNSPlatformOneSecond * 8) 74647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 74747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("InitializeLastAPTime ERROR m->SuppressProbes %d m->NextScheduledProbe %d m->NextScheduledQuery %d m->SuppressSending %d %d", 74847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressProbes - m->timenow, 74947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledProbe - m->timenow, 75047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledQuery - m->timenow, 75147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressSending, 75247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressSending - m->timenow); 75347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2)); 75447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 75547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 75647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval; 75747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 75847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (m->SuppressProbes && m->SuppressProbes - m->timenow >= 0) 75947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval + DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2; 76047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 76147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastAPTime = m->timenow - rr->ThisAPInterval; 76247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 76347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we 76447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing. 76547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // After three probes one second apart with no answer, we conclude the client is now sleeping 76647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and we can begin broadcasting our announcements to take over ownership of that IP address. 76747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk 76847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address. 76947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->AddressProxy.type) rr->LastAPTime = m->timenow; 77047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 77147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Unsolicited Neighbor Advertisements (RFC 2461 Section 7.2.6) give us fast address cache updating, 77247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // but some older IPv6 clients get confused by them, so for now we don't send them. Without Unsolicited 77347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Neighbor Advertisements we have to rely on Neighbor Unreachability Detection instead, which is slower. 77447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Given this, we'll do our best to wake for existing IPv6 connections, but we don't want to encourage 77547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // new ones for sleeping clients, so we'll we send deletions for our SPS clients' AAAA records. 77647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->KnownBugs & mDNS_KnownBug_LimitedIPv6) 77747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->WakeUp.HMAC.l[0] && rr->resrec.rrtype == kDNSType_AAAA) 77847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastAPTime = m->timenow - rr->ThisAPInterval + mDNSPlatformOneSecond * 10; 77947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 78047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Set LastMCTime to now, to inhibit multicast responses 78147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (no need to send additional multicast responses when we're announcing anyway) 78247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastMCTime = m->timenow; 78347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastMCInterface = mDNSInterfaceMark; 78447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 78547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextAnnounceProbeTime(m, rr); 78647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 78747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 78847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal const domainname *SetUnicastTargetToHostName(mDNS *const m, AuthRecord *rr) 78947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 79047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainname *target; 79147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->AutoTarget) 79247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 79347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other 79447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate, 79547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // with the port number in our advertised SRV record automatically tracking the external mapped port. 79647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name); 79747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AuthInfo || !AuthInfo->AutoTunnel) rr->AutoTarget = Target_AutoHostAndNATMAP; 79847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 79947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 80047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt target = GetServiceTarget(m, rr); 80147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!target || target->c[0] == 0) 80247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 80347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // defer registration until we've got a target 80447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("SetUnicastTargetToHostName No target for %s", ARDisplayString(m, rr)); 80547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->state = regState_NoTarget; 80647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNSNULL; 80747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 80847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 80947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 81047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("SetUnicastTargetToHostName target %##s for resource record %s", target->c, ARDisplayString(m,rr)); 81147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return target; 81247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 81347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 81447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 81547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname 81647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Eventually we should unify this with GetServiceTarget() in uDNS.c 81747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr) 81847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 81947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainname *const target = GetRRDomainNameTarget(&rr->resrec); 82047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainname *newname = &m->MulticastHostname; 82147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 82247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!target) LogInfo("SetTargetToHostName: Don't know how to set the target of rrtype %s", DNSTypeName(rr->resrec.rrtype)); 82347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 82447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!(rr->ForceMCast || rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P || IsLocalDomain(&rr->namestorage))) 82547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 82647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainname *const n = SetUnicastTargetToHostName(m, rr); 82747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (n) newname = n; 82847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else { target->c[0] = 0; SetNewRData(&rr->resrec, mDNSNULL, 0); return; } 82947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 83047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 83147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (target && SameDomainName(target, newname)) 83247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c); 83347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 83447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (target && !SameDomainName(target, newname)) 83547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 83647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(target, newname); 83747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNewRData(&rr->resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash 83847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 83947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we're in the middle of probing this record, we need to start again, 84047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // because changing its rdata may change the outcome of the tie-breaker. 84147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.) 84247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 84347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 84447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we've announced this record, we really should send a goodbye packet for the old rdata before 84547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records, 84647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way. 84747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared) 84847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating", 84947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 85047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 85147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount = InitialAnnounceCount; 85247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->RequireGoodbye = mDNSfalse; 85347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeLastAPTime(m, rr); 85447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 85547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 85647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 85747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr) 85847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 85947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->RecordCallback) 86047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 86147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function 86247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. 86347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->Acknowledged = mDNStrue; 86447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 86547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->RecordCallback(m, rr, mStatus_NoError); 86647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 86747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 86847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 86947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 87047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr) 87147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 87247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Make sure that we don't activate the SRV record and associated service records, if it is in 87347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // NoTarget state. First time when a service is being instantiated, SRV record may be in NoTarget state. 87447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We should not activate any of the other reords (PTR, TXT) that are part of the service. When 87547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the target becomes available, the records will be reregistered. 87647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rrtype != kDNSType_SRV) 87747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 87847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *srvRR = mDNSNULL; 87947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rrtype == kDNSType_PTR) 88047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt srvRR = rr->Additional1; 88147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->resrec.rrtype == kDNSType_TXT) 88247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt srvRR = rr->DependentOn; 88347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (srvRR) 88447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 88547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (srvRR->resrec.rrtype != kDNSType_SRV) 88647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 88747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("ActivateUnicastRegistration: ERROR!! Resource record %s wrong, expecting SRV type", ARDisplayString(m, srvRR)); 88847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 88947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 89047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 89147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("ActivateUnicastRegistration: Found Service Record %s in state %d for %##s (%s)", 89247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ARDisplayString(m, srvRR), srvRR->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 89347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->state = srvRR->state; 89447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 89547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 89647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 89747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 89847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->state == regState_NoTarget) 89947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 90047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("ActivateUnicastRegistration record %s in regState_NoTarget, not activating", ARDisplayString(m, rr)); 90147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 90247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 90347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When we wake up from sleep, we call ActivateUnicastRegistration. It is possible that just before we went to sleep, 90447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the service/record was being deregistered. In that case, we should not try to register again. For the cases where 90547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the records are deregistered due to e.g., no target for the SRV record, we would have returned from above if it 90647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // was already in NoTarget state. If it was in the process of deregistration but did not complete fully before we went 90747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to sleep, then it is okay to start in Pending state as we will go back to NoTarget state if we don't have a target. 90847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) 90947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 91047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to DeregPending", ARDisplayString(m, rr), rr->state); 91147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->state = regState_DeregPending; 91247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 91347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 91447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 91547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to Pending", ARDisplayString(m, rr), rr->state); 91647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->state = regState_Pending; 91747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 91847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ProbeCount = 0; 91947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount = 0; 92047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; 92147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastAPTime = m->timenow - rr->ThisAPInterval; 92247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->expire = 0; // Forget about all the leases, start fresh 92347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->uselease = mDNStrue; 92447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->updateid = zeroID; 92547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SRVChanged = mDNSfalse; 92647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->updateError = mStatus_NoError; 92747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // RestartRecordGetZoneData calls this function whenever a new interface gets registered with core. 92847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The records might already be registered with the server and hence could have NAT state. 92947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NATinfo.clientContext) 93047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 93147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopNATOperation_internal(m, &rr->NATinfo); 93247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NATinfo.clientContext = mDNSNULL; 93347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 93447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; } 93547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } 93647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextuDNSEvent - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 93747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextuDNSEvent = (rr->LastAPTime + rr->ThisAPInterval); 93847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 93947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 94047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Two records qualify to be local duplicates if: 94147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (a) the RecordTypes are the same, or 94247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (b) one is Unique and the other Verified 94347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (c) either is in the process of deregistering 94447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \ 94547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified) || \ 94647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((A)->resrec.RecordType == kDNSRecordTypeDeregistering || (B)->resrec.RecordType == kDNSRecordTypeDeregistering)) 94747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 94847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define RecordIsLocalDuplicate(A,B) \ 94947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec)) 95047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 95147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal AuthRecord *CheckAuthIdenticalRecord(AuthHash *r, AuthRecord *rr) 95247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 95347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *a; 95447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup **ag = &a; 95547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord **rp; 95647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = AuthHashSlot(rr->resrec.name); 95747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 95847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt a = AuthGroupForRecord(r, slot, &rr->resrec); 95947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!a) return mDNSNULL; 96047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp = &(*ag)->members; 96147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*rp) 96247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 96347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!RecordIsLocalDuplicate(*rp, rr)) 96447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp=&(*rp)->next; 96547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 96647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 96747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((*rp)->resrec.RecordType == kDNSRecordTypeDeregistering) 96847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 96947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (*rp)->AnnounceCount = 0; 97047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp=&(*rp)->next; 97147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 97247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else return *rp; 97347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 97447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 97547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return (mDNSNULL); 97647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 97747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 97847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool CheckAuthRecordConflict(AuthHash *r, AuthRecord *rr) 97947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 98047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *a; 98147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup **ag = &a; 98247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord **rp; 98347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = AuthHashSlot(rr->resrec.name); 98447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 98547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt a = AuthGroupForRecord(r, slot, &rr->resrec); 98647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!a) return mDNSfalse; 98747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp = &(*ag)->members; 98847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*rp) 98947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 99047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr; 99147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const AuthRecord *s2 = (*rp)->RRSet ? (*rp)->RRSet : *rp; 99247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (s1 != s2 && SameResourceRecordSignature((*rp), rr) && !IdenticalSameNameRecord(&(*rp)->resrec, &rr->resrec)) 99347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNStrue; 99447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 99547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp=&(*rp)->next; 99647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 99747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return (mDNSfalse); 99847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 99947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 100047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// checks to see if "rr" is already present 100147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal AuthRecord *CheckAuthSameRecord(AuthHash *r, AuthRecord *rr) 100247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 100347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *a; 100447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup **ag = &a; 100547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord **rp; 100647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = AuthHashSlot(rr->resrec.name); 100747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 100847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt a = AuthGroupForRecord(r, slot, &rr->resrec); 100947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!a) return mDNSNULL; 101047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp = &(*ag)->members; 101147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*rp) 101247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 101347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*rp != rr) 101447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp=&(*rp)->next; 101547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 101647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 101747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return *rp; 101847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 101947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 102047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return (mDNSNULL); 102147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 102247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 102347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Exported so uDNS.c can call this 102447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) 102547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 102647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainname *target = GetRRDomainNameTarget(&rr->resrec); 102747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *r; 102847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord **p = &m->ResourceRecords; 102947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord **d = &m->DuplicateRecords; 103047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 103147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((mDNSs32)rr->resrec.rroriginalttl <= 0) 103247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { LogMsg("mDNS_Register_internal: TTL %X should be 1 - 0x7FFFFFFF %s", rr->resrec.rroriginalttl, ARDisplayString(m, rr)); return(mStatus_BadParamErr); } 103347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 103447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rr->resrec.RecordType) 103547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); } 103647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 103747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->ShutdownTime) 103847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m, rr)); return(mStatus_ServiceNotRunning); } 103947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 104047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->DivertMulticastAdvertisements && !AuthRecord_uDNS(rr)) 104147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 104247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSInterfaceID previousID = rr->resrec.InterfaceID; 104347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID == mDNSInterface_Any || rr->resrec.InterfaceID == mDNSInterface_P2P) 104447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 104547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.InterfaceID = mDNSInterface_LocalOnly; 104647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ARType = AuthRecordLocalOnly; 104747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 104847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly) 104947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 105047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); 105147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf && !intf->Advertise){ rr->resrec.InterfaceID = mDNSInterface_LocalOnly; rr->ARType = AuthRecordLocalOnly; } 105247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 105347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID != previousID) 105447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m, rr)); 105547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 105647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 105747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRLocalOnly(rr)) 105847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 105947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (CheckAuthSameRecord(&m->rrauth, rr)) 106047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 106147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Register_internal: ERROR!! Tried to register LocalOnly AuthRecord %p %##s (%s) that's already in the list", 106247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 106347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_AlreadyRegistered); 106447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 106547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 106647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 106747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 106847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*p && *p != rr) p=&(*p)->next; 106947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*p) 107047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 107147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Register_internal: ERROR!! Tried to register AuthRecord %p %##s (%s) that's already in the list", 107247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 107347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_AlreadyRegistered); 107447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 107547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 107647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 107747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*d && *d != rr) d=&(*d)->next; 107847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*d) 107947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 108047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Register_internal: ERROR!! Tried to register AuthRecord %p %##s (%s) that's already in the Duplicate list", 108147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 108247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_AlreadyRegistered); 108347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 108447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 108547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->DependentOn) 108647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 108747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeUnique) 108847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.RecordType = kDNSRecordTypeVerified; 108947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 109047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 109147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique", 109247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 109347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_Invalid); 109447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 109547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique))) 109647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 109747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X", 109847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType); 109947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_Invalid); 110047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 110147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 110247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 110347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this resource record is referencing a specific interface, make sure it exists. 110447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Skip checks for LocalOnly and P2P as they are not valid InterfaceIDs. Also, for scoped 110547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // entries in /etc/hosts skip that check as that interface may not be valid at this time. 110647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID && rr->ARType != AuthRecordLocalOnly && rr->ARType != AuthRecordP2P) 110747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 110847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); 110947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!intf) 111047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 111147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID); 111247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_BadReferenceErr); 111347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 111447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 111547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 111647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->next = mDNSNULL; 111747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 111847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Field Group 1: The actual information pertaining to this resource record 111947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Set up by client prior to call 112047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 112147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Field Group 2: Persistent metadata for Authoritative Records 112247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 112347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 112447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 112547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 112647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->Callback = already set in mDNS_SetupResourceRecord 112747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->Context = already set in mDNS_SetupResourceRecord 112847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->RecordType = already set in mDNS_SetupResourceRecord 112947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client 113047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client 113147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Make sure target is not uninitialized data, or we may crash writing debugging log messages 113247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->AutoTarget && target) target->c[0] = 0; 113347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 113447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Field Group 3: Transient state for Authoritative Records 113547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->Acknowledged = mDNSfalse; 113647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 113747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount = InitialAnnounceCount; 113847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->RequireGoodbye = mDNSfalse; 113947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnsweredLocalQ = mDNSfalse; 114047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->IncludeInProbe = mDNSfalse; 114147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedUnicast = mDNSfalse; 114247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendNSECNow = mDNSNULL; 114347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAnswer = mDNSNULL; 114447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAdditional = mDNSNULL; 114547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendRNow = mDNSNULL; 114647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->v4Requester = zerov4Addr; 114747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->v6Requester = zerov6Addr; 114847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NextResponse = mDNSNULL; 114947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NR_AnswerTo = mDNSNULL; 115047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NR_AdditionalTo = mDNSNULL; 115147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rr->AutoTarget) InitializeLastAPTime(m, rr); 115247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->LastAPTime = Set for us in InitializeLastAPTime() 115347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->LastMCTime = Set for us in InitializeLastAPTime() 115447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->LastMCInterface = Set for us in InitializeLastAPTime() 115547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NewRData = mDNSNULL; 115647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->newrdlength = 0; 115747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UpdateCallback = mDNSNULL; 115847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UpdateCredits = kMaxUpdateCredits; 115947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NextUpdateCredit = 0; 116047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UpdateBlocked = 0; 116147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 116247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient 116347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->WakeUp.HMAC.l[0] && !rr->AddressProxy.type) rr->AnnounceCount = 2; 116447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 116547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Field Group 4: Transient uDNS state for Authoritative Records 116647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->state = regState_Zero; 116747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->uselease = 0; 116847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->expire = 0; 116947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->Private = 0; 117047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->updateid = zeroID; 117147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->zone = rr->resrec.name; 117247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->nta = mDNSNULL; 117347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->tcp = mDNSNULL; 117447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->OrigRData = 0; 117547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->OrigRDLen = 0; 117647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->InFlightRData = 0; 117747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->InFlightRDLen = 0; 117847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->QueuedRData = 0; 117947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->QueuedRDLen = 0; 118047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //mDNSPlatformMemZero(&rr->NATinfo, sizeof(rr->NATinfo)); 118147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We should be recording the actual internal port for this service record here. Once we initiate our NAT mapping 118247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // request we'll subsequently overwrite srv.port with the allocated external NAT port -- potentially multiple 118347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // times with different values if the external NAT port changes during the lifetime of the service registration. 118447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //if (rr->resrec.rrtype == kDNSType_SRV) rr->NATinfo.IntPort = rr->resrec.rdata->u.srv.port; 118547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 118647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->resrec.interface = already set in mDNS_SetupResourceRecord 118747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->resrec.name->c = MUST be set by client 118847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->resrec.rrtype = already set in mDNS_SetupResourceRecord 118947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->resrec.rrclass = already set in mDNS_SetupResourceRecord 119047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord 119147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set 119247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 119347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct, 119447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s". 119547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here. 119647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; } 119747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 119847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->AutoTarget) 119947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 120047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime(); 120147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 120247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we have no target record yet, SetTargetToHostName will set rr->state == regState_NoTarget 120347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In this case we leave the record half-formed in the list, and later we'll remove it from the list and re-add it properly. 120447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->state == regState_NoTarget) 120547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 120647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Initialize the target so that we don't crash while logging etc. 120747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainname *tar = GetRRDomainNameTarget(&rr->resrec); 120847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (tar) tar->c[0] = 0; 120947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_Register_internal: record %s in NoTarget state", ARDisplayString(m, rr)); 121047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 121147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 121247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 121347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 121447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 121547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse); 121647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue); 121747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 121847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 121947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ValidateDomainName(rr->resrec.name)) 122047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); } 122147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 122247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't do this until *after* we've set rr->resrec.rdlength 122347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata)) 122447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); } 122547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 122647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); 122747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec); 122847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 122947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRLocalOnly(rr)) 123047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 123147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this is supposed to be unique, make sure we don't have any name conflicts. 123247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we found a conflict, we may still want to insert the record in the list but mark it appropriately 123347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (kDNSRecordTypeDeregistering) so that we deliver RMV events to the application. But this causes more 123447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // complications and not clear whether there are any benefits. See rdar:9304275 for details. 123547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Hence, just bail out. 123647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 123747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 123847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (CheckAuthRecordConflict(&m->rrauth, rr)) 123947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 124047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_Register_internal: Name conflict %s (%p), InterfaceID %p", ARDisplayString(m, rr), rr, rr->resrec.InterfaceID); 124147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mStatus_NameConflict; 124247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 124347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 124447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 124547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 124647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For uDNS records, we don't support duplicate checks at this time. 124747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 124847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (AuthRecord_uDNS(rr)) 124947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 125047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->NewLocalRecords) m->NewLocalRecords = rr; 125147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When we called SetTargetToHostName, it may have caused mDNS_Register_internal to be re-entered, appending new 125247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // records to the list, so we now need to update p to advance to the new end to the list before appending our new record. 125347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note that for AutoTunnel this should never happen, but this check makes the code future-proof. 125447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*p) p=&(*p)->next; 125547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *p = rr; 125647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified; 125747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ProbeCount = 0; 125847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount = 0; 125947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->state != regState_NoTarget) ActivateUnicastRegistration(m, rr); 126047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); // <--- Note: For unicast records, code currently bails out at this point 126147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 126247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 126347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 126447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Now that we've finished building our new record, make sure it's not identical to one we already have 126547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRLocalOnly(rr)) 126647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 126747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ProbeCount = 0; 126847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount = 0; 126947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r = CheckAuthIdenticalRecord(&m->rrauth, rr); 127047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 127147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 127247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 127347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r = m->ResourceRecords; r; r=r->next) 127447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RecordIsLocalDuplicate(r, rr)) 127547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 127647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r->resrec.RecordType == kDNSRecordTypeDeregistering) r->AnnounceCount = 0; 127747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else break; 127847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 127947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 128047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 128147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r) 128247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 128347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_Register_internal:Adding to duplicate list %s", ARDisplayString(m,rr)); 128447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *d = rr; 128547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the previous copy of this record is already verified unique, 128647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then indicate that we should move this record promptly to kDNSRecordTypeUnique state. 128747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Setting ProbeCount to zero will cause SendQueries() to advance this record to 128847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // kDNSRecordTypeVerified state and call the client callback at the next appropriate time. 128947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified) 129047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ProbeCount = 0; 129147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 129247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 129347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 129447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_Register_internal: Adding to active record list %s", ARDisplayString(m,rr)); 129547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRLocalOnly(rr)) 129647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 129747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *ag; 129847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag = InsertAuthRecord(m, &m->rrauth, rr); 129947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ag && !ag->NewLocalOnlyRecords) { 130047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NewLocalOnlyRecords = mDNStrue; 130147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag->NewLocalOnlyRecords = rr; 130247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 130347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // No probing for LocalOnly records, Acknowledge them right away 130447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified; 130547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AcknowledgeRecord(m, rr); 130647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); 130747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 130847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 130947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 131047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->NewLocalRecords) m->NewLocalRecords = rr; 131147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *p = rr; 131247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 131347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 131447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 131547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AuthRecord_uDNS(rr)) // This check is superfluous, given that for unicast records we (currently) bail out above 131647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 131747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For records that are not going to probe, acknowledge them right away 131847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering) 131947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AcknowledgeRecord(m, rr); 132047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 132147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Adding a record may affect whether or not we should sleep 132247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_UpdateAllowSleep(m); 132347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 132447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 132547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); 132647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 132747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 132847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr) 132947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 133047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ProbeFailTime = m->timenow; 133147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NumFailedProbes++; 133247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we've had fifteen or more probe failures, rate-limit to one every five seconds. 133347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If a bunch of hosts have all been configured with the same name, then they'll all 133447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // conflict and run through the same series of names: name-2, name-3, name-4, etc., 133547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // up to name-10. After that they'll start adding random increments in the range 1-100, 133647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so they're more likely to branch out in the available namespace and settle on a set of 133747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // unique names quickly. If after five more tries the host is still conflicting, then we 133847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // may have a serious problem, so we start rate-limiting so we don't melt down the network. 133947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NumFailedProbes >= 15) 134047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 134147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5); 134247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect", 134347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 134447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 134547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 134647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 134747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr) 134847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 134947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RData *OldRData = rr->resrec.rdata; 135047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu16 OldRDLen = rr->resrec.rdlength; 135147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); // Update our rdata 135247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NewRData = mDNSNULL; // Clear the NewRData pointer ... 135347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->UpdateCallback) 135447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UpdateCallback(m, rr, OldRData, OldRDLen); // ... and let the client know 135547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 135647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 135747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list. 135847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 135947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Exported so uDNS.c can call this 136047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt) 136147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 136247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *r2; 136347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 RecordType = rr->resrec.RecordType; 136447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records 136547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool dupList = mDNSfalse; 136647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 136747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRLocalOnly(rr)) 136847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 136947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *a; 137047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup **ag = &a; 137147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord **rp; 137247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = AuthHashSlot(rr->resrec.name); 137347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 137447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt a = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec); 137547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!a) return mDNSfalse; 137647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp = &(*ag)->members; 137747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*rp && *rp != rr) rp=&(*rp)->next; 137847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt p = rp; 137947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 138047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 138147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 138247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*p && *p != rr) p=&(*p)->next; 138347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 138447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 138547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*p) 138647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 138747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We found our record on the main list. See if there are any duplicates that need special handling. 138847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (drt == mDNS_Dereg_conflict) // If this was a conflict, see that all duplicates get the same treatment 138947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 139047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished 139147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory. 139247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF; 139347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 139447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 139547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 139647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Before we delete the record (and potentially send a goodbye packet) 139747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // first see if we have a record on the duplicate list ready to take over from it. 139847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord **d = &m->DuplicateRecords; 139947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next; 140047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*d) 140147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 140247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *dup = *d; 140347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_Register_internal: Duplicate record %p taking over from %p %##s (%s)", 140447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 140547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *d = dup->next; // Cut replacement record from DuplicateRecords list 140647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRLocalOnly(rr)) 140747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 140847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->next = mDNSNULL; 140947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!InsertAuthRecord(m, &m->rrauth, dup)) LogMsg("mDNS_Deregister_internal: ERROR!! cannot insert %s", ARDisplayString(m, dup)); 141047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 141147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 141247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 141347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->next = rr->next; // And then... 141447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->next = dup; // ... splice it in right after the record we're about to delete 141547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 141647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->resrec.RecordType = rr->resrec.RecordType; 141747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->ProbeCount = rr->ProbeCount; 141847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->AnnounceCount = rr->AnnounceCount; 141947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->RequireGoodbye = rr->RequireGoodbye; 142047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->AnsweredLocalQ = rr->AnsweredLocalQ; 142147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->ImmedAnswer = rr->ImmedAnswer; 142247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->ImmedUnicast = rr->ImmedUnicast; 142347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->ImmedAdditional = rr->ImmedAdditional; 142447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->v4Requester = rr->v4Requester; 142547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->v6Requester = rr->v6Requester; 142647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->ThisAPInterval = rr->ThisAPInterval; 142747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->LastAPTime = rr->LastAPTime; 142847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->LastMCTime = rr->LastMCTime; 142947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->LastMCInterface = rr->LastMCInterface; 143047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->Private = rr->Private; 143147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dup->state = rr->state; 143247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->RequireGoodbye = mDNSfalse; 143347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnsweredLocalQ = mDNSfalse; 143447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 143547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 143647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 143747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 143847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 143947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We didn't find our record on the main list; try the DuplicateRecords list instead. 144047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt p = &m->DuplicateRecords; 144147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*p && *p != rr) p=&(*p)->next; 144247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we found our record on the duplicate list, then make sure we don't send a goodbye for it 144347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*p) { rr->RequireGoodbye = mDNSfalse; dupList = mDNStrue; } 144447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*p) debugf("mDNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)", 144547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 144647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 144747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 144847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!*p) 144947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 145047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // No need to log an error message if we already know this is a potentially repeated deregistration 145147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (drt != mDNS_Dereg_repeat) 145247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Deregister_internal: Record %p not found in list %s", rr, ARDisplayString(m,rr)); 145347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_BadReferenceErr); 145447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 145547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 145647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this is a shared record and we've announced it at least once, 145747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we need to retract that announcement before we delete the record 145847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 145947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then 146047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe. 146147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion" 146247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // mechanism to cope with the client callback modifying the question list while that's happening. 146347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain) 146447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice. 146547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other 146647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // records, thereby invoking yet more callbacks, without limit. 146747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending 146847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // actual goodbye packets. 146947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 147047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 147147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (AuthRecord_uDNS(rr)) 147247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 147347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->RequireGoodbye) 147447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 147547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } 147647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.RecordType = kDNSRecordTypeDeregistering; 147747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LocalRemoveEvents = mDNStrue; 147847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uDNS_DeregisterRecord(m, rr); 147947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // At this point unconditionally we bail out 148047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration, 148147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration 148247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // process and will complete asynchronously. Either way we don't need to do anything more here. 148347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); 148447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 148547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Sometimes the records don't complete proper deregistration i.e., don't wait for a response 148647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // from the server. In that case, if the records have been part of a group update, clear the 148747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // state here. Some recors e.g., AutoTunnel gets reused without ever being completely initialized 148847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->updateid = zeroID; 148947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 149047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We defer cleaning up NAT state only after sending goodbyes. This is important because 149147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // RecordRegistrationGotZoneData guards against creating NAT state if clientContext is non-NULL. 149247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This happens today when we turn on/off interface where we get multiple network transitions 149347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and RestartRecordGetZoneData triggers re-registration of the resource records even though 149447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // they may be in Registered state which causes NAT information to be setup multiple times. Defering 149547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the cleanup here keeps clientContext non-NULL and hence prevents that. Note that cleaning up 149647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // NAT state here takes care of the case where we did not send goodbyes at all. 149747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NATinfo.clientContext) 149847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 149947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopNATOperation_internal(m, &rr->NATinfo); 150047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NATinfo.clientContext = mDNSNULL; 150147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 150247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; } 150347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } 150447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 150547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif // UNICAST_DISABLED 150647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 150747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RecordType == kDNSRecordTypeUnregistered) 150847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr)); 150947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (RecordType == kDNSRecordTypeDeregistering) 151047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 151147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr)); 151247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_BadReferenceErr); 151347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 151447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 151547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // <rdar://problem/7457925> Local-only questions don't get remove events for unique records 151647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We may want to consider changing this code so that we generate local-only question "rmv" 151747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // events (and maybe goodbye packets too) for unique records as well as for shared records 151847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: If we change the logic for this "if" statement, need to ensure that the code in 151947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // CompleteDeregistration() sets the appropriate state variables to gaurantee that "else" 152047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // clause will execute here and the record will be cut from the list. 152147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->WakeUp.HMAC.l[0] || 152247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ))) 152347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 152447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("mDNS_Deregister_internal: Starting deregistration for %s", ARDisplayString(m, rr)); 152547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.RecordType = kDNSRecordTypeDeregistering; 152647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rroriginalttl = 0; 152747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount = rr->WakeUp.HMAC.l[0] ? WakeupCount : (drt == mDNS_Dereg_rapid) ? 1 : GoodbyeCount; 152847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ThisAPInterval = mDNSPlatformOneSecond * 2; 152947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastAPTime = m->timenow - rr->ThisAPInterval; 153047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LocalRemoveEvents = mDNStrue; 153147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0) 153247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10); 153347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 153447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 153547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 153647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!dupList && RRLocalOnly(rr)) 153747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 153847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *ag = RemoveAuthRecord(m, &m->rrauth, rr); 153947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ag->NewLocalOnlyRecords == rr) ag->NewLocalOnlyRecords = rr->next; 154047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 154147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 154247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 154347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *p = rr->next; // Cut this record from the list 154447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next; 154547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 154647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If someone is about to look at this, bump the pointer forward 154747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord == rr) m->CurrentRecord = rr->next; 154847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->next = mDNSNULL; 154947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 155047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Should we generate local remove events here? 155147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // i.e. something like: 155247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; } 155347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 155447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr)); 155547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.RecordType = kDNSRecordTypeUnregistered; 155647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 155747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared) 155847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)", 155947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 156047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 156147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we have an update queued up which never executed, give the client a chance to free that memory 156247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client 156347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 156447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 156547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function 156647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. 156747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In this case the likely client action to the mStatus_MemFree message is to free the memory, 156847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so any attempt to touch rr after this is likely to lead to a crash. 156947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (drt != mDNS_Dereg_conflict) 157047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 157147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 157247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_Deregister_internal: mStatus_MemFree for %s", ARDisplayString(m, rr)); 157347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->RecordCallback) 157447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this 157547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 157647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 157747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 157847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 157947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RecordProbeFailure(m, rr); 158047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 158147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->RecordCallback) 158247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this 158347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 158447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously. 158547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note that with all the client callbacks going on, by the time we get here all the 158647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // records we marked may have been explicitly deregistered by the client anyway. 158747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2 = m->DuplicateRecords; 158847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (r2) 158947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 159047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2->ProbeCount != 0xFF) r2 = r2->next; 159147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; } 159247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 159347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 159447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 159547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_UpdateAllowSleep(m); 159647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); 159747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 159847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 159947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// *************************************************************************** 160047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK 160147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - 160247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Packet Sending Functions 160347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 160447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 160547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add) 160647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 160747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse) 160847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 160947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt **nrpp = rr; 161047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo) 161147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does 161247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The referenced record will definitely be acceptable (by recursive application of this rule) 161347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo; 161447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NR_AdditionalTo = add; 161547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *nrpp = &rr->NextResponse; 161647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 161747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 161847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 161947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 162047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID) 162147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 162247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr, *rr2; 162347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr=ResponseRecords; rr; rr=rr->NextResponse) // For each record we plan to put 162447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 162547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (Note: This is an "if", not a "while". If we add a record, we'll find it again 162647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // later in the "for" loop, and we will follow further "additional" links then.) 162747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID)) 162847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AddRecordToResponseList(nrpp, rr->Additional1, rr); 162947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 163047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID)) 163147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AddRecordToResponseList(nrpp, rr->Additional2, rr); 163247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 163347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For SRV records, automatically add the Address record(s) for the target host 163447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rrtype == kDNSType_SRV) 163547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 163647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records 163747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ... 163847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ... 163947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rdatahash == rr2->resrec.namehash && // ... whose name is the name of the SRV target 164047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name)) 164147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AddRecordToResponseList(nrpp, rr2, rr); 164247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 164347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (RRTypeIsAddressType(rr->resrec.rrtype)) // For A or AAAA, put counterpart as additional 164447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 164547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records 164647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ... 164747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ... 164847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.namehash == rr2->resrec.namehash && // ... and have the same name 164947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameDomainName(rr->resrec.name, rr2->resrec.name)) 165047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AddRecordToResponseList(nrpp, rr2, rr); 165147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 165247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->resrec.rrtype == kDNSType_PTR) // For service PTR, see if we want to add DeviceInfo record 165347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 165447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResourceRecordIsValidInterfaceAnswer(&m->DeviceInfo, InterfaceID) && 165547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c)) 165647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AddRecordToResponseList(nrpp, &m->DeviceInfo, rr); 165747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 165847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 165947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 166047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 166147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID) 166247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 166347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 166447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *ResponseRecords = mDNSNULL; 166547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord **nrp = &ResponseRecords; 166647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); 166747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 166847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Make a list of all our records that need to be unicast to this destination 166947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 167047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 167147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we find we can no longer unicast this answer, clear ImmedUnicast 167247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedAnswer == mDNSInterfaceMark || 167347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) || 167447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr) ) 167547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedUnicast = mDNSfalse; 167647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 167747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID) 167847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 167947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) || 168047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6))) 168147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 168247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAnswer = mDNSNULL; // Clear the state fields 168347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedUnicast = mDNSfalse; 168447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->v4Requester = zerov4Addr; 168547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->v6Requester = zerov6Addr; 168647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 168747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Only sent records registered for P2P over P2P interfaces 168847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf && !mDNSPlatformValidRecordForInterface(rr, intf)) 168947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 169047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("SendDelayedUnicastResponse: Not sending %s, on %s", ARDisplayString(m, rr), InterfaceNameForID(m, InterfaceID)); 169147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt continue; 169247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 169347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 169447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse) // rr->NR_AnswerTo 169547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; } 169647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 169747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 169847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 169947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 170047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID); 170147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 170247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (ResponseRecords) 170347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 170447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *responseptr = m->omsg.data; 170547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *newptr; 170647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags); 170747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 170847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Put answers in the packet 170947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (ResponseRecords && ResponseRecords->NR_AnswerTo) 171047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 171147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr = ResponseRecords; 171247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 171347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 171447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec); 171547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 171647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!newptr && m->omsg.h.numAnswers) break; // If packet full, send it now 171747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newptr) responseptr = newptr; 171847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ResponseRecords = rr->NextResponse; 171947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NextResponse = mDNSNULL; 172047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NR_AnswerTo = mDNSNULL; 172147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NR_AdditionalTo = mDNSNULL; 172247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->RequireGoodbye = mDNStrue; 172347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 172447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 172547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Add additionals, if there's space 172647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (ResponseRecords && !ResponseRecords->NR_AnswerTo) 172747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 172847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr = ResponseRecords; 172947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 173047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 173147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &rr->resrec); 173247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 173347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 173447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newptr) responseptr = newptr; 173547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newptr && m->omsg.h.numAnswers) rr->RequireGoodbye = mDNStrue; 173647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) rr->ImmedAnswer = mDNSInterfaceMark; 173747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ResponseRecords = rr->NextResponse; 173847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NextResponse = mDNSNULL; 173947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NR_AnswerTo = mDNSNULL; 174047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NR_AdditionalTo = mDNSNULL; 174147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 174247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 174347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->omsg.h.numAnswers) 174447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSSendDNSMessage(m, &m->omsg, responseptr, InterfaceID, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL); 174547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 174647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 174747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 174847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// CompleteDeregistration guarantees that on exit the record will have been cut from the m->ResourceRecords list 174947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// and the client's mStatus_MemFree callback will have been invoked 175047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr) 175147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 175247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CompleteDeregistration: called for Resource record %s", ARDisplayString(m, rr)); 175347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that 175447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // it should go ahead and immediately dispose of this registration 175547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.RecordType = kDNSRecordTypeShared; 175647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->RequireGoodbye = mDNSfalse; 175747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->WakeUp.HMAC = zeroEthAddr; 175847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; } 175947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this 176047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 176147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 176247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// DiscardDeregistrations is used on shutdown and sleep to discard (forcibly and immediately) 176347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// any deregistering records that remain in the m->ResourceRecords list. 176447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, 176547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// which may change the record list and/or question list. 176647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 176747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void DiscardDeregistrations(mDNS *const m) 176847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 176947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord) 177047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 177147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = m->ResourceRecords; 177247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 177347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord) 177447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 177547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr = m->CurrentRecord; 177647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AuthRecord_uDNS(rr) && rr->resrec.RecordType == kDNSRecordTypeDeregistering) 177747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CompleteDeregistration(m, rr); // Don't touch rr after this 177847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 177947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = rr->next; 178047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 178147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 178247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 178347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mStatus GetLabelDecimalValue(const mDNSu8 *const src, mDNSu8 *dst) 178447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 178547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i, val = 0; 178647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (src[0] < 1 || src[0] > 3) return(mStatus_Invalid); 178747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=1; i<=src[0]; i++) 178847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 178947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (src[i] < '0' || src[i] > '9') return(mStatus_Invalid); 179047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt val = val * 10 + src[i] - '0'; 179147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 179247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (val > 255) return(mStatus_Invalid); 179347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *dst = (mDNSu8)val; 179447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); 179547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 179647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 179747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mStatus GetIPv4FromName(mDNSAddr *const a, const domainname *const name) 179847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 179947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int skip = CountLabels(name) - 6; 180047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (skip < 0) { LogMsg("GetIPFromName: Need six labels in IPv4 reverse mapping name %##s", name); return mStatus_Invalid; } 180147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (GetLabelDecimalValue(SkipLeadingLabels(name, skip+3)->c, &a->ip.v4.b[0]) || 180247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt GetLabelDecimalValue(SkipLeadingLabels(name, skip+2)->c, &a->ip.v4.b[1]) || 180347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt GetLabelDecimalValue(SkipLeadingLabels(name, skip+1)->c, &a->ip.v4.b[2]) || 180447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt GetLabelDecimalValue(SkipLeadingLabels(name, skip+0)->c, &a->ip.v4.b[3])) return mStatus_Invalid; 180547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt a->type = mDNSAddrType_IPv4; 180647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); 180747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 180847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 180947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0' ) : \ 181047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : \ 181147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : -1) 181247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 181347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mStatus GetIPv6FromName(mDNSAddr *const a, const domainname *const name) 181447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 181547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i, h, l; 181647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainname *n; 181747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 181847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int skip = CountLabels(name) - 34; 181947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (skip < 0) { LogMsg("GetIPFromName: Need 34 labels in IPv6 reverse mapping name %##s", name); return mStatus_Invalid; } 182047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 182147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt n = SkipLeadingLabels(name, skip); 182247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<16; i++) 182347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 182447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (n->c[0] != 1) return mStatus_Invalid; 182547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt l = HexVal(n->c[1]); 182647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt n = (const domainname *)(n->c + 2); 182747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 182847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (n->c[0] != 1) return mStatus_Invalid; 182947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt h = HexVal(n->c[1]); 183047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt n = (const domainname *)(n->c + 2); 183147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 183247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (l<0 || h<0) return mStatus_Invalid; 183347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt a->ip.v6.b[15-i] = (mDNSu8)((h << 4) | l); 183447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 183547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 183647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt a->type = mDNSAddrType_IPv6; 183747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); 183847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 183947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 184047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSs32 ReverseMapDomainType(const domainname *const name) 184147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 184247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int skip = CountLabels(name) - 2; 184347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (skip >= 0) 184447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 184547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainname *suffix = SkipLeadingLabels(name, skip); 184647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameDomainName(suffix, (const domainname*)"\x7" "in-addr" "\x4" "arpa")) return mDNSAddrType_IPv4; 184747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameDomainName(suffix, (const domainname*)"\x3" "ip6" "\x4" "arpa")) return mDNSAddrType_IPv6; 184847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 184947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSAddrType_None); 185047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 185147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 185247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SendARP(mDNS *const m, const mDNSu8 op, const AuthRecord *const rr, 185347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSv4Addr *const spa, const mDNSEthAddr *const tha, const mDNSv4Addr *const tpa, const mDNSEthAddr *const dst) 185447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 185547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 185647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *ptr = m->omsg.data; 185747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); 185847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!intf) { LogMsg("SendARP: No interface with InterfaceID %p found %s", rr->resrec.InterfaceID, ARDisplayString(m,rr)); return; } 185947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 186047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x00 Destination address 186147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<6; i++) *ptr++ = dst->b[i]; 186247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 186347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us) 186447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<6; i++) *ptr++ = intf->MAC.b[0]; 186547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 186647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x0C ARP Ethertype (0x0806) 186747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x08; *ptr++ = 0x06; 186847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 186947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x0E ARP header 187047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x00; *ptr++ = 0x01; // Hardware address space; Ethernet = 1 187147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x08; *ptr++ = 0x00; // Protocol address space; IP = 0x0800 187247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 6; // Hardware address length 187347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 4; // Protocol address length 187447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x00; *ptr++ = op; // opcode; Request = 1, Response = 2 187547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 187647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x16 Sender hardware address (our MAC address) 187747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<6; i++) *ptr++ = intf->MAC.b[i]; 187847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 187947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x1C Sender protocol address 188047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<4; i++) *ptr++ = spa->b[i]; 188147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 188247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x20 Target hardware address 188347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<6; i++) *ptr++ = tha->b[i]; 188447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 188547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x26 Target protocol address 188647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<4; i++) *ptr++ = tpa->b[i]; 188747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 188847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x2A Total ARP Packet length 42 bytes 188947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformSendRawPacket(m->omsg.data, ptr, rr->resrec.InterfaceID); 189047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 189147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 189247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu16 CheckSum(const void *const data, mDNSs32 length, mDNSu32 sum) 189347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 189447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu16 *ptr = data; 189547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (length > 0) { length -= 2; sum += *ptr++; } 189647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sum = (sum & 0xFFFF) + (sum >> 16); 189747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sum = (sum & 0xFFFF) + (sum >> 16); 189847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(sum != 0xFFFF ? sum : 0); 189947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 190047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 190147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu16 IPv6CheckSum(const mDNSv6Addr *const src, const mDNSv6Addr *const dst, const mDNSu8 protocol, const void *const data, const mDNSu32 length) 190247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 190347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt IPv6PseudoHeader ph; 190447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ph.src = *src; 190547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ph.dst = *dst; 190647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ph.len.b[0] = length >> 24; 190747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ph.len.b[1] = length >> 16; 190847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ph.len.b[2] = length >> 8; 190947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ph.len.b[3] = length; 191047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ph.pro.b[0] = 0; 191147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ph.pro.b[1] = 0; 191247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ph.pro.b[2] = 0; 191347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ph.pro.b[3] = protocol; 191447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return CheckSum(&ph, sizeof(ph), CheckSum(data, length, 0)); 191547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 191647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 191747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SendNDP(mDNS *const m, const mDNSu8 op, const mDNSu8 flags, const AuthRecord *const rr, 191847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSv6Addr *const spa, const mDNSEthAddr *const tha, const mDNSv6Addr *const tpa, const mDNSEthAddr *const dst) 191947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 192047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 192147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSOpaque16 checksum; 192247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *ptr = m->omsg.data; 192347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Some recipient hosts seem to ignore Neighbor Solicitations if the IPv6-layer destination address is not the 192447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // appropriate IPv6 solicited node multicast address, so we use that IPv6-layer destination address, even though 192547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // at the Ethernet-layer we unicast the packet to the intended target, to avoid wasting network bandwidth. 192647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSv6Addr mc = { { 0xFF,0x02,0x00,0x00, 0,0,0,0, 0,0,0,1, 0xFF,tpa->b[0xD],tpa->b[0xE],tpa->b[0xF] } }; 192747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSv6Addr *const v6dst = (op == NDP_Sol) ? &mc : tpa; 192847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); 192947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!intf) { LogMsg("SendNDP: No interface with InterfaceID %p found %s", rr->resrec.InterfaceID, ARDisplayString(m,rr)); return; } 193047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 193147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x00 Destination address 193247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<6; i++) *ptr++ = dst->b[i]; 193347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Right now we only send Neighbor Solicitations to verify whether the host we're proxying for has gone to sleep yet. 193447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Since we know who we're looking for, we send it via Ethernet-layer unicast, rather than bothering every host on the 193547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // link with a pointless link-layer multicast. 193647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Should we want to send traditional Neighbor Solicitations in the future, where we really don't know in advance what 193747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Ethernet-layer address we're looking for, we'll need to send to the appropriate Ethernet-layer multicast address: 193847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *ptr++ = 0x33; 193947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *ptr++ = 0x33; 194047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *ptr++ = 0xFF; 194147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *ptr++ = tpa->b[0xD]; 194247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *ptr++ = tpa->b[0xE]; 194347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *ptr++ = tpa->b[0xF]; 194447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 194547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us) 194647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<6; i++) *ptr++ = (tha ? *tha : intf->MAC).b[i]; 194747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 194847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x0C IPv6 Ethertype (0x86DD) 194947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x86; *ptr++ = 0xDD; 195047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 195147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x0E IPv6 header 195247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x60; *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0x00; // Version, Traffic Class, Flow Label 195347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x00; *ptr++ = 0x20; // Length 195447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x3A; // Protocol == ICMPv6 195547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0xFF; // Hop Limit 195647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 195747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x16 Sender IPv6 address 195847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<16; i++) *ptr++ = spa->b[i]; 195947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 196047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x26 Destination IPv6 address 196147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<16; i++) *ptr++ = v6dst->b[i]; 196247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 196347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x36 NDP header 196447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = op; // 0x87 == Neighbor Solicitation, 0x88 == Neighbor Advertisement 196547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x00; // Code 196647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x00; *ptr++ = 0x00; // Checksum placeholder (0x38, 0x39) 196747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = flags; 196847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0x00; 196947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 197047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (op == NDP_Sol) // Neighbor Solicitation. The NDP "target" is the address we seek. 197147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 197247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x3E NDP target. 197347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<16; i++) *ptr++ = tpa->b[i]; 197447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x4E Source Link-layer Address 197547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // <http://www.ietf.org/rfc/rfc2461.txt> 197647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // MUST NOT be included when the source IP address is the unspecified address. 197747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Otherwise, on link layers that have addresses this option MUST be included 197847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // in multicast solicitations and SHOULD be included in unicast solicitations. 197947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSIPv6AddressIsZero(*spa)) 198047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 198147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = NDP_SrcLL; // Option Type 1 == Source Link-layer Address 198247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x01; // Option length 1 (in units of 8 octets) 198347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<6; i++) *ptr++ = (tha ? *tha : intf->MAC).b[i]; 198447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 198547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 198647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else // Neighbor Advertisement. The NDP "target" is the address we're giving information about. 198747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 198847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x3E NDP target. 198947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<16; i++) *ptr++ = spa->b[i]; 199047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x4E Target Link-layer Address 199147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = NDP_TgtLL; // Option Type 2 == Target Link-layer Address 199247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x01; // Option length 1 (in units of 8 octets) 199347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<6; i++) *ptr++ = (tha ? *tha : intf->MAC).b[i]; 199447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 199547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 199647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x4E or 0x56 Total NDP Packet length 78 or 86 bytes 199747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.data[0x13] = ptr - &m->omsg.data[0x36]; // Compute actual length 199847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt checksum.NotAnInteger = ~IPv6CheckSum(spa, v6dst, 0x3A, &m->omsg.data[0x36], m->omsg.data[0x13]); 199947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.data[0x38] = checksum.b[0]; 200047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.data[0x39] = checksum.b[1]; 200147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 200247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformSendRawPacket(m->omsg.data, ptr, rr->resrec.InterfaceID); 200347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 200447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 200547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SetupOwnerOpt(const mDNS *const m, const NetworkInterfaceInfo *const intf, rdataOPT *const owner) 200647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 200747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt owner->u.owner.vers = 0; 200847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt owner->u.owner.seq = m->SleepSeqNum; 200947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt owner->u.owner.HMAC = m->PrimaryMAC; 201047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt owner->u.owner.IMAC = intf->MAC; 201147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt owner->u.owner.password = zeroEthAddr; 201247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 201347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't try to compute the optlen until *after* we've set up the data fields 201447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Right now the DNSOpt_Owner_Space macro does not depend on the owner->u.owner being set up correctly, but in the future it might 201547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt owner->opt = kDNSOpt_Owner; 201647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt owner->optlen = DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC) - 4; 201747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 201847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 201947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void GrantUpdateCredit(AuthRecord *rr) 202047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 202147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0; 202247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else rr->NextUpdateCredit = NonZeroTime(rr->NextUpdateCredit + kUpdateCreditRefreshInterval); 202347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 202447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 202547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note about acceleration of announcements to facilitate automatic coalescing of 202647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// multiple independent threads of announcements into a single synchronized thread: 202747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The announcements in the packet may be at different stages of maturity; 202847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// One-second interval, two-second interval, four-second interval, and so on. 202947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// After we've put in all the announcements that are due, we then consider 203047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// whether there are other nearly-due announcements that are worth accelerating. 203147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// To be eligible for acceleration, a record MUST NOT be older (further along 203247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// its timeline) than the most mature record we've already put in the packet. 203347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In other words, younger records can have their timelines accelerated to catch up 203447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// with their elder bretheren; this narrows the age gap and helps them eventually get in sync. 203547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Older records cannot have their timelines accelerated; this would just widen 203647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// the gap between them and their younger bretheren and get them even more out of sync. 203747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 203847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change 203947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// the record list and/or question list. 204047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 204147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SendResponses(mDNS *const m) 204247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 204347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int pktcount = 0; 204447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr, *r2; 204547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 maxExistingAnnounceInterval = 0; 204647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces); 204747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 204847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledResponse = m->timenow + 0x78000000; 204947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 205047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SleepState == SleepState_Transferring) RetrySPSRegistrations(m); 205147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 205247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 205347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedUnicast) 205447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 205547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSAddr v4 = { mDNSAddrType_IPv4, {{{0}}} }; 205647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSAddr v6 = { mDNSAddrType_IPv6, {{{0}}} }; 205747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt v4.ip.v4 = rr->v4Requester; 205847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt v6.ip.v6 = rr->v6Requester; 205947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSIPv4AddressIsZero(rr->v4Requester)) SendDelayedUnicastResponse(m, &v4, rr->ImmedAnswer); 206047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSIPv6AddressIsZero(rr->v6Requester)) SendDelayedUnicastResponse(m, &v6, rr->ImmedAnswer); 206147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedUnicast) 206247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 206347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m, rr)); 206447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedUnicast = mDNSfalse; 206547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 206647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 206747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 206847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 206947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on 207047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 207147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 207247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Run through our list of records, and decide which ones we're going to announce on all interfaces 207347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 207447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 207547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr); 207647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (TimeToAnnounceThisRecord(rr, m->timenow)) 207747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 207847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) 207947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 208047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rr->WakeUp.HMAC.l[0]) 208147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 208247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->AnnounceCount) rr->ImmedAnswer = mDNSInterfaceMark; // Send goodbye packet on all interfaces 208347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 208447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 208547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 208647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("SendResponses: Sending wakeup %2d for %.6a %s", rr->AnnounceCount-3, &rr->WakeUp.IMAC, ARDisplayString(m, rr)); 208747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password); 208847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r2 = rr; r2; r2=r2->next) 208947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2->AnnounceCount && r2->resrec.InterfaceID == rr->resrec.InterfaceID && mDNSSameEthAddress(&r2->WakeUp.IMAC, &rr->WakeUp.IMAC)) 209047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 209147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For now we only want to send a single Unsolicited Neighbor Advertisement restoring the address to the original 209247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // owner, because these packets can cause some IPv6 stacks to falsely conclude that there's an address conflict. 209347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2->AddressProxy.type == mDNSAddrType_IPv6 && r2->AnnounceCount == WakeupCount) 209447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 209547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("NDP Announcement %2d Releasing traffic for H-MAC %.6a I-MAC %.6a %s", 209647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->AnnounceCount-3, &r2->WakeUp.HMAC, &r2->WakeUp.IMAC, ARDisplayString(m,r2)); 209747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendNDP(m, NDP_Adv, NDP_Override, r2, &r2->AddressProxy.ip.v6, &r2->WakeUp.IMAC, &AllHosts_v6, &AllHosts_v6_Eth); 209847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 209947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->LastAPTime = m->timenow; 210047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // After 15 wakeups without success (maybe host has left the network) send three goodbyes instead 210147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (--r2->AnnounceCount <= GoodbyeCount) r2->WakeUp.HMAC = zeroEthAddr; 210247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 210347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 210447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 210547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (ResourceRecordIsValidAnswer(rr)) 210647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 210747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->AddressProxy.type) 210847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 210947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount--; 211047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ThisAPInterval *= 2; 211147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastAPTime = m->timenow; 211247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->AddressProxy.type == mDNSAddrType_IPv4) 211347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 211447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("ARP Announcement %2d Capturing traffic for H-MAC %.6a I-MAC %.6a %s", 211547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr)); 211647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendARP(m, 1, rr, &rr->AddressProxy.ip.v4, &zeroEthAddr, &rr->AddressProxy.ip.v4, &onesEthAddr); 211747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 211847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->AddressProxy.type == mDNSAddrType_IPv6) 211947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 212047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("NDP Announcement %2d Capturing traffic for H-MAC %.6a I-MAC %.6a %s", 212147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr)); 212247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendNDP(m, NDP_Adv, NDP_Override, rr, &rr->AddressProxy.ip.v6, mDNSNULL, &AllHosts_v6, &AllHosts_v6_Eth); 212347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 212447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 212547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 212647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 212747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces 212847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (maxExistingAnnounceInterval < rr->ThisAPInterval) 212947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt maxExistingAnnounceInterval = rr->ThisAPInterval; 213047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->UpdateBlocked) rr->UpdateBlocked = 0; 213147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 213247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 213347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 213447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 213547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 213647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Any interface-specific records we're going to send are marked as being sent on all appropriate interfaces (which is just one) 213747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Eligible records that are more than half-way to their announcement time are accelerated 213847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 213947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((rr->resrec.InterfaceID && rr->ImmedAnswer) || 214047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rr->ThisAPInterval <= maxExistingAnnounceInterval && 214147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2) && 214247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !rr->AddressProxy.type && // Don't include ARP Annoucements when considering which records to accelerate 214347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ResourceRecordIsValidAnswer(rr))) 214447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces 214547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 214647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals 214747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID, 214847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen) 214947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then all that means is that it won't get sent -- which would not be the end of the world. 215047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 215147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 215247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedAnswer && rr->resrec.rrtype == kDNSType_SRV) 215347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r2=m->ResourceRecords; r2; r2=r2->next) // Scan list of resource records 215447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRTypeIsAddressType(r2->resrec.rrtype) && // For all address records (A/AAAA) ... 215547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ResourceRecordIsValidAnswer(r2) && // ... which are valid for answer ... 215647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastMCTime - r2->LastMCTime >= 0 && // ... which we have not sent recently ... 215747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rdatahash == r2->resrec.namehash && // ... whose name is the name of the SRV target 215847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameDomainName(&rr->resrec.rdata->u.srv.target, r2->resrec.name) && 215947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID)) 216047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->ImmedAdditional = r2->resrec.InterfaceID; // ... then mark this address record for sending too 216147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We also make sure we send the DeviceInfo TXT record too, if necessary 216247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We check for RecordType == kDNSRecordTypeShared because we don't want to tag the 216347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // DeviceInfo TXT record onto a goodbye packet (RecordType == kDNSRecordTypeDeregistering). 216447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedAnswer && rr->resrec.RecordType == kDNSRecordTypeShared && rr->resrec.rrtype == kDNSType_PTR) 216547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResourceRecordIsValidAnswer(&m->DeviceInfo) && SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c)) 216647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 216747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->DeviceInfo.ImmedAnswer) m->DeviceInfo.ImmedAnswer = rr->ImmedAnswer; 216847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else m->DeviceInfo.ImmedAnswer = mDNSInterfaceMark; 216947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 217047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 217147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 217247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If there's a record which is supposed to be unique that we're going to send, then make sure that we give 217347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class 217447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then we need to mark them for sending too. Otherwise, if we set the kDNSClass_UniqueRRSet bit on a 217547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // record, then other RRSet members that have not been sent recently will get flushed out of client caches. 217647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // -- If a record is marked to be sent on a certain interface, make sure the whole set is marked to be sent on that interface 217747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // -- If any record is marked to be sent on all interfaces, make sure the whole set is marked to be sent on all interfaces 217847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 217947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 218047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 218147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedAnswer) // If we're sending this as answer, see that its whole RRSet is similarly marked 218247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 218347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r2 = m->ResourceRecords; r2; r2=r2->next) 218447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResourceRecordIsValidAnswer(r2)) 218547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2->ImmedAnswer != mDNSInterfaceMark && 218647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(r2, rr)) 218747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->ImmedAnswer = !r2->ImmedAnswer ? rr->ImmedAnswer : mDNSInterfaceMark; 218847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 218947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->ImmedAdditional) // If we're sending this as additional, see that its whole RRSet is similarly marked 219047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 219147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r2 = m->ResourceRecords; r2; r2=r2->next) 219247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResourceRecordIsValidAnswer(r2)) 219347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(r2, rr)) 219447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->ImmedAdditional = rr->ImmedAdditional; 219547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 219647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 219747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 219847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Now set SendRNow state appropriately 219947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 220047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 220147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedAnswer == mDNSInterfaceMark) // Sending this record on all appropriate interfaces 220247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 220347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendRNow = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID; 220447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAdditional = mDNSNULL; // No need to send as additional if sending as answer 220547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastMCTime = m->timenow; 220647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastMCInterface = rr->ImmedAnswer; 220747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done 220847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2)) 220947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 221047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount--; 221147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType != kDNSRecordTypeDeregistering) 221247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ThisAPInterval *= 2; 221347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastAPTime = m->timenow; 221447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount); 221547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 221647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 221747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->ImmedAnswer) // Else, just respond to a single query on single interface: 221847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 221947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendRNow = rr->ImmedAnswer; // Just respond on that interface 222047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAdditional = mDNSNULL; // No need to send as additional too 222147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastMCTime = m->timenow; 222247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastMCInterface = rr->ImmedAnswer; 222347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 222447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextAnnounceProbeTime(m, rr); 222547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr)); 222647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 222747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 222847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 222947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 2. Loop through interface list, sending records as appropriate 223047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 223147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 223247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (intf) 223347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 223447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const int OwnerRecordSpace = (m->AnnounceOwner && intf->MAC.l[0]) ? DNSOpt_Header_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC) : 0; 223547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int numDereg = 0; 223647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int numAnnounce = 0; 223747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int numAnswer = 0; 223847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *responseptr = m->omsg.data; 223947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *newptr; 224047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags); 224147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 224247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // First Pass. Look for: 224347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. Deregistering records that need to send their goodbye packet 224447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. Updated records that need to retract their old data 224547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3. Answers and announcements we need to send 224647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 224747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 224847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 224947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Skip this interface if the record InterfaceID is *Any and the record is not 225047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // appropriate for the interface type. 225147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((rr->SendRNow == intf->InterfaceID) && 225247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((rr->resrec.InterfaceID == mDNSInterface_Any) && !mDNSPlatformValidRecordForInterface(rr, intf))) 225347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 225447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("SendResponses: Not sending %s, on %s", ARDisplayString(m, rr), InterfaceNameForID(m, rr->SendRNow)); 225547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendRNow = GetNextActiveInterfaceID(intf); 225647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 225747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->SendRNow == intf->InterfaceID) 225847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 225947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RData *OldRData = rr->resrec.rdata; 226047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu16 oldrdlength = rr->resrec.rdlength; 226147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 active = (mDNSu8) 226247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rr->resrec.RecordType != kDNSRecordTypeDeregistering && 226347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (m->SleepState != SleepState_Sleeping || intf->SPSAddr[0].type || intf->SPSAddr[1].type || intf->SPSAddr[2].type)); 226447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newptr = mDNSNULL; 226547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NewRData && active) 226647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 226747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // See if we should send a courtesy "goodbye" for the old data before we replace it. 226847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResourceRecordIsValidAnswer(rr) && rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye) 226947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 227047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0); 227147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newptr) { responseptr = newptr; numDereg++; rr->RequireGoodbye = mDNSfalse; } 227247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else continue; // If this packet is already too full to hold the goodbye for this record, skip it for now and we'll retry later 227347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 227447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); 227547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 227647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 227747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 227847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 227947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0); 228047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 228147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newptr) 228247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 228347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt responseptr = newptr; 228447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->RequireGoodbye = active; 228547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) numDereg++; 228647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++; 228747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 228847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 228947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NewRData && active) 229047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNewRData(&rr->resrec, OldRData, oldrdlength); 229147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 229247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The first time through (pktcount==0), if this record is verified unique 229347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (i.e. typically A, AAAA, SRV, TXT and reverse-mapping PTR), set the flag to add an NSEC too. 229447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!pktcount && active && (rr->resrec.RecordType & kDNSRecordTypeActiveUniqueMask) && !rr->SendNSECNow) 229547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendNSECNow = mDNSInterfaceMark; 229647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 229747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newptr) // If succeeded in sending, advance to next interface 229847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 229947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If sending on all interfaces, go to next interface; else we're finished now 230047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any) 230147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendRNow = GetNextActiveInterfaceID(intf); 230247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 230347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendRNow = mDNSNULL; 230447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 230547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 230647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 230747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 230847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Second Pass. Add additional records, if there's space. 230947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newptr = responseptr; 231047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 231147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedAdditional == intf->InterfaceID) 231247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResourceRecordIsValidAnswer(rr)) 231347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 231447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we have at least one answer already in the packet, then plan to add additionals too 231547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool SendAdditional = (m->omsg.h.numAnswers > 0); 231647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 231747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we're not planning to send any additionals, but this record is a unique one, then 231847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // make sure we haven't already sent any other members of its RRSet -- if we have, then they 231947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // will have had the cache flush bit set, so now we need to finish the job and send the rest. 232047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!SendAdditional && (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)) 232147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 232247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const AuthRecord *a; 232347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (a = m->ResourceRecords; a; a=a->next) 232447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (a->LastMCTime == m->timenow && 232547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt a->LastMCInterface == intf->InterfaceID && 232647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameResourceRecordSignature(a, rr)) { SendAdditional = mDNStrue; break; } 232747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 232847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!SendAdditional) // If we don't want to send this after all, 232947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAdditional = mDNSNULL; // then cancel its ImmedAdditional field 233047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (newptr) // Else, try to add it if we can 233147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 233247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The first time through (pktcount==0), if this record is verified unique 233347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (i.e. typically A, AAAA, SRV, TXT and reverse-mapping PTR), set the flag to add an NSEC too. 233447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!pktcount && (rr->resrec.RecordType & kDNSRecordTypeActiveUniqueMask) && !rr->SendNSECNow) 233547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendNSECNow = mDNSInterfaceMark; 233647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 233747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 233847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 233947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newptr = PutRR_OS(newptr, &m->omsg.h.numAdditionals, &rr->resrec); 234047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 234147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newptr) 234247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 234347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt responseptr = newptr; 234447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAdditional = mDNSNULL; 234547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->RequireGoodbye = mDNStrue; 234647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface. 234747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise, 234847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get 234947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches. 235047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastMCTime = m->timenow; 235147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastMCInterface = intf->InterfaceID; 235247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 235347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 235447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 235547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 235647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Third Pass. Add NSEC records, if there's space. 235747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When we're generating an NSEC record in response to a specify query for that type 235847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (recognized by rr->SendNSECNow == intf->InterfaceID) we should really put the NSEC in the Answer Section, 235947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // not Additional Section, but for now it's easier to handle both cases in this Additional Section loop here. 236047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 236147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->SendNSECNow == mDNSInterfaceMark || rr->SendNSECNow == intf->InterfaceID) 236247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 236347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord nsec; 236447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&nsec, mDNSNULL, mDNSInterface_Any, kDNSType_NSEC, rr->resrec.rroriginalttl, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL); 236547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt nsec.resrec.rrclass |= kDNSClass_UniqueRRSet; 236647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&nsec.namestorage, rr->resrec.name); 236747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemZero(nsec.rdatastorage.u.nsec.bitmap, sizeof(nsec.rdatastorage.u.nsec.bitmap)); 236847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r2 = m->ResourceRecords; r2; r2=r2->next) 236947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResourceRecordIsValidAnswer(r2) && SameResourceRecordNameClassInterface(r2, rr)) 237047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 237147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2->resrec.rrtype >= kDNSQType_ANY) { LogMsg("Can't create NSEC for record %s", ARDisplayString(m, r2)); break; } 237247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else nsec.rdatastorage.u.nsec.bitmap[r2->resrec.rrtype >> 3] |= 128 >> (r2->resrec.rrtype & 7); 237347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 237447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newptr = responseptr; 237547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!r2) // If we successfully built our NSEC record, add it to the packet now 237647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 237747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newptr = PutRR_OS(responseptr, &m->omsg.h.numAdditionals, &nsec.resrec); 237847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newptr) responseptr = newptr; 237947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 238047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 238147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we successfully put the NSEC record, clear the SendNSECNow flag 238247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we consider this NSEC optional, then we unconditionally clear the SendNSECNow flag, even if we fail to put this additional record 238347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newptr || rr->SendNSECNow == mDNSInterfaceMark) 238447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 238547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendNSECNow = mDNSNULL; 238647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Run through remainder of list clearing SendNSECNow flag for all other records which would generate the same NSEC 238747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r2 = rr->next; r2; r2=r2->next) 238847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameResourceRecordNameClassInterface(r2, rr)) 238947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2->SendNSECNow == mDNSInterfaceMark || r2->SendNSECNow == intf->InterfaceID) 239047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->SendNSECNow = mDNSNULL; 239147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 239247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 239347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 239447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->omsg.h.numAnswers || m->omsg.h.numAdditionals) 239547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 239647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we have data to send, add OWNER option if necessary, then send packet 239747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 239847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (OwnerRecordSpace) 239947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 240047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord opt; 240147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); 240247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rrclass = NormalMaxDNSMessageData; 240347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record 240447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdestimate = sizeof(rdataOPT); 240547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]); 240647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &opt.resrec); 240747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newptr) { responseptr = newptr; LogSPS("SendResponses put %s", ARDisplayString(m, &opt)); } 240847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (m->omsg.h.numAnswers + m->omsg.h.numAuthorities + m->omsg.h.numAdditionals == 1) 240947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("SendResponses: No space in packet for Owner OPT record (%d/%d/%d/%d) %s", 241047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt)); 241147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 241247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SendResponses: How did we fail to have space for Owner OPT record (%d/%d/%d/%d) %s", 241347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt)); 241447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 241547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 241647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p", 241747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt numDereg, numDereg == 1 ? "" : "s", 241847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt numAnnounce, numAnnounce == 1 ? "" : "s", 241947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt numAnswer, numAnswer == 1 ? "" : "s", 242047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID); 242147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 242247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL); 242347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL); 242447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10); 242547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; } 242647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // There might be more things to send on this interface, so go around one more time and try again. 242747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 242847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else // Nothing more to send on this interface; go to next 242947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 243047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next); 243147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #if MDNS_DEBUGMSGS && 0 243247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *const msg = next ? "SendResponses: Nothing more on %p; moving to %p" : "SendResponses: Nothing more on %p"; 243347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf(msg, intf, next); 243447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #endif 243547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf = next; 243647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt pktcount = 0; // When we move to a new interface, reset packet count back to zero -- NSEC generation logic uses it 243747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 243847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 243947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 244047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 244147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables 244247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 244347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 244447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord) 244547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SendResponses ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 244647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = m->ResourceRecords; 244747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord) 244847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 244947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr = m->CurrentRecord; 245047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = rr->next; 245147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 245247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->SendRNow) 245347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 245447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ARType != AuthRecordLocalOnly && rr->ARType != AuthRecordP2P) 245547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SendResponses: No active interface %p to send: %p %02X %s", rr->SendRNow, rr->resrec.InterfaceID, rr->resrec.RecordType, ARDisplayString(m, rr)); 245647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendRNow = mDNSNULL; 245747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 245847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 245947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedAnswer || rr->resrec.RecordType == kDNSRecordTypeDeregistering) 246047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 246147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client 246247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 246347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeDeregistering && rr->AnnounceCount == 0) 246447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 246547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For Unicast, when we get the response from the server, we will call CompleteDeregistration 246647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AuthRecord_uDNS(rr)) CompleteDeregistration(m, rr); // Don't touch rr after this 246747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 246847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 246947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 247047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAnswer = mDNSNULL; 247147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedUnicast = mDNSfalse; 247247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->v4Requester = zerov4Addr; 247347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->v6Requester = zerov6Addr; 247447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 247547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 247647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 247747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("SendResponses: Next in %ld ticks", m->NextScheduledResponse - m->timenow); 247847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 247947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 248047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache, 248147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// so we want to be lazy about how frequently we do it. 248247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 1. If a cache record is currently referenced by *no* active questions, 248347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// then we don't mind expiring it up to a minute late (who will know?) 248447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 2. Else, if a cache record is due for some of its final expiration queries, 248547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// we'll allow them to be late by up to 2% of the TTL 248647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 3. Else, if a cache record has completed all its final expiration queries without success, 248747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late 248847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets), 248947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// so allow at most 1/10 second lateness 249047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately 249147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients). 249247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define CacheCheckGracePeriod(RR) ( \ 249347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \ 249447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \ 249547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \ 249647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ((RR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0) 249747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 249847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define NextCacheCheckEvent(RR) ((RR)->NextRequiredQuery + CacheCheckGracePeriod(RR)) 249947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 250047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void ScheduleNextCacheCheckTime(mDNS *const m, const mDNSu32 slot, const mDNSs32 event) 250147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 250247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rrcache_nextcheck[slot] - event > 0) 250347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_nextcheck[slot] = event; 250447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextCacheCheck - event > 0) 250547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextCacheCheck = event; 250647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 250747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 250847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: MUST call SetNextCacheCheckTimeForRecord any time we change: 250947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->TimeRcvd 251047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->resrec.rroriginalttl 251147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->UnansweredQueries 251247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr->CRActiveQuestion 251347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SetNextCacheCheckTimeForRecord(mDNS *const m, CacheRecord *const rr) 251447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 251547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NextRequiredQuery = RRExpireTime(rr); 251647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 251747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we have an active question, then see if we want to schedule a refresher query for this record. 251847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Usually we expect to do four queries, at 80-82%, 85-87%, 90-92% and then 95-97% of the TTL. 251947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries) 252047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 252147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries); 252247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50); 252347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("SetNextCacheCheckTimeForRecord: NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks for %s", 252447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m,rr)); 252547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 252647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 252747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ScheduleNextCacheCheckTime(m, HashSlot(rr->resrec.name), NextCacheCheckEvent(rr)); 252847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 252947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 253047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5) 253147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5) 253247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 5) 253347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30) 253447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 253547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval) 253647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 253747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (interval < kMinimumReconfirmTime) 253847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt interval = kMinimumReconfirmTime; 253947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (interval > 0x10000000) // Make sure interval doesn't overflow when we multiply by four below 254047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt interval = 0x10000000; 254147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 254247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the expected expiration time for this record is more than interval+33%, then accelerate its expiration 254347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRExpireTime(rr) - m->timenow > (mDNSs32)((interval * 4) / 3)) 254447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 254547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Add a 33% random amount to the interval, to avoid synchronization between multiple hosts 254647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For all the reconfirmations in a given batch, we want to use the same random value 254747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so that the reconfirmation questions can be grouped into a single query packet 254847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(0x3FFFFFFF); 254947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt interval += m->RandomReconfirmDelay % ((interval/3) + 1); 255047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->TimeRcvd = m->timenow - (mDNSs32)interval * 3; 255147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rroriginalttl = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond; 255247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextCacheCheckTimeForRecord(m, rr); 255347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 255447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p", 255547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr), rr->CRActiveQuestion); 255647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); 255747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 255847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 255947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define MaxQuestionInterval (3600 * mDNSPlatformOneSecond) 256047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 256147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// BuildQuestion puts a question into a DNS Query packet and if successful, updates the value of queryptr. 256247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// It also appends to the list of known answer records that need to be included, 256347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// and updates the forcast for the size of the known answer section. 256447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **queryptr, DNSQuestion *q, 256547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord ***kalistptrptr, mDNSu32 *answerforecast) 256647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 256747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353; 256847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0); 256947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData; 257047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *newptr = putQuestion(query, *queryptr, limit - *answerforecast, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit)); 257147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!newptr) 257247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 257347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 257447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSfalse); 257547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 257647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 257747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 257847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 forecast = *answerforecast; 257947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = HashSlot(&q->qname); 258047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 258147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr; 258247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord **ka = *kalistptrptr; // Make a working copy of the pointer we're going to update 258347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 258447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache, 258547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface 258647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !(rr->resrec.RecordType & kDNSRecordTypeUniqueMask) && // which is a shared (i.e. not unique) record type 258747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not already in the known answer list 258847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet 258947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question 259047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away 259147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformOneSecond) // (also ensures we never include goodbye records with TTL=1) 259247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 259347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We don't want to include unique records in the Known Answer section. The Known Answer section 259447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // is intended to suppress floods of shared-record replies from many other devices on the network. 259547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // That concept really does not apply to unique records, and indeed if we do send a query for 259647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which we have a unique record already in our cache, then including that unique record as a 259747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Known Answer, so as to suppress the only answer we were expecting to get, makes little sense. 259847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 259947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ka = rr; // Link this record into our known answer chain 260047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ka = &rr->NextInKAList; 260147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n) 260247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt forecast += 12 + rr->resrec.rdestimate; 260347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we're trying to put more than one question in this packet, and it doesn't fit 260447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then undo that last question and try again next time 260547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (query->h.numQuestions > 1 && newptr + forecast >= limit) 260647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 260747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d", 260847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qname.c, DNSTypeName(q->qtype), newptr + forecast - query->data); 260947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->h.numQuestions--; 261047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ka = *kalistptrptr; // Go back to where we started and retract these answer records 261147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*ka) { CacheRecord *c = *ka; *ka = mDNSNULL; ka = &c->NextInKAList; } 261247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSfalse); // Return false, so we'll try again in the next packet 261347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 261447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 261547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 261647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Success! Update our state pointers, increment UnansweredQueries as appropriate, and return 261747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *queryptr = newptr; // Update the packet pointer 261847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *answerforecast = forecast; // Update the forecast 261947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *kalistptrptr = ka; // Update the known answer list pointer 262047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ucast) q->ExpectUnicastResp = NonZeroTime(m->timenow); 262147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 262247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // For every resource record in our cache, 262347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface 262447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not in the known answer list 262547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameNameRecordAnswersQuestion(&rr->resrec, q)) // which answers our question 262647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 262747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UnansweredQueries++; // indicate that we're expecting a response 262847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastUnansweredTime = m->timenow; 262947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextCacheCheckTimeForRecord(m, rr); 263047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 263147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 263247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNStrue); 263347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 263447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 263547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 263647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// When we have a query looking for a specified name, but there appear to be no answers with 263747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// that name, ReconfirmAntecedents() is called with depth=0 to start the reconfirmation process 263847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// for any records in our cache that reference the given name (e.g. PTR and SRV records). 263947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// For any such cache record we find, we also recursively call ReconfirmAntecedents() for *its* name. 264047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// We increment depth each time we recurse, to guard against possible infinite loops, with a limit of 5. 264147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// A typical reconfirmation scenario might go like this: 264247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Depth 0: Name "myhost.local" has no address records 264347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Depth 1: SRV "My Service._example._tcp.local." refers to "myhost.local"; may be stale 264447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Depth 2: PTR "_example._tcp.local." refers to "My Service"; may be stale 264547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Depth 3: PTR "_services._dns-sd._udp.local." refers to "_example._tcp.local."; may be stale 264647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Currently depths 4 and 5 are not expected to occur; if we did get to depth 5 we'd reconfim any records we 264747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// found referring to the given name, but not recursively descend any further reconfirm *their* antecedents. 264847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const int depth) 264947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 265047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 265147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg; 265247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *cr; 265347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("ReconfirmAntecedents (depth=%d) for %##s", depth, name->c); 265447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt FORALL_CACHERECORDS(slot, cg, cr) 265547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 265647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainname *crtarget = GetRRDomainNameTarget(&cr->resrec); 265747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (crtarget && cr->resrec.rdatahash == namehash && SameDomainName(crtarget, name)) 265847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 265947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth, CRDisplayString(m, cr)); 266047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); 266147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (depth < 5) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, depth+1); 266247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 266347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 266447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 266547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 266647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If we get no answer for a AAAA query, then before doing an automatic implicit ReconfirmAntecedents 266747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// we check if we have an address record for the same name. If we do have an IPv4 address for a given 266847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// name but not an IPv6 address, that's okay (it just means the device doesn't do IPv6) so the failure 266947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// to get a AAAA response is not grounds to doubt the PTR/SRV chain that lead us to that name. 267047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal const CacheRecord *CacheHasAddressTypeForName(mDNS *const m, const domainname *const name, const mDNSu32 namehash) 267147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 267247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *const cg = CacheGroupForName(m, HashSlot(name), namehash, name); 267347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const CacheRecord *cr = cg ? cg->members : mDNSNULL; 267447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (cr && !RRTypeIsAddressType(cr->resrec.rrtype)) cr=cr->next; 267547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(cr); 267647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 267747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 267847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal const CacheRecord *FindSPSInCache1(mDNS *const m, const DNSQuestion *const q, const CacheRecord *const c0, const CacheRecord *const c1) 267947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 268047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *const cg = CacheGroupForName(m, HashSlot(&q->qname), q->qnamehash, &q->qname); 268147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const CacheRecord *cr, *bestcr = mDNSNULL; 268247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 bestmetric = 1000000; 268347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) 268447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->resrec.rrtype == kDNSType_PTR && cr->resrec.rdlength >= 6) // If record is PTR type, with long enough name, 268547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr != c0 && cr != c1) // that's not one we've seen before, 268647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameNameRecordAnswersQuestion(&cr->resrec, q)) // and answers our browse query, 268747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!IdenticalSameNameRecord(&cr->resrec, &m->SPSRecords.RR_PTR.resrec)) // and is not our own advertised service... 268847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 268947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 metric = SPSMetric(cr->resrec.rdata->u.name.c); 269047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (bestmetric > metric) { bestmetric = metric; bestcr = cr; } 269147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 269247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(bestcr); 269347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 269447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 269547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Finds the three best Sleep Proxies we currently have in our cache 269647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3]) 269747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 269847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sps[0] = FindSPSInCache1(m, q, mDNSNULL, mDNSNULL); 269947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sps[1] = !sps[0] ? mDNSNULL : FindSPSInCache1(m, q, sps[0], mDNSNULL); 270047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sps[2] = !sps[1] ? mDNSNULL : FindSPSInCache1(m, q, sps[0], sps[1]); 270147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 270247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 270347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Only DupSuppressInfos newer than the specified 'time' are allowed to remain active 270447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time) 270547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 270647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 270747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL; 270847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 270947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 271047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time, mDNSInterfaceID InterfaceID) 271147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 271247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 271347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL; 271447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 271547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 271647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool SuppressOnThisInterface(const DupSuppressInfo ds[DupSuppressInfoSize], const NetworkInterfaceInfo * const intf) 271747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 271847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 271947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool v4 = !intf->IPv4Available; // If this interface doesn't do v4, we don't need to find a v4 duplicate of this query 272047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool v6 = !intf->IPv6Available; // If this interface doesn't do v6, we don't need to find a v6 duplicate of this query 272147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<DupSuppressInfoSize; i++) 272247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ds[i].InterfaceID == intf->InterfaceID) 272347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 272447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ds[i].Type == mDNSAddrType_IPv4) v4 = mDNStrue; 272547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (ds[i].Type == mDNSAddrType_IPv6) v6 = mDNStrue; 272647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (v4 && v6) return(mDNStrue); 272747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 272847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSfalse); 272947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 273047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 273147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int RecordDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 Time, mDNSInterfaceID InterfaceID, mDNSs32 Type) 273247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 273347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i, j; 273447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 273547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // See if we have this one in our list somewhere already 273647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Type == Type) break; 273747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 273847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If not, find a slot we can re-use 273947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (i >= DupSuppressInfoSize) 274047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 274147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt i = 0; 274247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (j=1; j<DupSuppressInfoSize && ds[i].InterfaceID; j++) 274347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ds[j].InterfaceID || ds[j].Time - ds[i].Time < 0) 274447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt i = j; 274547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 274647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 274747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Record the info about this query we saw 274847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ds[i].Time = Time; 274947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ds[i].InterfaceID = InterfaceID; 275047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ds[i].Type = Type; 275147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 275247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(i); 275347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 275447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 275547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void mDNSSendWakeOnResolve(mDNS *const m, DNSQuestion *q) 275647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 275747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int len, i, cnt; 275847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSInterfaceID InterfaceID = q->InterfaceID; 275947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainname *d = &q->qname; 276047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 276147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We can't send magic packets without knowing which interface to send it on. 276247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (InterfaceID == mDNSInterface_Any || InterfaceID == mDNSInterface_LocalOnly || InterfaceID == mDNSInterface_P2P) 276347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 276447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSSendWakeOnResolve: ERROR!! Invalid InterfaceID %p for question %##s", InterfaceID, q->qname.c); 276547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 276647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 276747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 276847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Split MAC@IPAddress and pass them separately 276947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt len = d->c[0]; 277047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt i = 1; 277147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cnt = 0; 277247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i = 1; i < len; i++) 277347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 277447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (d->c[i] == '@') 277547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 277647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char EthAddr[18]; // ethernet adddress : 12 bytes + 5 ":" + 1 NULL byte 277747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char IPAddr[47]; // Max IP address len: 46 bytes (IPv6) + 1 NULL byte 277847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cnt != 5) 277947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 278047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSSendWakeOnResolve: ERROR!! Malformed Ethernet address %##s, cnt %d", q->qname.c, cnt); 278147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 278247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 278347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((i - 1) > (int) (sizeof(EthAddr) - 1)) 278447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 278547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSSendWakeOnResolve: ERROR!! Malformed Ethernet address %##s, length %d", q->qname.c, i - 1); 278647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 278747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 278847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((len - i) > (int)(sizeof(IPAddr) - 1)) 278947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 279047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSSendWakeOnResolve: ERROR!! Malformed IP address %##s, length %d", q->qname.c, len - i); 279147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 279247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 279347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemCopy(EthAddr, &d->c[1], i - 1); 279447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt EthAddr[i - 1] = 0; 279547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemCopy(IPAddr, &d->c[i + 1], len - i); 279647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt IPAddr[len - i] = 0; 279747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformSendWakeupPacket(m, InterfaceID, EthAddr, IPAddr, InitialWakeOnResolveCount - q->WakeOnResolveCount); 279847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 279947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 280047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (d->c[i] == ':') 280147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cnt++; 280247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 280347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSSendWakeOnResolve: ERROR!! Malformed WakeOnResolve name %##s", q->qname.c); 280447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 280547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 280647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 280747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q) 280847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 280947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If more than 90% of the way to the query time, we should unconditionally accelerate it 281047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/10)) 281147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNStrue); 281247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 281347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If half-way to next scheduled query time, only accelerate if it will add less than 512 bytes to the packet 281447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/2)) 281547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 281647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We forecast: qname (n) type (2) class (2) 281747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4; 281847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = HashSlot(&q->qname); 281947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 282047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const CacheRecord *rr; 282147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache, 282247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet 282347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question 282447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 && // and it is less than half-way to expiry 282547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0)// and we'll ask at least once again before NextRequiredQuery 282647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 282747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n) 282847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt forecast += 12 + rr->resrec.rdestimate; 282947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (forecast >= 512) return(mDNSfalse); // If this would add 512 bytes or more to the packet, don't accelerate 283047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 283147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNStrue); 283247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 283347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 283447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSfalse); 283547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 283647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 283747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// How Standard Queries are generated: 283847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 1. The Question Section contains the question 283947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 2. The Additional Section contains answers we already know, to suppress duplicate responses 284047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 284147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// How Probe Queries are generated: 284247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 1. The Question Section contains queries for the name we intend to use, with QType=ANY because 284347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// if some other host is already using *any* records with this name, we want to know about it. 284447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 2. The Authority Section contains the proposed values we intend to use for one or more 284547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// of our records with that name (analogous to the Update section of DNS Update packets) 284647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// because if some other host is probing at the same time, we each want to know what the other is 284747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// planning, in order to apply the tie-breaking rule to see who gets to use the name and who doesn't. 284847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 284947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SendQueries(mDNS *const m) 285047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 285147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 285247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg; 285347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *cr; 285447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *ar; 285547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int pktcount = 0; 285647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 285747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval 285847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 maxExistingQuestionInterval = 0; 285947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces); 286047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *KnownAnswerList = mDNSNULL; 286147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 286247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. If time for a query, work out what we need to do 286347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 286447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We're expecting to send a query anyway, so see if any expiring cache records are close enough 286547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to their NextRequiredQuery to be worth batching them together with this one 286647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt FORALL_CACHERECORDS(slot, cg, cr) 286747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries) 286847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow + TicksTTL(cr)/50 - cr->NextRequiredQuery >= 0) 286947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 287047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("Sending %d%% cache expiration query for %s", 80 + 5 * cr->UnansweredQueries, CRDisplayString(m, cr)); 287147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q = cr->CRActiveQuestion; 287247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(cr)/20, cr->resrec.InterfaceID); 287347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For uDNS queries (TargetQID non-zero) we adjust LastQTime, 287447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly 287547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->Target.type) q->SendQNow = mDNSInterfaceMark; // If targeted query, mark it 287647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (!mDNSOpaque16IsZero(q->TargetQID)) { q->LastQTime = m->timenow - q->ThisQInterval; cr->UnansweredQueries++; } 287747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (q->SendQNow == mDNSNULL) q->SendQNow = cr->resrec.InterfaceID; 287847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (q->SendQNow != cr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark; 287947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 288047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 288147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Scan our list of questions to see which: 288247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *WideArea* queries need to be sent 288347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *unicast* queries need to be sent 288447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *multicast* queries we're definitely going to send 288547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 288647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 288747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = m->Questions; 288847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 288947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 289047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q = m->CurrentQuestion; 289147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow))) 289247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 289347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *qptr = m->omsg.data; 289447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data); 289547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 289647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time 289747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort); 289847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->LocalSocket) 289947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 290047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags); 290147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass); 290247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, q->LocalSocket, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL); 290347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval *= QuestionIntervalStep; 290447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 290547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->ThisQInterval > MaxQuestionInterval) 290647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval = MaxQuestionInterval; 290747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTime = m->timenow; 290847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTxTime = m->timenow; 290947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->RecentAnswerPkts = 0; 291047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->SendQNow = mDNSNULL; 291147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ExpectUnicastResp = NonZeroTime(m->timenow); 291247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 291347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow)) 291447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 291547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - NextQSendTime(q)); 291647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces 291747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (maxExistingQuestionInterval < q->ThisQInterval) 291847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt maxExistingQuestionInterval = q->ThisQInterval; 291947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 292047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If m->CurrentQuestion wasn't modified out from under us, advance it now 292147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having 292247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // m->CurrentQuestion point to the right question 292347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q == m->CurrentQuestion) m->CurrentQuestion = m->CurrentQuestion->next; 292447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 292547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentQuestion) 292647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 292747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("SendQueries question loop 1: Skipping NewQuestion %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 292847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = m->CurrentQuestion->next; 292947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 293047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 293147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 293247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Scan our list of questions 293347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (a) to see if there are any more that are worth accelerating, and 293447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (b) to update the state variables for *all* the questions we're going to send 293547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list, 293647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very 293747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value. 293847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledQuery = m->timenow + 0x78000000; 293947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q && q != m->NewQuestions; q=q->next) 294047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 294147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow || 294247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q)))) 294347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 294447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If at least halfway to next query time, advance to next interval 294547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If less than halfway to next query time, then 294647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // treat this as logically a repeat of the last transmission, without advancing the interval 294747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - (q->LastQTime + (q->ThisQInterval/2)) >= 0) 294847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 294947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //LogInfo("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - NextQSendTime(q)); 295047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces 295147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d", 295247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval / InitialQuestionInterval, q->RequestUnicast); 295347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval *= QuestionIntervalStep; 295447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->ThisQInterval > MaxQuestionInterval) 295547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval = MaxQuestionInterval; 295647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep3 && !q->RequestUnicast && 295747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !(RRTypeIsAddressType(q->qtype) && CacheHasAddressTypeForName(m, &q->qname, q->qnamehash))) 295847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 295947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Generally don't need to log this. 296047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // It's not especially noteworthy if a query finds no results -- this usually happens for domain 296147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa") 296247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and when there simply happen to be no instances of the service the client is looking 296347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // for (e.g. iTunes is set to look for RAOP devices, and the current network has none). 296447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents", 296547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qname.c, DNSTypeName(q->qtype)); 296647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Sending third query, and no answers yet; time to begin doubting the source 296747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0); 296847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 296947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 297047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 297147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Mark for sending. (If no active interfaces, then don't even try.) 297247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->SendOnAll = (q->SendQNow == mDNSInterfaceMark); 297347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->SendOnAll) 297447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 297547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->SendQNow = !intf ? mDNSNULL : (q->InterfaceID) ? q->InterfaceID : intf->InterfaceID; 297647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTime = m->timenow; 297747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 297847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 297947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we recorded a duplicate suppression for this question less than half an interval ago, 298047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then we consider it recent enough that we don't need to do an identical query ourselves. 298147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2); 298247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 298347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTxTime = m->timenow; 298447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->RecentAnswerPkts = 0; 298547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->RequestUnicast) q->RequestUnicast--; 298647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 298747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For all questions (not just the ones we're sending) check what the next scheduled event will be 298847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We don't need to consider NewQuestions here because for those we'll set m->NextScheduledQuery in AnswerNewQuestion 298947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextQueryTime(m,q); 299047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 299147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 299247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. Scan our authoritative RR list to see what probes we might need to send 299347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 299447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledProbe = m->timenow + 0x78000000; 299547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 299647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord) 299747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 299847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = m->ResourceRecords; 299947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord) 300047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 300147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar = m->CurrentRecord; 300247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = ar->next; 300347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AuthRecord_uDNS(ar) && ar->resrec.RecordType == kDNSRecordTypeUnique) // For all records that are still probing... 300447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 300547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly 300647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - (ar->LastAPTime + ar->ThisAPInterval) < 0) 300747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 300847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextAnnounceProbeTime(m, ar); 300947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 301047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly 301147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (ar->ProbeCount) 301247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 301347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ar->AddressProxy.type == mDNSAddrType_IPv4) 301447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 301547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("SendQueries ARP Probe %d %s %s", ar->ProbeCount, InterfaceNameForID(m, ar->resrec.InterfaceID), ARDisplayString(m,ar)); 301647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendARP(m, 1, ar, &zerov4Addr, &zeroEthAddr, &ar->AddressProxy.ip.v4, &ar->WakeUp.IMAC); 301747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 301847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (ar->AddressProxy.type == mDNSAddrType_IPv6) 301947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 302047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("SendQueries NDP Probe %d %s %s", ar->ProbeCount, InterfaceNameForID(m, ar->resrec.InterfaceID), ARDisplayString(m,ar)); 302147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // IPv6 source = zero 302247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // No target hardware address 302347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // IPv6 target address is address we're probing 302447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Ethernet destination address is Ethernet interface address of the Sleep Proxy client we're probing 302547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendNDP(m, NDP_Sol, 0, ar, &zerov6Addr, mDNSNULL, &ar->AddressProxy.ip.v6, &ar->WakeUp.IMAC); 302647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 302747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Mark for sending. (If no active interfaces, then don't even try.) 302847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->SendRNow = (!intf || ar->WakeUp.HMAC.l[0]) ? mDNSNULL : ar->resrec.InterfaceID ? ar->resrec.InterfaceID : intf->InterfaceID; 302947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->LastAPTime = m->timenow; 303047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When we have a late conflict that resets a record to probing state we use a special marker value greater 303147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // than DefaultProbeCountForTypeUnique. Here we detect that state and reset ar->ProbeCount back to the right value. 303247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ar->ProbeCount > DefaultProbeCountForTypeUnique) 303347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->ProbeCount = DefaultProbeCountForTypeUnique; 303447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->ProbeCount--; 303547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextAnnounceProbeTime(m, ar); 303647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ar->ProbeCount == 0) 303747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 303847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this is the last probe for this record, then see if we have any matching records 303947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // on our duplicate list which should similarly have their ProbeCount cleared to zero... 304047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *r2; 304147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r2 = m->DuplicateRecords; r2; r2=r2->next) 304247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, ar)) 304347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->ProbeCount = 0; 304447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // ... then acknowledge this record to the client. 304547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We do this optimistically, just as we're about to send the third probe. 304647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This helps clients that both advertise and browse, and want to filter themselves 304747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // from the browse results list, because it helps ensure that the registration 304847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // confirmation will be delivered 1/4 second *before* the browse "add" event. 304947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // A potential downside is that we could deliver a registration confirmation and then find out 305047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // moments later that there's a name conflict, but applications have to be prepared to handle 305147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new. 305247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ar->Acknowledged) AcknowledgeRecord(m, ar); 305347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 305447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 305547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // else, if it has now finished probing, move it to state Verified, 305647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and update m->NextScheduledResponse so it will be announced 305747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 305847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 305947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ar->Acknowledged) AcknowledgeRecord(m, ar); // Defensive, just in case it got missed somehow 306047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->resrec.RecordType = kDNSRecordTypeVerified; 306147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique; 306247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->LastAPTime = m->timenow - DefaultAnnounceIntervalForTypeUnique; 306347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextAnnounceProbeTime(m, ar); 306447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 306547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 306647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 306747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = m->DuplicateRecords; 306847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord) 306947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 307047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar = m->CurrentRecord; 307147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = ar->next; 307247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ar->resrec.RecordType == kDNSRecordTypeUnique && ar->ProbeCount == 0 && !ar->Acknowledged) 307347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AcknowledgeRecord(m, ar); 307447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 307547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 307647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3. Now we know which queries and probes we're sending, 307747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // go through our interface list sending the appropriate queries on each interface 307847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (intf) 307947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 308047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const int OwnerRecordSpace = (m->AnnounceOwner && intf->MAC.l[0]) ? DNSOpt_Header_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC) : 0; 308147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *queryptr = m->omsg.data; 308247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags); 308347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (KnownAnswerList) verbosedebugf("SendQueries: KnownAnswerList set... Will continue from previous packet"); 308447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!KnownAnswerList) 308547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 308647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Start a new known-answer list 308747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord **kalistptr = &KnownAnswerList; 308847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 answerforecast = OwnerRecordSpace; // We start by assuming we'll need at least enough space to put the Owner Option 308947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 309047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Put query questions in this packet 309147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q && q != m->NewQuestions; q=q->next) 309247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 309347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow == intf->InterfaceID)) 309447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 309547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d", 309647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting ", 309747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qname.c, DNSTypeName(q->qtype), queryptr - m->omsg.data, queryptr + answerforecast - m->omsg.data); 309847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 309947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we're suppressing this question, or we successfully put it, update its SendQNow state 310047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SuppressOnThisInterface(q->DupSuppress, intf) || 310147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast)) 310247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 310347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf); 310447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->WakeOnResolveCount) 310547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 310647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSSendWakeOnResolve(m, q); 310747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->WakeOnResolveCount--; 310847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 310947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 311047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 311147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 311247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 311347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Put probe questions in this packet 311447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (ar = m->ResourceRecords; ar; ar=ar->next) 311547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ar->SendRNow == intf->InterfaceID) 311647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 311747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool ucast = (ar->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353; 311847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0); 311947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.numQuestions ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData); 312047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n) 312147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 forecast = answerforecast + 12 + ar->resrec.rdestimate; 312247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit - forecast, ar->resrec.name, kDNSQType_ANY, (mDNSu16)(ar->resrec.rrclass | ucbit)); 312347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newptr) 312447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 312547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt queryptr = newptr; 312647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt answerforecast = forecast; 312747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->SendRNow = (ar->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf); 312847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->IncludeInProbe = mDNStrue; 312947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d", 313047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->resrec.name->c, DNSTypeName(ar->resrec.rrtype), ar->ProbeCount); 313147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 313247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 313347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 313447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 313547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Put our known answer list (either new one from this question or questions, or remainder of old one from last time) 313647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (KnownAnswerList) 313747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 313847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *ka = KnownAnswerList; 313947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - ka->TimeRcvd)) / mDNSPlatformOneSecond; 314047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *newptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAnswers, 314147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd, m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace); 314247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newptr) 314347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 314447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("SendQueries: Put %##s (%s) at %d - %d", 314547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ka->resrec.name->c, DNSTypeName(ka->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data); 314647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt queryptr = newptr; 314747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt KnownAnswerList = ka->NextInKAList; 314847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ka->NextInKAList = mDNSNULL; 314947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 315047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 315147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 315247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we ran out of space and we have more than one question in the packet, that's an error -- 315347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we shouldn't have put more than one question if there was a risk of us running out of space. 315447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->omsg.h.numQuestions > 1) 315547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SendQueries: Put %d answers; No more space for known answers", m->omsg.h.numAnswers); 315647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.flags.b[0] |= kDNSFlag0_TC; 315747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 315847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 315947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 316047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 316147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (ar = m->ResourceRecords; ar; ar=ar->next) 316247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ar->IncludeInProbe) 316347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 316447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &ar->resrec); 316547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->IncludeInProbe = mDNSfalse; 316647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newptr) queryptr = newptr; 316747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else LogMsg("SendQueries: How did we fail to have space for the Update record %s", ARDisplayString(m,ar)); 316847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 316947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 317047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (queryptr > m->omsg.data) 317147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 317247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (OwnerRecordSpace) 317347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 317447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord opt; 317547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); 317647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rrclass = NormalMaxDNSMessageData; 317747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record 317847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdestimate = sizeof(rdataOPT); 317947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]); 318047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("SendQueries putting %s", ARDisplayString(m, &opt)); 318147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt queryptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAdditionals, 318247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData); 318347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!queryptr) 318447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SendQueries: How did we fail to have space for the OPT record (%d/%d/%d/%d) %s", 318547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt)); 318647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (queryptr > m->omsg.data + NormalMaxDNSMessageData) 318747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->omsg.h.numQuestions != 1 || m->omsg.h.numAnswers != 0 || m->omsg.h.numAuthorities != 1 || m->omsg.h.numAdditionals != 1) 318847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SendQueries: Why did we generate oversized packet with OPT record %p %p %p (%d/%d/%d/%d) %s", 318947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.data, m->omsg.data + NormalMaxDNSMessageData, queryptr, 319047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt)); 319147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 319247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 319347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1) 319447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions); 319547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %p", 319647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s", 319747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s", 319847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID); 319947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL); 320047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL); 320147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10); 320247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (++pktcount >= 1000) 320347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; } 320447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // There might be more records left in the known answer list, or more questions to send 320547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // on this interface, so go around one more time and try again. 320647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 320747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else // Nothing more to send on this interface; go to next 320847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 320947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next); 321047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #if MDNS_DEBUGMSGS && 0 321147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *const msg = next ? "SendQueries: Nothing more on %p; moving to %p" : "SendQueries: Nothing more on %p"; 321247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf(msg, intf, next); 321347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #endif 321447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf = next; 321547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 321647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 321747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 321847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 4. Final housekeeping 321947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 322047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 4a. Debugging check: Make sure we announced all our records 322147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (ar = m->ResourceRecords; ar; ar=ar->next) 322247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ar->SendRNow) 322347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 322447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ar->ARType != AuthRecordLocalOnly && ar->ARType != AuthRecordP2P) 322547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SendQueries: No active interface %p to send probe: %p %s", ar->SendRNow, ar->resrec.InterfaceID, ARDisplayString(m, ar)); 322647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->SendRNow = mDNSNULL; 322747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 322847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 322947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope 323047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that their interface which went away might come back again, the logic will want to send queries 323147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // for those records, but we can't because their interface isn't here any more, so to keep the 323247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // state machine ticking over we just pretend we did so. 323347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the interface does not come back in time, the cache record will expire naturally 323447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt FORALL_CACHERECORDS(slot, cg, cr) 323547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries) 323647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow + TicksTTL(cr)/50 - cr->NextRequiredQuery >= 0) 323747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 323847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->UnansweredQueries++; 323947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->CRActiveQuestion->SendQNow = mDNSNULL; 324047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextCacheCheckTimeForRecord(m, cr); 324147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 324247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 324347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 4c. Debugging check: Make sure we sent all our planned questions 324447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions 324547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we legitimately couldn't send because the interface is no longer available 324647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) 324747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->SendQNow) 324847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 324947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *x; 325047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (x = m->NewQuestions; x; x=x->next) if (x == q) break; // Check if this question is a NewQuestion 325147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SendQueries: No active interface %p to send %s question: %p %##s (%s)", q->SendQNow, x ? "new" : "old", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype)); 325247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->SendQNow = mDNSNULL; 325347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 325447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 325547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 325647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password) 325747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 325847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i, j; 325947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *ptr = m->omsg.data; 326047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); 326147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!intf) { LogMsg("SendARP: No interface with InterfaceID %p found", InterfaceID); return; } 326247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 326347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x00 Destination address 326447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<6; i++) *ptr++ = EthAddr->b[i]; 326547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 326647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us) 326747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<6; i++) *ptr++ = intf->MAC.b[0]; 326847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 326947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x0C Ethertype (0x0842) 327047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x08; 327147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *ptr++ = 0x42; 327247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 327347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x0E Wakeup sync sequence 327447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<6; i++) *ptr++ = 0xFF; 327547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 327647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x14 Wakeup data 327747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (j=0; j<16; j++) for (i=0; i<6; i++) *ptr++ = EthAddr->b[i]; 327847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 327947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 0x74 Password 328047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<6; i++) *ptr++ = password->b[i]; 328147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 328247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID); 328347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 328447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For Ethernet switches that don't flood-foward packets with unknown unicast destination MAC addresses, 328547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // broadcast is the only reliable way to get a wakeup packet to the intended target machine. 328647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For 802.11 WPA networks, where a sleeping target machine may have missed a broadcast/multicast 328747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // key rotation, unicast is the only way to get a wakeup packet to the intended target machine. 328847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // So, we send one of each, unicast first, then broadcast second. 328947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<6; i++) m->omsg.data[i] = 0xFF; 329047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID); 329147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 329247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 329347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// *************************************************************************** 329447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK 329547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - 329647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - RR List Management & Task Management 329747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 329847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 329947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list. 330047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this. 330147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion, 330247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// which will be auto-advanced (possibly to NULL) if the client callback cancels the question. 330347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord) 330447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 330547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *const q = m->CurrentQuestion; 330647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool followcname = FollowCNAME(q, &rr->resrec, AddRecord); 330747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 330847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", 330947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr)); 331047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 331147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Normally we don't send out the unicast query if we have answered using our local only auth records e.g., /etc/hosts. 331247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // But if the query for "A" record has a local answer but query for "AAAA" record has no local answer, we might 331347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // send the AAAA query out which will come back with CNAME and will also answer the "A" query. To prevent that, 331447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we check to see if that query already has a unique local answer. 331547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->LOAddressAnswers) 331647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 331747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("AnswerCurrentQuestionWithResourceRecord: Question %p %##s (%s) not answering with record %s due to " 331847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "LOAddressAnswers %d", q, q->qname.c, DNSTypeName(q->qtype), ARDisplayString(m, rr), 331947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LOAddressAnswers); 332047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 332147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 332247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 332347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (QuerySuppressed(q)) 332447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 332547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the query is suppressed, then we don't want to answer from the cache. But if this query is 332647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // supposed to time out, we still want to callback the clients. We do this only for TimeoutQuestions 332747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that are timing out, which we know are answered with Negative cache record when timing out. 332847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q->TimeoutQuestion || rr->resrec.RecordType != kDNSRecordTypePacketNegative || (m->timenow - q->StopTime < 0)) 332947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 333047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 333147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 333247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue) 333347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // may be called twice, once when the record is received, and again when it's time to notify local clients. 333447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this. 333547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 333647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastUsed = m->timenow; 333747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q) 333847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 333947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count 334047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion from %p to %p for cache record %s, CurrentAnswer %d", 334147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->CRActiveQuestion, q, CRDisplayString(m,rr), q->CurrentAnswers); 334247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->CRActiveQuestion = q; // We know q is non-null 334347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextCacheCheckTimeForRecord(m, rr); 334447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 334547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 334647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this is: 334747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (a) a no-cache add, where we've already done at least one 'QM' query, or 334847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (b) a normal add, where we have at least one unique-type answer, 334947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then there's no need to keep polling the network. 335047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.) 335147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We do this for mDNS questions and uDNS one-shot questions, but not for 335247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // uDNS LongLived questions, because that would mess up our LLQ lease renewal timing. 335347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((AddRecord == QC_addnocache && !q->RequestUnicast) || 335447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (AddRecord == QC_add && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)))) 335547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ActiveQuestion(q) && (mDNSOpaque16IsZero(q->TargetQID) || !q->LongLived)) 335647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 335747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTime = m->timenow; 335847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTxTime = m->timenow; 335947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->RecentAnswerPkts = 0; 336047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval = MaxQuestionInterval; 336147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->RequestUnicast = mDNSfalse; 336247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("AnswerCurrentQuestionWithResourceRecord: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 336347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 336447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 336547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us 336647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 336747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Only deliver negative answers if client has explicitly requested them 336847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypePacketNegative || (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype))) 336947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AddRecord || !q->ReturnIntermed) return; 337047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 337147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For CNAME results to non-CNAME questions, only inform the client if they explicitly requested that 337247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->QuestionCallback && !q->NoAnswer && (!followcname || q->ReturnIntermed)) 337347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 337447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DropLockBeforeCallback(); // Allow client (and us) to legally make mDNS API calls 337547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype)) 337647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 337747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord neg; 337847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt MakeNegativeCacheRecord(m, &neg, &q->qname, q->qnamehash, q->qtype, q->qclass, 1, rr->resrec.InterfaceID, q->qDNSServer); 337947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->QuestionCallback(m, q, &neg.resrec, AddRecord); 338047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 338147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 338247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->QuestionCallback(m, q, &rr->resrec, AddRecord); 338347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 338447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 338547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: Proceed with caution here because client callback function is allowed to do anything, 338647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // including starting/stopping queries, registering/deregistering records, etc. 338747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 338847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (followcname && m->CurrentQuestion == q) 338947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerQuestionByFollowingCNAME(m, q, &rr->resrec); 339047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 339147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 339247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// New Questions are answered through AnswerNewQuestion. But there may not have been any 339347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// matching cache records for the questions when it is called. There are two possibilities. 339447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 339547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 1) There are no cache records 339647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 2) There are cache records but the DNSServers between question and cache record don't match. 339747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 339847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In the case of (1), where there are no cache records and later we add them when we get a response, 339947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// CacheRecordAdd/CacheRecordDeferredAdd will take care of adding the cache and delivering the ADD 340047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// events to the application. If we already have a cache entry, then no ADD events are delivered 340147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// unless the RDATA has changed 340247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 340347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In the case of (2) where we had the cache records and did not answer because of the DNSServer mismatch, 340447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// we need to answer them whenever we change the DNSServer. But we can't do it at the instant the DNSServer 340547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// changes because when we do the callback, the question can get deleted and the calling function would not 340647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// know how to handle it. So, we run this function from mDNS_Execute to handle DNSServer changes on the 340747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// question 340847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 340947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void AnswerQuestionsForDNSServerChanges(mDNS *const m) 341047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 341147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 341247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *qnext; 341347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr; 341447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 341547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg; 341647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 341747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 341847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("AnswerQuestionsForDNSServerChanges: ERROR m->CurrentQuestion already set: %##s (%s)", 341947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 342047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 342147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q && q != m->NewQuestions; q = qnext) 342247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 342347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt qnext = q->next; 342447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 342547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // multicast or DNSServers did not change. 342647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSOpaque16IsZero(q->TargetQID)) continue; 342747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q->deliverAddEvents) continue; 342847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 342947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We are going to look through the cache for this question since it changed 343047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // its DNSserver last time. Reset it so that we don't call them again. Calling 343147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // them again will deliver duplicate events to the application 343247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->deliverAddEvents = mDNSfalse; 343347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (QuerySuppressed(q)) continue; 343447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = q; 343547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt slot = HashSlot(&q->qname); 343647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 343747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 343847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 343947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameNameRecordAnswersQuestion(&rr->resrec, q)) 344047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 344147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("AnswerQuestionsForDNSServerChanges: Calling AnswerCurrentQuestionWithResourceRecord for question %p %##s using resource record %s", 344247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q, q->qname.c, CRDisplayString(m, rr)); 344347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When this question penalizes a DNS server and has no more DNS servers to pick, we normally 344447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // deliver a negative cache response and suspend the question for 60 seconds (see uDNS_CheckCurrentQuestion). 344547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // But sometimes we may already find the negative cache entry and deliver that here as the process 344647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // of changing DNS servers. When the cache entry is about to expire, we will resend the question and 344747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that time, we need to make sure that we have a valid DNS server. Otherwise, we will deliver 344847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // a negative cache response without trying the server. 344947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q->qDNSServer && !q->DuplicateOf && rr->resrec.RecordType == kDNSRecordTypePacketNegative) 345047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 345147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *qptr; 345247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetValidDNSServers(m, q); 345347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qDNSServer = GetServerForQuestion(m, q); 345447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (qptr = q->next ; qptr; qptr = qptr->next) 345547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; } 345647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 345747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->CurrentAnswers++; 345847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; 345947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; 346047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); 346147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 346247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 346347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 346447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 346547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 346647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 346747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 346847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr) 346947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 347047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->DelayDelivery = 0; 347147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 347247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", 347347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 347447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = m->Questions; 347547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 347647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 347747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q = m->CurrentQuestion; 347847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 347947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); 348047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 348147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = q->next; 348247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 348347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 348447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 348547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 348647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu32 slot) 348747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 348847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond; // See if there are any records expiring within one second 348947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSs32 start = m->timenow - 0x10000000; 349047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 delay = start; 349147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg = CacheGroupForName(m, slot, namehash, name); 349247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const CacheRecord *rr; 349347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 349447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (threshhold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second 349547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (delay - RRExpireTime(rr) < 0) // then delay until after they've been deleted 349647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt delay = RRExpireTime(rr); 349747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (delay - start > 0) return(NonZeroTime(delay)); 349847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else return(0); 349947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 350047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 350147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// CacheRecordAdd is only called from CreateNewCacheEntry, *never* directly as a result of a client API call. 350247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If new questions are created as a result of invoking client callbacks, they will be added to 350347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// the end of the question list, and m->NewQuestions will be set to indicate the first new question. 350447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr is a new CacheRecord just received into our cache 350547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). 350647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, 350747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// which may change the record list and/or question list. 350847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 350947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) 351047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 351147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 351247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 351347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We stop when we get to NewQuestions -- if we increment their CurrentAnswers/LargeAnswers/UniqueAnswers 351447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion(). 351547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q && q != m->NewQuestions; q=q->next) 351647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 351747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 351847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 351947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this question is one that's actively sending queries, and it's received ten answers within one 352047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // second of sending the last query packet, then that indicates some radical network topology change, 352147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so reset its exponential backoff back to the start. We must be at least at the eight-second interval 352247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating 352347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // because we will anyway send another query within a few seconds. The first reset query is sent out 352447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // randomized over the next four seconds to reduce possible synchronization between machines. 352547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->LastAnswerPktNum != m->PktNum) 352647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 352747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastAnswerPktNum = m->PktNum; 352847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 && 352947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval > InitialQuestionInterval * QuestionIntervalStep3 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond) 353047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 353147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst (%d); restarting exponential backoff sequence (%d)", 353247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qname.c, DNSTypeName(q->qtype), q->RecentAnswerPkts, q->ThisQInterval); 353347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTime = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4); 353447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval = InitialQuestionInterval; 353547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextQueryTime(m,q); 353647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 353747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 353847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("CacheRecordAdd %p %##s (%s) %lu %#a:%d question %p", rr, rr->resrec.name->c, 353947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl, rr->resrec.rDNSServer ? 354047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt &rr->resrec.rDNSServer->addr : mDNSNULL, mDNSVal16(rr->resrec.rDNSServer ? 354147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rDNSServer->port : zeroIPPort), q); 354247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->CurrentAnswers++; 354347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->unansweredQueries = 0; 354447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; 354547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; 354647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->CurrentAnswers > 4000) 354747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 354847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static int msgcount = 0; 354947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (msgcount++ < 10) 355047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack", 355147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers); 355247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rroriginalttl = 0; 355347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UnansweredQueries = MaxUnansweredQueries; 355447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 355547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 355647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 355747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 355847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rr->DelayDelivery) 355947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 356047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 356147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 356247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = m->Questions; 356347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 356447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 356547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q = m->CurrentQuestion; 356647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 356747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); 356847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 356947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = q->next; 357047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 357147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 357247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 357347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 357447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextCacheCheckTimeForRecord(m, rr); 357547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 357647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 357747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call. 357847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If new questions are created as a result of invoking client callbacks, they will be added to 357947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// the end of the question list, and m->NewQuestions will be set to indicate the first new question. 358047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique) 358147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any 358247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists, 358347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network. 358447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, 358547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// which may change the record list and/or question list. 358647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 358747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr) 358847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 358947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c); 359047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 359147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 359247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = m->Questions; 359347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We do this for *all* questions, not stopping when we get to m->NewQuestions, 359447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // since we're not caching the record and we'll get no opportunity to do this later 359547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentQuestion) 359647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 359747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q = m->CurrentQuestion; 359847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 359947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache); // QC_addnocache means "don't expect remove events for this" 360047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 360147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = q->next; 360247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 360347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 360447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 360547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 360647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute. 360747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question. 360847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If new questions are created as a result of invoking client callbacks, they will be added to 360947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// the end of the question list, and m->NewQuestions will be set to indicate the first new question. 361047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// rr is an existing cache CacheRecord that just expired and is being deleted 361147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). 361247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, 361347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// which may change the record list and/or question list. 361447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 361547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr) 361647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 361747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 361847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", 361947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 362047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = m->Questions; 362147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 362247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters 362347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // will all still be zero because we haven't yet gone through the cache counting how many answers we have for them. 362447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 362547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 362647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q = m->CurrentQuestion; 362747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When a question enters suppressed state, we generate RMV events and generate a negative 362847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // response. A cache may be present that answers this question e.g., cache entry generated 362947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // before the question became suppressed. We need to skip the suppressed questions here as 363047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the RMV event has already been generated. 363147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q)) 363247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 363347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr)); 363447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->FlappingInterface1 = mDNSNULL; 363547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->FlappingInterface2 = mDNSNULL; 363647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 363747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When a question changes DNS server, it is marked with deliverAddEvents if we find any 363847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // cache entry corresponding to the new DNS server. Before we deliver the ADD event, the 363947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // cache entry may be removed in which case CurrentAnswers can be zero. 364047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->deliverAddEvents && !q->CurrentAnswers) 364147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 364247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CacheRecordRmv: Question %p %##s (%s) deliverAddEvents set, DNSServer %#a:%d", 364347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, 364447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort)); 364547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = q->next; 364647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt continue; 364747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 364847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->CurrentAnswers == 0) 364947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("CacheRecordRmv ERROR!!: How can CurrentAnswers already be zero for %p %##s (%s) DNSServer %#a:%d", 365047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, 365147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort)); 365247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 365347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 365447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->CurrentAnswers--; 365547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--; 365647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--; 365747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 365847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results 365947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 366047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->CurrentAnswers == 0) 366147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 366247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents", 366347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qname.c, DNSTypeName(q->qtype)); 366447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0); 366547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 366647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv); 366747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 366847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 366947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 367047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = q->next; 367147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 367247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 367347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 367447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 367547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e) 367647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 367747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 367847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt unsigned int i; 367947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF; 368047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 368147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt e->next = m->rrcache_free; 368247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_free = e; 368347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_totalused--; 368447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 368547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 368647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp) 368747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 368847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheEntity *e = (CacheEntity *)(*cp); 368947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c); 369047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((*cp)->rrcache_tail != &(*cp)->members) 369147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)"); 369247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //if ((*cp)->name != (domainname*)((*cp)->namestorage)) 369347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage)); 369447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name); 369547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (*cp)->name = mDNSNULL; 369647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *cp = (*cp)->next; // Cut record from list 369747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ReleaseCacheEntity(m, e); 369847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 369947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 370047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r) 370147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 370247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r)); 370347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->smallrdatastorage) mDNSPlatformMemFree(r->resrec.rdata); 370447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r->resrec.rdata = mDNSNULL; 370547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ReleaseCacheEntity(m, (CacheEntity *)r); 370647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 370747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 370847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering 370947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all 371047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// callbacks for old records are delivered before callbacks for newer records. 371147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGroup *const cg) 371247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 371347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord **rp = &cg->members; 371447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 371547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; } 371647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->lock_rrcache = 1; 371747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 371847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*rp) 371947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 372047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *const rr = *rp; 372147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 event = RRExpireTime(rr); 372247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - event >= 0) // If expired, delete it 372347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 372447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *rp = rr->next; // Cut it from the list 372547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("CheckCacheExpiration: Deleting%7d %7d %p %s", 372647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr)); 372747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away 372847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 372947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q = rr->CRActiveQuestion; 373047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When a cache record is about to expire, we expect to do four queries at 80-82%, 85-87%, 90-92% and 373147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then 95-97% of the TTL. If the DNS server does not respond, then we will remove the cache entry 373247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // before we pick a new DNS server. As the question interval is set to MaxQuestionInterval, we may 373347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // not send out a query anytime soon. Hence, we need to reset the question interval. If this is 373447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // a normal deferred ADD case, then AnswerCurrentQuestionWithResourceRecord will reset it to 373547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // MaxQuestionInterval. If we have inactive questions referring to negative cache entries, 373647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // don't ressurect them as they will deliver duplicate "No such Record" ADD events 373747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && ActiveQuestion(q)) 373847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 373947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval = InitialQuestionInterval; 374047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTime = m->timenow - q->ThisQInterval; 374147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextQueryTime(m, q); 374247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 374347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecordRmv(m, rr); 374447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_active--; 374547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 374647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ReleaseCacheRecord(m, rr); 374747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 374847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else // else, not expired; see if we need to query 374947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 375047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If waiting to delay delivery, do nothing until then 375147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0) 375247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt event = rr->DelayDelivery; 375347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 375447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 375547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr); 375647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries) 375747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 375847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - rr->NextRequiredQuery < 0) // If not yet time for next query 375947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt event = NextCacheCheckEvent(rr); // then just record when we want the next query 376047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else // else trigger our question to go out now 376147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 376247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Set NextScheduledQuery to timenow so that SendQueries() will run. 376347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // SendQueries() will see that we have records close to expiration, and send FEQs for them. 376447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledQuery = m->timenow; 376547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTimeForRecord(), 376647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which will correctly update m->NextCacheCheck for us. 376747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt event = m->timenow + 0x3FFFFFFF; 376847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 376947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 377047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 377147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("CheckCacheExpiration:%6d %5d %s", 377247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr)); 377347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rrcache_nextcheck[slot] - event > 0) 377447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_nextcheck[slot] = event; 377547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp = &rr->next; 377647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 377747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 377847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp); 377947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cg->rrcache_tail = rp; 378047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->lock_rrcache = 0; 378147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 378247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 378347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void AnswerNewQuestion(mDNS *const m) 378447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 378547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool ShouldQueryImmediately = mDNStrue; 378647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *const q = m->NewQuestions; // Grab the question we're going to answer 378747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot = HashSlot(&q->qname); 378847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 378947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *lr; 379047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *ag; 379147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool AnsweredFromCache = mDNSfalse; 379247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 379347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 379447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 379547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cg) CheckCacheExpiration(m, slot, cg); 379647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NewQuestions != q) { LogInfo("AnswerNewQuestion: Question deleted while doing CheckCacheExpiration"); goto exit; } 379747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NewQuestions = q->next; 379847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Advance NewQuestions to the next *after* calling CheckCacheExpiration, because if we advance it first 379947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then CheckCacheExpiration may give this question add/remove callbacks, and it's not yet ready for that. 380047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 380147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Also, CheckCacheExpiration() calls CacheRecordDeferredAdd() and CacheRecordRmv(), which invoke 380247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // client callbacks, which may delete their own or any other question. Our mechanism for detecting 380347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // whether our current m->NewQuestions question got deleted by one of these callbacks is to store the 380447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // value of m->NewQuestions in 'q' before calling CheckCacheExpiration(), and then verify afterwards 380547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that they're still the same. If m->NewQuestions has changed (because mDNS_StopQuery_internal 380647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // advanced it), that means the question was deleted, so we no longer need to worry about answering 380747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // it (and indeed 'q' is now a dangling pointer, so dereferencing it at all would be bad, and the 380847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // values we computed for slot and cg are now stale and relate to a question that no longer exists). 380947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 381047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We can't use the usual m->CurrentQuestion mechanism for this because CacheRecordDeferredAdd() and 381147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // CacheRecordRmv() both use that themselves when walking the list of (non-new) questions generating callbacks. 381247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Fortunately mDNS_StopQuery_internal auto-advances both m->CurrentQuestion *AND* m->NewQuestions when 381347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // deleting a question, so luckily we have an easy alternative way of detecting if our question got deleted. 381447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 381547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!"); 381647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This should be safe, because calling the client's question callback may cause the 381747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // question list to be modified, but should not ever cause the rrcache list to be modified. 381847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the client's question callback deletes the question, then m->CurrentQuestion will 381947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // be advanced, and we'll exit out of the loop 382047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->lock_rrcache = 1; 382147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 382247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", 382347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 382447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted 382547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 382647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->NoAnswer == NoAnswer_Fail) 382747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 382847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 382947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, q->qDNSServer); 383047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression 383147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache); 383247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't touch the question if it has been stopped already 383347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion == q) q->NoAnswer = NoAnswer_Fail; // Restore NoAnswer state 383447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 383547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 383647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while generating NoAnswer_Fail response"); goto exit; } 383747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 383847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // See if we want to tell it about LocalOnly records 383947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord) 384047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 384147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt slot = AuthHashSlot(&q->qname); 384247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); 384347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ag) 384447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 384547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = ag->members; 384647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord && m->CurrentRecord != ag->NewLocalOnlyRecords) 384747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 384847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr = m->CurrentRecord; 384947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = rr->next; 385047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 385147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the question is mDNSInterface_LocalOnly, all records local to the machine should be used 385247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to answer the query. This is handled in AnswerNewLocalOnlyQuestion. 385347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 385447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We handle mDNSInterface_Any and scoped questions here. See LocalOnlyRecordAnswersQuestion for more 385547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // details on how we handle this case. For P2P we just handle "Interface_Any" questions. For LocalOnly 385647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we handle both mDNSInterface_Any and scoped questions. 385747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 385847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ARType == AuthRecordLocalOnly || (rr->ARType == AuthRecordP2P && q->InterfaceID == mDNSInterface_Any)) 385947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (LocalOnlyRecordAnswersQuestion(rr, q)) 386047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 386147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); 386247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 386347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 386447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 386547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 386647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = mDNSNULL; 386747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 386847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while while giving LocalOnly record answers"); goto exit; } 386947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 387047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->LOAddressAnswers) 387147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 387247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("AnswerNewQuestion: Question %p %##s (%s) answered using local auth records LOAddressAnswers %d", 387347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q, q->qname.c, DNSTypeName(q->qtype), q->LOAddressAnswers); 387447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt goto exit; 387547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 387647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 387747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Before we go check the cache and ship this query on the wire, we have to be sure that there are 387847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // no local records that could possibly answer this question. As we did not check the NewLocalRecords, we 387947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // need to just peek at them to see whether it will answer this question. If it would answer, pretend 388047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that we answered. AnswerAllLocalQuestionsWithLocalAuthRecord will answer shortly. This happens normally 388147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // when we add new /etc/hosts entries and restart the question. It is a new question and also a new record. 388247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ag) 388347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 388447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt lr = ag->NewLocalOnlyRecords; 388547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (lr) 388647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 388747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (LORecordAnswersAddressType(lr) && LocalOnlyRecordAnswersQuestion(lr, q)) 388847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 388947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("AnswerNewQuestion: Question %p %##s (%s) will be answered using new local auth records " 389047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt " LOAddressAnswers %d", q, q->qname.c, DNSTypeName(q->qtype), q->LOAddressAnswers); 389147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt goto exit; 389247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 389347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt lr = lr->next; 389447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 389547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 389647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 389747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 389847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we are not supposed to answer this question, generate a negative response. 389947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Temporarily suspend the SuppressQuery so that AnswerCurrentQuestionWithResourceRecord can answer the question 390047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (QuerySuppressed(q)) { q->SuppressQuery = mDNSfalse; GenerateNegativeResponse(m); q->SuppressQuery = mDNStrue; } 390147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 390247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 390347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr; 390447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 390547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameNameRecordAnswersQuestion(&rr->resrec, q)) 390647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 390747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // SecsSinceRcvd is whole number of elapsed seconds, rounded down 390847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond; 390947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rroriginalttl <= SecsSinceRcvd) 391047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 391147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d", 391247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rroriginalttl, SecsSinceRcvd, CRDisplayString(m, rr), m->timenow, rr->TimeRcvd); 391347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt continue; // Go to next one in loop 391447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 391547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 391647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this record set is marked unique, then that means we can reasonably assume we have the whole set 391747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // -- we don't need to rush out on the network and query immediately to see if there are more answers out there 391847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique)) 391947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ShouldQueryImmediately = mDNSfalse; 392047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->CurrentAnswers++; 392147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; 392247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; 392347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnsweredFromCache = mDNStrue; 392447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); 392547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 392647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 392747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype)) 392847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ShouldQueryImmediately = mDNSfalse; 392947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 393047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We don't use LogInfo for this "Question deleted" message because it happens so routinely that 393147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // it's not remotely remarkable, and therefore unlikely to be of much help tracking down bugs. 393247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving cache answers"); goto exit; } 393347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 393447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Neither a local record nor a cache entry could answer this question. If this question need to be retried 393547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // with search domains, generate a negative response which will now retry after appending search domains. 393647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the query was suppressed above, we already generated a negative response. When it gets unsuppressed, 393747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we will retry with search domains. 393847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!QuerySuppressed(q) && !AnsweredFromCache && q->RetryWithSearchDomains) 393947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 394047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("AnswerNewQuestion: Generating response for retrying with search domains %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 394147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt GenerateNegativeResponse(m); 394247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 394347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 394447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving negative answer"); goto exit; } 394547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 394647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: When a query gets suppressed or retried with search domains, we de-activate the question. 394747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Hence we don't execute the following block of code for those cases. 394847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ShouldQueryImmediately && ActiveQuestion(q)) 394947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 395047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 395147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval = InitialQuestionInterval; 395247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTime = m->timenow - q->ThisQInterval; 395347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSOpaque16IsZero(q->TargetQID)) // For mDNS, spread packets to avoid a burst of simultaneous queries 395447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 395547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms 395647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->RandomQueryDelay) 395747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1; 395847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTime += m->RandomQueryDelay; 395947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 396047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 396147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 396247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // IN ALL CASES make sure that m->NextScheduledQuery is set appropriately. 396347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In cases where m->NewQuestions->DelayAnswering is set, we may have delayed generating our 396447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // answers for this question until *after* its scheduled transmission time, in which case 396547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // m->NextScheduledQuery may now be set to 'never', and in that case -- even though we're *not* doing 396647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // ShouldQueryImmediately -- we still need to make sure we set m->NextScheduledQuery correctly. 396747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextQueryTime(m,q); 396847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 396947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit: 397047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 397147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->lock_rrcache = 0; 397247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 397347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 397447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any 397547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// appropriate answers, stopping if it reaches a NewLocalOnlyRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord 397647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) 397747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 397847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 397947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *ag; 398047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer 398147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NewLocalOnlyQuestions = q->next; // Advance NewLocalOnlyQuestions to the next (if any) 398247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 398347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 398447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 398547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 398647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", 398747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 398847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted 398947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 399047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord) 399147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 399247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 399347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. First walk the LocalOnly records answering the LocalOnly question 399447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. As LocalOnly questions should also be answered by any other Auth records local to the machine, 399547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // walk the ResourceRecords list delivering the answers 399647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt slot = AuthHashSlot(&q->qname); 399747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); 399847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ag) 399947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 400047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = ag->members; 400147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord && m->CurrentRecord != ag->NewLocalOnlyRecords) 400247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 400347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr = m->CurrentRecord; 400447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = rr->next; 400547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (LocalOnlyRecordAnswersQuestion(rr, q)) 400647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 400747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); 400847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 400947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 401047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 401147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 401247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 401347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion == q) 401447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 401547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = m->ResourceRecords; 401647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 401747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords) 401847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 401947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr = m->CurrentRecord; 402047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = rr->next; 402147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 402247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 402347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); 402447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 402547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 402647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 402747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 402847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 402947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 403047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = mDNSNULL; 403147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 403247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 403347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG) 403447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 403547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheEntity *e = mDNSNULL; 403647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 403747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); } 403847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->lock_rrcache = 1; 403947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 404047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we have no free records, ask the client layer to give us some more memory 404147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->rrcache_free && m->MainCallback) 404247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 404347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rrcache_totalused != m->rrcache_size) 404447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu", 404547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_totalused, m->rrcache_size); 404647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 404747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We don't want to be vulnerable to a malicious attacker flooding us with an infinite 404847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // number of bogus records so that we keep growing our cache until the machine runs out of memory. 404947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each), 405047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and we're actively using less than 1/32 of that cache, then we purge all the unused records 405147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and recycle them, instead of allocating more memory. 405247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rrcache_size > 5000 && m->rrcache_size / 32 > m->rrcache_active) 405347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu", 405447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_size, m->rrcache_active); 405547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 405647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 405747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 405847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->MainCallback(m, mStatus_GrowCache); 405947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 406047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 406147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 406247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 406347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we still have no free records, recycle all the records we can. 406447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass. 406547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->rrcache_free) 406647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 406747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 oldtotalused = m->rrcache_totalused; 406847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 406947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) 407047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 407147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup **cp = &m->rrcache_hash[slot]; 407247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*cp) 407347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 407447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord **rp = &(*cp)->members; 407547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*rp) 407647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 407747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Records that answer still-active questions are not candidates for recycling 407847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash 407947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList) 408047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp=&(*rp)->next; 408147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 408247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 408347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr = *rp; 408447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *rp = (*rp)->next; // Cut record from list 408547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ReleaseCacheRecord(m, rr); 408647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 408747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 408847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((*cp)->rrcache_tail != rp) 408947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp); 409047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (*cp)->rrcache_tail = rp; 409147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next; 409247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else ReleaseCacheGroup(m, cp); 409347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 409447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 409547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d", 409647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused); 409747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 409847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 409947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rrcache_free) // If there are records in the free list, take one 410047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 410147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt e = m->rrcache_free; 410247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_free = e->next; 410347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (++m->rrcache_totalused >= m->rrcache_report) 410447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 410547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("RR Cache now using %ld objects", m->rrcache_totalused); 410647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rrcache_report < 100) m->rrcache_report += 10; 410747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (m->rrcache_report < 1000) m->rrcache_report += 100; 410847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else m->rrcache_report += 1000; 410947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 411047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemZero(e, sizeof(*e)); 411147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 411247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 411347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->lock_rrcache = 0; 411447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 411547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(e); 411647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 411747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 411847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength) 411947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 412047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg); 412147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r) 412247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 412347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r->resrec.rdata = (RData*)&r->smallrdatastorage; // By default, assume we're usually going to be using local storage 412447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RDLength > InlineCacheRDSize) // If RDLength is too big, allocate extra storage 412547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 412647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength); 412747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength; 412847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; } 412947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 413047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 413147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(r); 413247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 413347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 413447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr) 413547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 413647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu16 namelen = DomainNameLength(rr->name); 413747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL); 413847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); } 413947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cg->next = m->rrcache_hash[slot]; 414047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cg->namehash = rr->namehash; 414147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cg->members = mDNSNULL; 414247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cg->rrcache_tail = &cg->members; 414347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cg->name = (domainname*)cg->namestorage; 414447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s", 414547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c); 414647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen); 414747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!cg->name) 414847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 414947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c); 415047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ReleaseCacheEntity(m, (CacheEntity*)cg); 415147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSNULL); 415247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 415347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(cg->name, rr->name); 415447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 415547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c); 415647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_hash[slot] = cg; 415747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c); 415847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 415947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(cg); 416047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 416147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 416247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr) 416347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 416447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->mDNS_busy != m->mDNS_reentrancy+1) 416547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_PurgeCacheResourceRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); 416647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Make sure we mark this record as thoroughly expired -- we don't ever want to give 416747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // a positive answer using an expired record (e.g. from an interface that has gone away). 416847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We don't want to clear CRActiveQuestion here, because that would leave the record subject to 416947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // summary deletion without giving the proper callback to any questions that are monitoring it. 417047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries. 417147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->TimeRcvd = m->timenow - mDNSPlatformOneSecond * 60; 417247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UnansweredQueries = MaxUnansweredQueries; 417347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rroriginalttl = 0; 417447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextCacheCheckTimeForRecord(m, rr); 417547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 417647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 417747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m) 417847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 417947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 time; 418047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformLock(m); 418147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->mDNS_busy) 418247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 418347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow."); 418447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy); 418547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 418647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 418747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow) time = m->timenow; 418847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else time = mDNS_TimeNow_NoLock(m); 418947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformUnlock(m); 419047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(time); 419147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 419247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 419347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// To avoid pointless CPU thrash, we use SetSPSProxyListChanged(X) to record the last interface that 419447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute(). 419547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set) 419647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define SetSPSProxyListChanged(X) do { \ 419747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \ 419847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSProxyListChanged = (X); } while(0) 419947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 420047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Called from mDNS_Execute() to expire stale proxy records 420147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void CheckProxyRecords(mDNS *const m, AuthRecord *list) 420247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 420347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = list; 420447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord) 420547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 420647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr = m->CurrentRecord; 420747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType != kDNSRecordTypeDeregistering && rr->WakeUp.HMAC.l[0]) 420847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 420947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If m->SPSSocket is NULL that means we're not acting as a sleep proxy any more, 421047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so we need to cease proxying for *all* records we may have, expired or not. 421147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SPSSocket && m->timenow - rr->TimeExpire < 0) // If proxy record not expired yet, update m->NextScheduledSPS 421247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 421347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextScheduledSPS - rr->TimeExpire > 0) 421447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledSPS = rr->TimeExpire; 421547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 421647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else // else proxy record expired, so remove it 421747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 421847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("CheckProxyRecords: Removing %d H-MAC %.6a I-MAC %.6a %d %s", 421947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, ARDisplayString(m, rr)); 422047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetSPSProxyListChanged(rr->resrec.InterfaceID); 422147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 422247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't touch rr after this -- memory may have been free'd 422347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 422447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 422547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because 422647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // new records could have been added to the end of the list as a result of that call. 422747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now 422847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = rr->next; 422947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 423047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 423147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 423247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void CheckRmvEventsForLocalRecords(mDNS *const m) 423347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 423447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord) 423547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 423647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr = m->CurrentRecord; 423747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->AnsweredLocalQ && rr->resrec.RecordType == kDNSRecordTypeDeregistering) 423847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 423947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("CheckRmvEventsForLocalRecords: Generating local RMV events for %s", ARDisplayString(m, rr)); 424047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.RecordType = kDNSRecordTypeShared; 424147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); 424247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord == rr) // If rr still exists in list, restore its state now 424347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 424447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.RecordType = kDNSRecordTypeDeregistering; 424547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnsweredLocalQ = mDNSfalse; 424647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // SendResponses normally calls CompleteDeregistration after sending goodbyes. 424747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For LocalOnly records, we don't do that and hence we need to do that here. 424847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRLocalOnly(rr)) CompleteDeregistration(m, rr); 424947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 425047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 425147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord == rr) // If m->CurrentRecord was not auto-advanced, do it ourselves now 425247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = rr->next; 425347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 425447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 425547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 425647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void TimeoutQuestions(mDNS *const m) 425747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 425847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledStopTime = m->timenow + 0x3FFFFFFF; 425947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 426047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("TimeoutQuestions ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, 426147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSTypeName(m->CurrentQuestion->qtype)); 426247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = m->Questions; 426347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentQuestion) 426447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 426547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *const q = m->CurrentQuestion; 426647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->StopTime) 426747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 426847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - q->StopTime >= 0) 426947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 427047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("TimeoutQuestions: question %##s timed out, time %d", q->qname.c, m->timenow - q->StopTime); 427147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt GenerateNegativeResponse(m); 427247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion == q) q->StopTime = 0; 427347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 427447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 427547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 427647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextScheduledStopTime - q->StopTime > 0) 427747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledStopTime = q->StopTime; 427847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 427947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 428047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If m->CurrentQuestion wasn't modified out from under us, advance it now 428147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We can't do this at the start of the loop because GenerateNegativeResponse 428247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // depends on having m->CurrentQuestion point to the right question 428347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion == q) 428447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = q->next; 428547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 428647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 428747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 428847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 428947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSs32 mDNS_Execute(mDNS *const m) 429047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 429147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); // Must grab lock before trying to read m->timenow 429247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 429347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - m->NextScheduledEvent >= 0) 429447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 429547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 429647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *head, *tail; 429747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 429847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *ag; 429947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 430047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("mDNS_Execute"); 430147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 430247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 430347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", 430447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 430547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 430647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord) 430747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Execute: ERROR m->CurrentRecord already set: %s", ARDisplayString(m, m->CurrentRecord)); 430847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 430947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. If we're past the probe suppression time, we can clear it 431047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0; 431147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 431247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter 431347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NumFailedProbes && m->timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10) m->NumFailedProbes = 0; 431447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 431547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3. Purge our cache of stale old records 431647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0) 431747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 431847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 numchecked = 0; 431947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextCacheCheck = m->timenow + 0x3FFFFFFF; 432047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) 432147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 432247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - m->rrcache_nextcheck[slot] >= 0) 432347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 432447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup **cp = &m->rrcache_hash[slot]; 432547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_nextcheck[slot] = m->timenow + 0x3FFFFFFF; 432647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*cp) 432747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 432847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("m->NextCacheCheck %4d Slot %3d %##s", numchecked, slot, *cp ? (*cp)->name : (domainname*)"\x04NULL"); 432947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt numchecked++; 433047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CheckCacheExpiration(m, slot, *cp); 433147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((*cp)->members) cp=&(*cp)->next; 433247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else ReleaseCacheGroup(m, cp); 433347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 433447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 433547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Even if we didn't need to actually check this slot yet, still need to 433647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // factor its nextcheck time into our overall NextCacheCheck value 433747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextCacheCheck - m->rrcache_nextcheck[slot] > 0) 433847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextCacheCheck = m->rrcache_nextcheck[slot]; 433947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 434047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("m->NextCacheCheck %4d checked, next in %d", numchecked, m->NextCacheCheck - m->timenow); 434147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 434247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 434347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - m->NextScheduledSPS >= 0) 434447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 434547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledSPS = m->timenow + 0x3FFFFFFF; 434647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CheckProxyRecords(m, m->DuplicateRecords); // Clear m->DuplicateRecords first, then m->ResourceRecords 434747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CheckProxyRecords(m, m->ResourceRecords); 434847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 434947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 435047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetSPSProxyListChanged(mDNSNULL); // Perform any deferred BPF reconfiguration now 435147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 435247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Clear AnnounceOwner if necessary. (Do this *before* SendQueries() and SendResponses().) 435347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->AnnounceOwner && m->timenow - m->AnnounceOwner >= 0) m->AnnounceOwner = 0; 435447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 435547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->DelaySleep && m->timenow - m->DelaySleep >= 0) 435647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 435747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->DelaySleep = 0; 435847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SleepState == SleepState_Transferring) 435947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 436047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("Re-sleep delay passed; now checking for Sleep Proxy Servers"); 436147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt BeginSleepProcessing(m); 436247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 436347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 436447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 436547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 4. See if we can answer any of our new local questions from the cache 436647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; m->NewQuestions && i<1000; i++) 436747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 436847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break; 436947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerNewQuestion(m); 437047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 437147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit"); 437247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 437347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Make sure we deliver *all* local RMV events, and clear the corresponding rr->AnsweredLocalQ flags, *before* 437447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we begin generating *any* new ADD events in the m->NewLocalOnlyQuestions and m->NewLocalRecords loops below. 437547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<1000 && m->LocalRemoveEvents; i++) 437647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 437747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LocalRemoveEvents = mDNSfalse; 437847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = m->ResourceRecords; 437947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CheckRmvEventsForLocalRecords(m); 438047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Walk the LocalOnly records and deliver the RMV events 438147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) 438247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next) 438347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 438447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = ag->members; 438547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord) CheckRmvEventsForLocalRecords(m); 438647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 438747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 438847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 438947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (i >= 1000) LogMsg("mDNS_Execute: m->LocalRemoveEvents exceeded loop limit"); 439047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 439147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m); 439247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit"); 439347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 439447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt head = tail = mDNSNULL; 439547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<1000 && m->NewLocalRecords && m->NewLocalRecords != head; i++) 439647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 439747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr = m->NewLocalRecords; 439847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NewLocalRecords = m->NewLocalRecords->next; 439947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (LocalRecordReady(rr)) 440047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 440147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr)); 440247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue); 440347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 440447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (!rr->next) 440547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 440647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we have just one record that is not ready, we don't have to unlink and 440747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // reinsert. As the NewLocalRecords will be NULL for this case, the loop will 440847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // terminate and set the NewLocalRecords to rr. 440947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_Execute: Just one LocalAuthRecord %s, breaking out of the loop early", ARDisplayString(m, rr)); 441047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (head != mDNSNULL || m->NewLocalRecords != mDNSNULL) 441147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Execute: ERROR!!: head %p, NewLocalRecords %p", head, m->NewLocalRecords); 441247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 441347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt head = rr; 441447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 441547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 441647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 441747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records 441847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_Execute: Skipping LocalAuthRecord %s", ARDisplayString(m, rr)); 441947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if this is the first record we are skipping, move to the end of the list. 442047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if we have already skipped records before, append it at the end. 442147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*p && *p != rr) p=&(*p)->next; 442247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*p) *p = rr->next; // Cut this record from the list 442347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else { LogMsg("mDNS_Execute: ERROR!! Cannot find record %s in ResourceRecords list", ARDisplayString(m, rr)); break; } 442447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!head) 442547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 442647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*p) p=&(*p)->next; 442747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *p = rr; 442847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt head = tail = rr; 442947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 443047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 443147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 443247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt tail->next = rr; 443347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt tail = rr; 443447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 443547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->next = mDNSNULL; 443647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 443747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 443847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NewLocalRecords = head; 443947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_Execute: Setting NewLocalRecords to %s", (head ? ARDisplayString(m, head) : "NULL")); 444047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 444147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (i >= 1000) LogMsg("mDNS_Execute: m->NewLocalRecords exceeded loop limit"); 444247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 444347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Check to see if we have any new LocalOnly/P2P records to examine for delivering 444447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to our local questions 444547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NewLocalOnlyRecords) 444647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 444747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NewLocalOnlyRecords = mDNSfalse; 444847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) 444947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next) 445047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 445147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<100 && ag->NewLocalOnlyRecords; i++) 445247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 445347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr = ag->NewLocalOnlyRecords; 445447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag->NewLocalOnlyRecords = ag->NewLocalOnlyRecords->next; 445547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // LocalOnly records should always be ready as they never probe 445647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (LocalRecordReady(rr)) 445747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 445847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr)); 445947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue); 446047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 446147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else LogMsg("mDNS_Execute: LocalOnlyRecord %s not ready", ARDisplayString(m, rr)); 446247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 446347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We limit about 100 per AuthGroup that can be serviced at a time 446447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (i >= 100) LogMsg("mDNS_Execute: ag->NewLocalOnlyRecords exceeded loop limit"); 446547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 446647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 446747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 446847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 5. Some questions may have picked a new DNS server and the cache may answer these questions now. 446947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerQuestionsForDNSServerChanges(m); 447047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 447147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 6. See what packets we need to send 447247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->mDNSPlatformStatus != mStatus_NoError || (m->SleepState == SleepState_Sleeping)) 447347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DiscardDeregistrations(m); 447447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->mDNSPlatformStatus == mStatus_NoError && (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0)) 447547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 447647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the platform code is ready, and we're not suppressing packet generation right now 447747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then send our responses, probes, and questions. 447847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We check the cache first, because there might be records close to expiring that trigger questions to refresh them. 447947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We send queries next, because there might be final-stage probes that complete their probing here, causing 448047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // them to advance to announcing state, and we want those to be included in any announcements we send out. 448147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Finally, we send responses, including the previously mentioned records that just completed probing. 448247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressSending = 0; 448347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 448447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 7. Send Query packets. This may cause some probing records to advance to announcing state 448547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m); 448647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - m->NextScheduledQuery >= 0) 448747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 448847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 448947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second", 449047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery); 449147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond; 449247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q && q != m->NewQuestions; q=q->next) 449347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ActiveQuestion(q) && m->timenow - NextQSendTime(q) >= 0) 449447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 449547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 449647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - m->NextScheduledProbe >= 0) 449747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 449847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second", 449947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->timenow, m->NextScheduledProbe, m->timenow - m->NextScheduledProbe); 450047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond; 450147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 450247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 450347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 8. Send Response packets, including probing records just advanced to announcing state 450447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m); 450547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - m->NextScheduledResponse >= 0) 450647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 450747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second"); 450847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledResponse = m->timenow + mDNSPlatformOneSecond; 450947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 451047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 451147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 451247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Clear RandomDelay values, ready to pick a new different value next time 451347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RandomQueryDelay = 0; 451447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RandomReconfirmDelay = 0; 451547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 451647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextScheduledStopTime && m->timenow - m->NextScheduledStopTime >= 0) TimeoutQuestions(m); 451747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 451847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0) UpdateAllSRVRecords(m); 451947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - m->NextScheduledNATOp >= 0) CheckNATMappings(m); 452047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - m->NextuDNSEvent >= 0) uDNS_Tasks(m); 452147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 452247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 452347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 452447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note about multi-threaded systems: 452547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(), 452647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // performing mDNS API operations that change our next scheduled event time. 452747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 452847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // On multi-threaded systems (like the current Windows implementation) that have a single main thread 452947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility 453047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will 453147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one 453247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful 453347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it 453447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // does, the state of the signal will be noticed, causing the blocking primitive to return immediately 453547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // without blocking. This avoids the race condition between the signal from the other thread arriving 453647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // just *before* or just *after* the main thread enters the blocking primitive. 453747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 453847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven, 453947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to 454047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer 454147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale 454247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // by the time it gets to the timer callback function). 454347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 454447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value 454547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(m->NextScheduledEvent); 454647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 454747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 454847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SuspendLLQs(mDNS *m) 454947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 455047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 455147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q = q->next) 455247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->state == LLQ_Established) 455347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { q->ReqLease = 0; sendLLQRefresh(m, q); } 455447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 455547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 455647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool QuestionHasLocalAnswers(mDNS *const m, DNSQuestion *q) 455747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 455847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 455947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 456047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *ag; 456147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 456247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt slot = AuthHashSlot(&q->qname); 456347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); 456447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ag) 456547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 456647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = ag->members; rr; rr=rr->next) 456747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Filter the /etc/hosts records - LocalOnly, Unique, A/AAAA/CNAME 456847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (LORecordAnswersAddressType(rr) && LocalOnlyRecordAnswersQuestion(rr, q)) 456947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 457047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("QuestionHasLocalAnswers: Question %p %##s (%s) has local answer %s", q, q->qname.c, DNSTypeName(q->qtype), ARDisplayString(m, rr)); 457147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNStrue; 457247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 457347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 457447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNSfalse; 457547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 457647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 457747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ActivateUnicastQuery() is called from three places: 457847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 1. When a new question is created 457947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 2. On wake from sleep 458047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 3. When the DNS configuration changes 458147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In case 1 we don't want to mess with our established ThisQInterval and LastQTime (ScheduleImmediately is false) 458247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true) 458347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, mDNSBool ScheduleImmediately) 458447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 458547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For now this AutoTunnel stuff is specific to Mac OS X. 458647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer 458747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder 458847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally. 458947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the 459047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel. 459147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then 459247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // returns results for both at the same time. If we are looking for the _autotunnel6 record, then skip this logic 459347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // as this would trigger looking up _autotunnel6._autotunnel6 and end up failing the original query. 459447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 459547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRTypeIsAddressType(question->qtype) && PrivateQuery(question) && 459647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !SameDomainLabel(question->qname.c, (const mDNSu8 *)"\x0c_autotunnel6")&& question->QuestionCallback != AutoTunnelCallback) 459747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 459847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->NoAnswer = NoAnswer_Suspended; 459947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AddNewClientTunnel(m, question); 460047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 460147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 460247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif // APPLE_OSX_mDNSResponder 460347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 460447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!question->DuplicateOf) 460547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 460647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("ActivateUnicastQuery: %##s %s%s%s", 460747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qname.c, DNSTypeName(question->qtype), PrivateQuery(question) ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : ""); 460847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->CNAMEReferrals = 0; 460947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; } 461047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->LongLived) 461147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 461247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->state = LLQ_InitialRequest; 461347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->id = zeroOpaque64; 461447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->servPort = zeroIPPort; 461547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; } 461647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 461747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the question has local answers, then we don't want answers from outside 461847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ScheduleImmediately && !QuestionHasLocalAnswers(m, question)) 461947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 462047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ThisQInterval = InitialQuestionInterval; 462147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->LastQTime = m->timenow - question->ThisQInterval; 462247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextQueryTime(m, question); 462347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 462447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 462547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 462647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 462747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Caller should hold the lock 462847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNSCoreRestartAddressQueries(mDNS *const m, mDNSBool SearchDomainsChanged, FlushCache flushCacheRecords, 462947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CallbackBeforeStartQuery BeforeStartCallback, void *context) 463047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 463147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 463247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *restart = mDNSNULL; 463347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 463447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->mDNS_busy) LogMsg("mDNSCoreRestartAddressQueries: ERROR!! Lock not held"); 463547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 463647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. Flush the cache records 463747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (flushCacheRecords) flushCacheRecords(m); 463847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 463947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. Even though we may have purged the cache records above, before it can generate RMV event 464047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we are going to stop the question. Hence we need to deliver the RMV event before we 464147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // stop the question. 464247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 464347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // CurrentQuestion is used by RmvEventsForQuestion below. While delivering RMV events, the 464447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // application callback can potentially stop the current question (detected by CurrentQuestion) or 464547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *any* other question which could be the next one that we may process here. RestartQuestion 464647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // points to the "next" question which will be automatically advanced in mDNS_StopQuery_internal 464747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if the "next" question is stopped while the CurrentQuestion is stopped 464847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 464947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->RestartQuestion) 465047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSCoreRestartAddressQueries: ERROR!! m->RestartQuestion already set: %##s (%s)", 465147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RestartQuestion->qname.c, DNSTypeName(m->RestartQuestion->qtype)); 465247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 465347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RestartQuestion = m->Questions; 465447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->RestartQuestion) 465547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 465647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q = m->RestartQuestion; 465747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RestartQuestion = q->next; 465847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // GetZoneData questions are referenced by other questions (original query that started the GetZoneData 465947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // question) through their "nta" pointer. Normally when the original query stops, it stops the 466047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // GetZoneData question and also frees the memory (See CancelGetZoneData). If we stop the GetZoneData 466147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // question followed by the original query that refers to this GetZoneData question, we will end up 466247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // freeing the GetZoneData question and then start the "freed" question at the end. 466347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 466447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (IsGetZoneDataQuestion(q)) 466547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 466647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *refq = q->next; 466747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreRestartAddressQueries: Skipping GetZoneDataQuestion %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); 466847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // debug stuff, we just try to find the referencing question and don't do much with it 466947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (refq) 467047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 467147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q == &refq->nta->question) 467247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 467347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreRestartAddressQueries: Question %p %##s (%s) referring to GetZoneDataQuestion %p, not stopping", refq, refq->qname.c, DNSTypeName(refq->qtype), q); 467447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 467547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt refq = refq->next; 467647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 467747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt continue; 467847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 467947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 468047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This function is called when /etc/hosts changes and that could affect A, AAAA and CNAME queries 468147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA && q->qtype != kDNSType_CNAME) continue; 468247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 468347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the search domains did not change, then we restart all the queries. Otherwise, only 468447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // for queries for which we "might" have appended search domains ("might" because we may 468547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // find results before we apply search domains even though AppendSearchDomains is set to 1) 468647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!SearchDomainsChanged || q->AppendSearchDomains) 468747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 468847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // NOTE: CacheRecordRmvEventsForQuestion will not generate RMV events for queries that have non-zero 468947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // LOAddressAnswers. Hence it is important that we call CacheRecordRmvEventsForQuestion before 469047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // LocalRecordRmvEventsForQuestion (which decrements LOAddressAnswers). Let us say that 469147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // /etc/hosts has an A Record for web.apple.com. Any queries for web.apple.com will be answered locally. 469247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // But this can't prevent a CNAME/AAAA query to not to be sent on the wire. When it is sent on the wire, 469347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // it could create cache entries. When we are restarting queries, we can't deliver the cache RMV events 469447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // for the original query using these cache entries as ADDs were never delivered using these cache 469547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // entries and hence this order is needed. 469647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 469747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the query is suppressed, the RMV events won't be delivered 469847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!CacheRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Cache Record RMV events"); continue; } 469947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 470047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // SuppressQuery status does not affect questions that are answered using local records 470147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!LocalRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Local Record RMV events"); continue; } 470247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 470347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreRestartAddressQueries: Stop question %p %##s (%s), AppendSearchDomains %d, qnameOrig %p", q, 470447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qname.c, DNSTypeName(q->qtype), q->AppendSearchDomains, q->qnameOrig); 470547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopQuery_internal(m, q); 470647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Reset state so that it looks like it was in the beginning i.e it should look at /etc/hosts, cache 470747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and then search domains should be appended. At the beginning, qnameOrig was NULL. 470847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->qnameOrig) 470947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 471047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreRestartAddressQueries: qnameOrig %##s", q->qnameOrig); 471147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&q->qname, q->qnameOrig); 471247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemFree(q->qnameOrig); 471347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qnameOrig = mDNSNULL; 471447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->RetryWithSearchDomains = ApplySearchDomainsFirst(q) ? 1 : 0; 471547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 471647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->SearchListIndex = 0; 471747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->next = restart; 471847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt restart = q; 471947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 472047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 472147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 472247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3. Callback before we start the query 472347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (BeforeStartCallback) BeforeStartCallback(m, context); 472447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 472547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 4. Restart all the stopped queries 472647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (restart) 472747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 472847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q = restart; 472947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt restart = restart->next; 473047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->next = mDNSNULL; 473147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreRestartAddressQueries: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); 473247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StartQuery_internal(m, q); 473347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 473447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 473547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 473647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNSCoreRestartQueries(mDNS *const m) 473747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 473847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 473947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 474047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 474147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Retrigger all our uDNS questions 474247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 474347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", 474447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 474547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = m->Questions; 474647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentQuestion) 474747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 474847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q = m->CurrentQuestion; 474947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = m->CurrentQuestion->next; 475047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) ActivateUnicastQuery(m, q, mDNStrue); 475147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 475247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 475347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 475447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Retrigger all our mDNS questions 475547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) // Scan our list of questions 475647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) 475747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 475847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question 475947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it 476047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTime = m->timenow - q->ThisQInterval; 476147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->RecentAnswerPkts = 0; 476247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ExpireDupSuppressInfo(q->DupSuppress, m->timenow); 476347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledQuery = m->timenow; 476447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 476547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 476647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 476747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// *************************************************************************** 476847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK 476947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - 477047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Power Management (Sleep/Wake) 477147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 477247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 477347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_UpdateAllowSleep(mDNS *const m) 477447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 477547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef IDLESLEEPCONTROL_DISABLED 477647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool allowSleep = mDNStrue; 477747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char reason[128]; 477847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 477947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt reason[0] = 0; 478047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 478147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SystemSleepOnlyIfWakeOnLAN) 478247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 478347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't sleep if we are a proxy for any services 478447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->ProxyRecords) 478547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 478647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt allowSleep = mDNSfalse; 478747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_snprintf(reason, sizeof(reason), "sleep proxy for %d records", m->ProxyRecords); 478847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("Sleep disabled because we are proxying %d records", m->ProxyRecords); 478947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 479047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 479147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (allowSleep && mDNSCoreHaveAdvertisedMulticastServices(m)) 479247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 479347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Scan the list of active interfaces 479447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf; 479547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 479647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 479747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->McastTxRx && !intf->Loopback) 479847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 479947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Disallow sleep if this interface doesn't support NetWake 480047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!intf->NetWake) 480147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 480247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt allowSleep = mDNSfalse; 480347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_snprintf(reason, sizeof(reason), "%s does not support NetWake", intf->ifname); 480447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("Sleep disabled because %s does not support NetWake", intf->ifname); 480547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 480647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 480747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 480847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Disallow sleep if there is no sleep proxy server 480947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (FindSPSInCache1(m, &intf->NetWakeBrowse, mDNSNULL, mDNSNULL) == mDNSNULL) 481047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 481147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt allowSleep = mDNSfalse; 481247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_snprintf(reason, sizeof(reason), "%s does not support NetWake", intf->ifname); 481347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("Sleep disabled because %s has no sleep proxy", intf->ifname); 481447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 481547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 481647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 481747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 481847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 481947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 482047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 482147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Call the platform code to enable/disable sleep 482247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformSetAllowSleep(m, allowSleep, reason); 482347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif /* !defined(IDLESLEEPCONTROL_DISABLED) */ 482447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 482547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 482647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SendSPSRegistrationForOwner(mDNS *const m, NetworkInterfaceInfo *const intf, const mDNSOpaque16 id, const OwnerOptData *const owner) 482747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 482847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC); 482947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const int sps = intf->NextSPSAttempt / 3; 483047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 483147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 483247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!intf->SPSAddr[sps].type) 483347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 483447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond; 483547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0) 483647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledSPRetry = intf->NextSPSAttemptTime; 483747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("SendSPSRegistration: %s SPS %d (%d) %##s not yet resolved", intf->ifname, intf->NextSPSAttempt, sps, intf->NetWakeResolve[sps].qname.c); 483847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt goto exit; 483947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 484047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 484147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Mark our mDNS records (not unicast records) for transfer to SPS 484247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSOpaque16IsZero(id)) 484347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 484447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType > kDNSRecordTypeDeregistering) 484547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID == intf->InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name)))) 484647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSPlatformMemSame(owner, &rr->WakeUp, sizeof(*owner))) 484747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendRNow = mDNSInterfaceMark; // mark it now 484847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 484947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (1) 485047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 485147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *p = m->omsg.data; 485247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // To comply with RFC 2782, PutResourceRecord suppresses name compression for SRV records in unicast updates. 485347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For now we follow that same logic for SPS registrations too. 485447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we decide to compress SRV records in SPS registrations in the future, we can achieve that by creating our 485547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // initial DNSMessage with h.flags set to zero, and then update it to UpdateReqFlags right before sending the packet. 485647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeDNSMessage(&m->omsg.h, mDNSOpaque16IsZero(id) ? mDNS_NewMessageID(m) : id, UpdateReqFlags); 485747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 485847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 485947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->SendRNow || (!mDNSOpaque16IsZero(id) && !AuthRecord_uDNS(rr) && mDNSSameOpaque16(rr->updateid, id) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0)) 486047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSPlatformMemSame(owner, &rr->WakeUp, sizeof(*owner))) 486147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 486247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *newptr; 486347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.mDNS_numUpdates ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData) - optspace; 486447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 486547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it 486647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newptr = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit); 486747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state 486847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!newptr) 486947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("SendSPSRegistration put %s FAILED %d/%d %s", intf->ifname, p - m->omsg.data, limit - m->omsg.data, ARDisplayString(m, rr)); 487047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 487147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 487247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, rr)); 487347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendRNow = mDNSNULL; 487447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ThisAPInterval = mDNSPlatformOneSecond; 487547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastAPTime = m->timenow; 487647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->updateid = m->omsg.h.id; 487747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 487847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval); 487947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt p = newptr; 488047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 488147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 488247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 488347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->omsg.h.mDNS_numUpdates) break; 488447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 488547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 488647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord opt; 488747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); 488847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rrclass = NormalMaxDNSMessageData; 488947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdlength = sizeof(rdataOPT) * 2; // Two options in this OPT record 489047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdestimate = sizeof(rdataOPT) * 2; 489147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; 489247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdata->u.opt[0].optlen = DNSOpt_LeaseData_Space - 4; 489347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdata->u.opt[0].u.updatelease = DEFAULT_UPDATE_LEASE; 489447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!owner->HMAC.l[0]) // If no owner data, 489547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[1]); // use our own interface information 489647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else // otherwise, use the owner data we were given 489747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 489847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdata->u.opt[1].u.owner = *owner; 489947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdata->u.opt[1].opt = kDNSOpt_Owner; 490047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdata->u.opt[1].optlen = DNSOpt_Owner_Space(&owner->HMAC, &owner->IMAC) - 4; 490147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 490247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, &opt)); 490347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData); 490447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!p) 490547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("SendSPSRegistration: Failed to put OPT record (%d updates) %s", m->omsg.h.mDNS_numUpdates, ARDisplayString(m, &opt)); 490647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 490747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 490847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus err; 490947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 491047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps, 491147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps])); 491247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss 491347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL); 491447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err); 491547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv6 && intf->NetWakeResolve[sps].ThisQInterval == -1) 491647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 491747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("SendSPSRegistration %d %##s failed to send to IPv6 address; will try IPv4 instead", sps, intf->NetWakeResolve[sps].qname.c); 491847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->NetWakeResolve[sps].qtype = kDNSType_A; 491947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StartQuery_internal(m, &intf->NetWakeResolve[sps]); 492047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 492147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 492247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 492347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 492447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 492547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 492647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond * 10; // If successful, update NextSPSAttemptTime 492747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 492847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit: 492947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSOpaque16IsZero(id) && intf->NextSPSAttempt < 8) intf->NextSPSAttempt++; 493047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 493147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 493247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool RecordIsFirstOccurrenceOfOwner(mDNS *const m, const AuthRecord *const rr) 493347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 493447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *ar; 493547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (ar = m->ResourceRecords; ar && ar != rr; ar=ar->next) 493647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSPlatformMemSame(&rr->WakeUp, &ar->WakeUp, sizeof(rr->WakeUp))) return mDNSfalse; 493747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNStrue; 493847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 493947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 494047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *const intf, const mDNSOpaque16 id) 494147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 494247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *ar; 494347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt OwnerOptData owner = zeroOwner; 494447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 494547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendSPSRegistrationForOwner(m, intf, id, &owner); 494647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 494747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (ar = m->ResourceRecords; ar; ar=ar->next) 494847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 494947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSPlatformMemSame(&owner, &ar->WakeUp, sizeof(owner)) && RecordIsFirstOccurrenceOfOwner(m, ar)) 495047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 495147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt owner = ar->WakeUp; 495247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendSPSRegistrationForOwner(m, intf, id, &owner); 495347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 495447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 495547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 495647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 495747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// RetrySPSRegistrations is called from SendResponses, with the lock held 495847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void RetrySPSRegistrations(mDNS *const m) 495947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 496047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 496147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf; 496247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 496347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // First make sure none of our interfaces' NextSPSAttemptTimes are inadvertently set to m->timenow + mDNSPlatformOneSecond * 10 496447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 496547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10) 496647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->NextSPSAttemptTime++; 496747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 496847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Retry any record registrations that are due 496947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 497047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AuthRecord_uDNS(rr) && !mDNSOpaque16IsZero(rr->updateid) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 497147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 497247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == intf->InterfaceID) 497347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 497447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("RetrySPSRegistrations: %s", ARDisplayString(m, rr)); 497547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendSPSRegistration(m, intf, rr->updateid); 497647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 497747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 497847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For interfaces where we did an SPS registration attempt, increment intf->NextSPSAttempt 497947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 498047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10 && intf->NextSPSAttempt < 8) 498147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->NextSPSAttempt++; 498247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 498347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 498447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 498547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 498647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf = (NetworkInterfaceInfo *)question->QuestionContext; 498747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int sps = (int)(question - intf->NetWakeResolve); 498847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (void)m; // Unused 498947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps, AddRecord, RRDisplayString(m, answer)); 499047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 499147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AddRecord) return; // Don't care about REMOVE events 499247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs 499347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 499447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if (answer->rrtype == kDNSType_AAAA && sps == 0) return; // To test failing to resolve sleep proxy's address 499547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 499647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (answer->rrtype == kDNSType_SRV) 499747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 499847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. Got the SRV record; now look up the target host's IPv6 link-local address 499947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopQuery(m, question); 500047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->SPSPort[sps] = answer->rdata->u.srv.port; 500147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&question->qname, &answer->rdata->u.srv.target); 500247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qtype = kDNSType_AAAA; 500347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StartQuery(m, question); 500447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 500547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == sizeof(mDNSv6Addr) && mDNSv6AddressIsLinkLocal(&answer->rdata->u.ipv6)) 500647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 500747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. Got the target host's IPv6 link-local address; record address and initiate an SPS registration if appropriate 500847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopQuery(m, question); 500947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ThisQInterval = -1; 501047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->SPSAddr[sps].type = mDNSAddrType_IPv6; 501147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->SPSAddr[sps].ip.v6 = answer->rdata->u.ipv6; 501247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 501347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now 501447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 501547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 501647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == 0) 501747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 501847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3. Got negative response -- target host apparently has IPv6 disabled -- so try looking up the target host's IPv4 address(es) instead 501947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopQuery(m, question); 502047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps, question->qname.c); 502147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qtype = kDNSType_A; 502247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StartQuery(m, question); 502347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 502447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (answer->rrtype == kDNSType_A && answer->rdlength == sizeof(mDNSv4Addr)) 502547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 502647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 4. Got an IPv4 address for the target host; record address and initiate an SPS registration if appropriate 502747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopQuery(m, question); 502847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ThisQInterval = -1; 502947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->SPSAddr[sps].type = mDNSAddrType_IPv4; 503047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->SPSAddr[sps].ip.v4 = answer->rdata->u.ipv4; 503147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 503247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now 503347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 503447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 503547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 503647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 503747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m) 503847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 503947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 504047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 504147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rrtype == kDNSType_SRV && !AuthRecord_uDNS(rr) && !mDNSSameIPPort(rr->resrec.rdata->u.srv.port, DiscardPort)) 504247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNStrue; 504347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNSfalse; 504447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 504547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 504647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SendSleepGoodbyes(mDNS *const m) 504747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 504847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 504947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SleepState = SleepState_Sleeping; 505047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 505147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 505247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SleepRecordRegistrations(m); // If we have no SPS, need to deregister our uDNS records 505347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif /* UNICAST_DISABLED */ 505447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 505547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Mark all the records we need to deregister and send them 505647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 505747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye) 505847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAnswer = mDNSInterfaceMark; 505947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendResponses(m); 506047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 506147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 506247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep 506347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void BeginSleepProcessing(mDNS *const m) 506447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 506547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool SendGoodbyes = mDNStrue; 506647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const CacheRecord *sps[3] = { mDNSNULL }; 506747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 506847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledSPRetry = m->timenow; 506947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 507047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->SystemWakeOnLANEnabled) LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false"); 507147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (!mDNSCoreHaveAdvertisedMulticastServices(m)) LogSPS("BeginSleepProcessing: No advertised services"); 507247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else // If we have at least one advertised service 507347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 507447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf; 507547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 507647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 507747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!intf->NetWake) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf->ifname); 507847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder 507947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (ActivateLocalProxy(m, intf->ifname) == mStatus_NoError) 508047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 508147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendGoodbyes = mDNSfalse; 508247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("BeginSleepProcessing: %-6s using local proxy", intf->ifname); 508347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This will leave m->SleepState set to SleepState_Transferring, 508447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which is okay because with no outstanding resolves, or updates in flight, 508547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // mDNSCoreReadyForSleep() will conclude correctly that all the updates have already completed 508647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 508747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif // APPLE_OSX_mDNSResponder 508847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 508947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 509047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt FindSPSInCache(m, &intf->NetWakeBrowse, sps); 509147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found (Next Browse Q in %d, interval %d)", 509247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->ifname, &intf->ip, NextQSendTime(&intf->NetWakeBrowse) - m->timenow, intf->NetWakeBrowse.ThisQInterval); 509347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 509447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 509547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 509647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendGoodbyes = mDNSfalse; 509747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->NextSPSAttempt = 0; 509847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond; 509947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above 510047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<3; i++) 510147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 510247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ForceAlerts 510347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->SPSAddr[i].type) 510447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { LogMsg("BeginSleepProcessing: %s %d intf->SPSAddr[i].type %d", intf->ifname, i, intf->SPSAddr[i].type); *(long*)0 = 0; } 510547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->NetWakeResolve[i].ThisQInterval >= 0) 510647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { LogMsg("BeginSleepProcessing: %s %d intf->NetWakeResolve[i].ThisQInterval %d", intf->ifname, i, intf->NetWakeResolve[i].ThisQInterval); *(long*)0 = 0; } 510747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 510847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->SPSAddr[i].type = mDNSAddrType_None; 510947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery(m, &intf->NetWakeResolve[i]); 511047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->NetWakeResolve[i].ThisQInterval = -1; 511147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sps[i]) 511247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 511347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("BeginSleepProcessing: %-6s Found Sleep Proxy Server %d TTL %d %s", intf->ifname, i, sps[i]->resrec.rroriginalttl, CRDisplayString(m, sps[i])); 511447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupQuestion(&intf->NetWakeResolve[i], intf->InterfaceID, &sps[i]->resrec.rdata->u.name, kDNSType_SRV, NetWakeResolve, intf); 511547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->NetWakeResolve[i].ReturnIntermed = mDNStrue; 511647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StartQuery_internal(m, &intf->NetWakeResolve[i]); 511747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 511847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 511947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 512047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 512147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 512247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 512347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 512447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SendGoodbyes) // If we didn't find even one Sleep Proxy 512547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 512647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server"); 512747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendSleepGoodbyes(m); 512847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 512947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 513047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 513147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep. 513247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up. 513347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Normally, the platform support layer below mDNSCore should call this, not the client layer above. 513447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep) 513547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 513647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 513747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 513847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow); 513947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 514047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sleep && !m->SleepState) // Going to sleep 514147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 514247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 514347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server 514447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SPSSocket) 514547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 514647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 oldstate = m->SPSState; 514747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here 514847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSState = 2; 514947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (oldstate == 1) mDNS_DeregisterService(m, &m->SPSRecords); 515047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_ReclaimLockAfterCallback(); 515147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 515247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 515347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SleepState = SleepState_Transferring; 515447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SystemWakeOnLANEnabled && m->DelaySleep) 515547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 515647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep 515747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow); 515847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SleepLimit = NonZeroTime(m->DelaySleep + mDNSPlatformOneSecond * 10); 515947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 516047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 516147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 516247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->DelaySleep = 0; 516347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SleepLimit = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 10); 516447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt BeginSleepProcessing(m); 516547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 516647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 516747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 516847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SuspendLLQs(m); 516947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 517047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 517147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // RemoveAutoTunnel6Record needs to be called outside the lock, as it grabs the lock also. 517247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder 517347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RemoveAutoTunnel6Record(m); 517447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 517547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState, 517647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SleepState == SleepState_Transferring ? "Transferring" : 517747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", m->SleepSeqNum); 517847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 517947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (!sleep) // Waking up 518047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 518147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 518247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg; 518347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *cr; 518447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf; 518547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 518647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 518747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Reset SleepLimit back to 0 now that we're awake again. 518847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SleepLimit = 0; 518947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 519047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness 519147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SleepState != SleepState_Awake) 519247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 519347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SleepState = SleepState_Awake; 519447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SleepSeqNum++; 519547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake) 519647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then we enforce a minimum delay of 16 seconds before we begin sleep processing. 519747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc., 519847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // before we make our determination of whether there's a Sleep Proxy out there we should register with. 519947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->DelaySleep = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 16); 520047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 520147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 520247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SPSState == 3) 520347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 520447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSState = 0; 520547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSCoreBeSleepProxyServer_internal(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower); 520647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 520747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 520847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy, 520947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // on wake we go through our record list and clear updateid back to zero 521047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) rr->updateid = zeroID; 521147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 521247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // ... and the same for NextSPSAttempt 521347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1; 521447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 521547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Restart unicast and multicast queries 521647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSCoreRestartQueries(m); 521747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 521847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and reactivtate service registrations 521947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond); 522047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreMachineSleep waking: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow); 522147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 522247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. Re-validate our cache records 522347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt FORALL_CACHERECORDS(slot, cg, cr) 522447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake); 522547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 522647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3. Retrigger probing and announcing for all our authoritative records 522747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 522847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (AuthRecord_uDNS(rr)) 522947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 523047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ActivateUnicastRegistration(m, rr); 523147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 523247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 523347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 523447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; 523547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 523647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount = InitialAnnounceCount; 523747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendNSECNow = mDNSNULL; 523847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeLastAPTime(m, rr); 523947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 524047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 524147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 4. Refresh NAT mappings 524247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We don't want to have to assume that all hardware can necessarily keep accurate 524347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // track of passage of time while asleep, so on wake we refresh our NAT mappings 524447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We typically wake up with no interfaces active, so there's no need to rush to try to find our external address. 524547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When we get a network configuration change, mDNSMacOSXNetworkChanged calls uDNS_SetupDNSConfig, which calls 524647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // mDNS_SetPrimaryInterfaceInfo, which then sets m->retryGetAddr to immediately request our external address from the NAT gateway. 524747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->retryIntervalGetAddr = NATMAP_INIT_RETRY; 524847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->retryGetAddr = m->timenow + mDNSPlatformOneSecond * 5; 524947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreMachineSleep: retryGetAddr in %d %d", m->retryGetAddr - m->timenow, m->timenow); 525047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RecreateNATMappings(m); 525147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 525247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 525347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 525447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 525547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now) 525647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 525747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 525847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 525947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf; 526047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 526147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 526247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 526347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->DelaySleep) goto notready; 526447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 526547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we've not hit the sleep limit time, and it's not time for our next retry, we can skip these checks 526647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SleepLimit - now > 0 && m->NextScheduledSPRetry - now > 0) goto notready; 526747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 526847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledSPRetry = now + 0x40000000UL; 526947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 527047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // See if we might need to retransmit any lost Sleep Proxy Registrations 527147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 527247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->NextSPSAttempt >= 0) 527347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 527447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (now - intf->NextSPSAttemptTime >= 0) 527547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 527647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("mDNSCoreReadyForSleep: retrying for %s SPS %d try %d", 527747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->ifname, intf->NextSPSAttempt/3, intf->NextSPSAttempt); 527847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendSPSRegistration(m, intf, zeroID); 527947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't need to "goto notready" here, because if we do still have record registrations 528047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that have not been acknowledged yet, we'll catch that in the record list scan below. 528147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 528247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 528347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0) 528447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledSPRetry = intf->NextSPSAttemptTime; 528547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 528647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 528747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Scan list of interfaces, and see if we're still waiting for any sleep proxy resolves to complete 528847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 528947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 529047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int sps = (intf->NextSPSAttempt == 0) ? 0 : (intf->NextSPSAttempt-1)/3; 529147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->NetWakeResolve[sps].ThisQInterval >= 0) 529247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 529347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("mDNSCoreReadyForSleep: waiting for SPS Resolve %s %##s (%s)", 529447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->ifname, intf->NetWakeResolve[sps].qname.c, DNSTypeName(intf->NetWakeResolve[sps].qtype)); 529547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt goto spsnotready; 529647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 529747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 529847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 529947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Scan list of registered records 530047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr = rr->next) 530147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AuthRecord_uDNS(rr)) 530247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(rr->updateid)) 530347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { LogSPS("mDNSCoreReadyForSleep: waiting for SPS Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto spsnotready; } 530447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 530547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Scan list of private LLQs, and make sure they've all completed their handshake with the server 530647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q = q->next) 530747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp) 530847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 530947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("mDNSCoreReadyForSleep: waiting for LLQ %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 531047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt goto notready; 531147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 531247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 531347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Scan list of registered records 531447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr = rr->next) 531547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (AuthRecord_uDNS(rr)) 531647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 531747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->state == regState_Refresh && rr->tcp) 531847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { LogSPS("mDNSCoreReadyForSleep: waiting for Record Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; } 531947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #if APPLE_OSX_mDNSResponder 532047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!RecordReadyForSleep(m, rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; } 532147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #endif 532247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 532347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 532447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 532547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNStrue; 532647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 532747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltspsnotready: 532847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 532947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we failed to complete sleep proxy registration within ten seconds, we give up on that 533047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and allow up to ten seconds more to complete wide-area deregistration instead 533147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (now - m->SleepLimit >= 0) 533247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 533347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Failed to register with SPS, now sending goodbyes"); 533447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 533547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 533647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->NetWakeBrowse.ThisQInterval >= 0) 533747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 533847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("ReadyForSleep mDNS_DeactivateNetWake %s %##s (%s)", 533947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype)); 534047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DeactivateNetWake_internal(m, intf); 534147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 534247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 534347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr = rr->next) 534447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AuthRecord_uDNS(rr)) 534547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(rr->updateid)) 534647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 534747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("ReadyForSleep clearing updateid for %s", ARDisplayString(m, rr)); 534847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->updateid = zeroID; 534947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 535047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 535147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We'd really like to allow up to ten seconds more here, 535247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // but if we don't respond to the sleep notification within 30 seconds 535347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we'll be put back to sleep forcibly without the chance to schedule the next maintenance wake. 535447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Right now we wait 16 sec after wake for all the interfaces to come up, then we wait up to 10 seconds 535547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // more for SPS resolves and record registrations to complete, which puts us at 26 seconds. 535647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we allow just one more second to send our goodbyes, that puts us at 27 seconds. 535747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SleepLimit = now + mDNSPlatformOneSecond * 1; 535847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 535947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendSleepGoodbyes(m); 536047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 536147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 536247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltnotready: 536347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 536447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNSfalse; 536547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 536647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 536747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now) 536847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 536947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *ar; 537047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 537147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Even when we have no wake-on-LAN-capable interfaces, or we failed to find a sleep proxy, or we have other 537247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // failure scenarios, we still want to wake up in at most 120 minutes, to see if the network environment has changed. 537347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment, 537447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and if that happens we don't want to just give up and go back to sleep and never try again. 537547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 e = now + (120 * 60 * mDNSPlatformOneSecond); // Sleep for at most 120 minutes 537647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 537747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NATTraversalInfo *nat; 537847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (nat = m->NATTraversals; nat; nat=nat->next) 537947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (nat->Protocol && nat->ExpiryTime && nat->ExpiryTime - now > mDNSPlatformOneSecond*4) 538047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 538147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 t = nat->ExpiryTime - (nat->ExpiryTime - now) / 10; // Wake up when 90% of the way to the expiry time 538247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (e - t > 0) e = t; 538347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d", 538447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP", 538547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result, 538647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0, 538747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt nat->retryInterval / mDNSPlatformOneSecond, 538847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0, 538947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (t - now) / mDNSPlatformOneSecond); 539047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 539147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 539247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This loop checks both the time we need to renew wide-area registrations, 539347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and the time we need to renew Sleep Proxy registrations 539447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (ar = m->ResourceRecords; ar; ar = ar->next) 539547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ar->expire && ar->expire - now > mDNSPlatformOneSecond*4) 539647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 539747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 t = ar->expire - (ar->expire - now) / 10; // Wake up when 90% of the way to the expiry time 539847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (e - t > 0) e = t; 539947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s", 540047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar, ar->ThisAPInterval / mDNSPlatformOneSecond, 540147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond, 540247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0, 540347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (t - now) / mDNSPlatformOneSecond, ARDisplayString(m, ar)); 540447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 540547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 540647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(e - now); 540747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 540847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 540947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// *************************************************************************** 541047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK 541147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - 541247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Packet Reception Functions 541347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 541447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 541547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo) 541647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 541747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end, 541847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords) 541947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 542047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *responseptr = response->data; 542147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *const limit = response->data + sizeof(response->data); 542247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *ptr = query->data; 542347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 542447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 maxttl = 0x70000000; 542547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 542647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 542747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Initialize the response fields so we can answer the questions 542847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeDNSMessage(&response->h, query->h.id, ResponseFlags); 542947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 543047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 543147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 1. Write out the list of questions we are actually going to answer with this packet 543247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 543347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (LegacyQuery) 543447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 543547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt maxttl = kStaticCacheTTL; 543647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<query->h.numQuestions; i++) // For each question... 543747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 543847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion q; 543947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = getQuestion(query, ptr, end, InterfaceID, &q); // get the question... 544047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ptr) return(mDNSNULL); 544147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 544247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr=ResponseRecords; rr; rr=rr->NextResponse) // and search our list of proposed answers 544347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 544447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NR_AnswerTo == ptr) // If we're going to generate a record answering this question 544547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { // then put the question in the question section 544647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt responseptr = putQuestion(response, responseptr, limit, &q.qname, q.qtype, q.qclass); 544747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!responseptr) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL); } 544847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; // break out of the ResponseRecords loop, and go on to the next question 544947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 545047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 545147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 545247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 545347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (response->h.numQuestions == 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL); } 545447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 545547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 545647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 545747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 2. Write Answers 545847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 545947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr=ResponseRecords; rr; rr=rr->NextResponse) 546047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NR_AnswerTo) 546147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 546247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAnswers, &rr->resrec, 546347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl); 546447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (p) responseptr = p; 546547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; } 546647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 546747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 546847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 546947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 3. Write Additionals 547047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 547147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr=ResponseRecords; rr; rr=rr->NextResponse) 547247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NR_AdditionalTo && !rr->NR_AnswerTo) 547347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 547447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec, 547547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl); 547647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (p) responseptr = p; 547747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else debugf("GenerateUnicastResponse: No more space for additionals"); 547847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 547947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 548047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(responseptr); 548147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 548247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 548347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// AuthRecord *our is our Resource Record 548447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network 548547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Returns 0 if there is no conflict 548647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Returns +1 if there was a conflict and we won 548747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Returns -1 if there was a conflict and we lost and have to rename 548847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const pkt) 548947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 549047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 ourdata[256], *ourptr = ourdata, *ourend; 549147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 pktdata[256], *pktptr = pktdata, *pktend; 549247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); } 549347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); } 549447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 549547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec); 549647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec); 549747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; } 549847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ourptr >= ourend && pktptr >= pktend) return(0); // If data identical, not a conflict 549947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 550047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ourptr >= ourend) return(-1); // Our data ran out first; We lost 550147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (pktptr >= pktend) return(+1); // Packet data ran out first; We won 550247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*pktptr > *ourptr) return(-1); // Our data is numerically lower; We lost 550347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*pktptr < *ourptr) return(+1); // Packet data is numerically lower; We won 550447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 550547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("CompareRData ERROR: Invalid state"); 550647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(-1); 550747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 550847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 550947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// See if we have an authoritative record that's identical to this packet record, 551047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// whose canonical DependentOn record is the specified master record. 551147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The DependentOn pointer is typically used for the TXT record of service registrations 551247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// It indicates that there is no inherent conflict detection for the TXT record 551347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// -- it depends on the SRV record to resolve name conflicts 551447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If we find any identical ResourceRecords in our authoritative list, then follow their DependentOn 551547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// pointer chain (if any) to make sure we reach the canonical DependentOn record 551647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If the record has no DependentOn, then just return that record's pointer 551747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Returns NULL if we don't have any local RRs that are identical to the one from the packet 551847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool MatchDependentOn(const mDNS *const m, const CacheRecord *const pktrr, const AuthRecord *const master) 551947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 552047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const AuthRecord *r1; 552147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r1 = m->ResourceRecords; r1; r1=r1->next) 552247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 552347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec)) 552447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 552547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const AuthRecord *r2 = r1; 552647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (r2->DependentOn) r2 = r2->DependentOn; 552747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2 == master) return(mDNStrue); 552847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 552947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 553047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r1 = m->DuplicateRecords; r1; r1=r1->next) 553147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 553247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec)) 553347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 553447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const AuthRecord *r2 = r1; 553547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (r2->DependentOn) r2 = r2->DependentOn; 553647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2 == master) return(mDNStrue); 553747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 553847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 553947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSfalse); 554047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 554147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 554247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Find the canonical RRSet pointer for this RR received in a packet. 554347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If we find any identical AuthRecord in our authoritative list, then follow its RRSet 554447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// pointers (if any) to make sure we return the canonical member of this name/type/class 554547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Returns NULL if we don't have any local RRs that are identical to the one from the packet 554647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal const AuthRecord *FindRRSet(const mDNS *const m, const CacheRecord *const pktrr) 554747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 554847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const AuthRecord *rr; 554947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 555047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 555147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec)) 555247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 555347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (rr->RRSet && rr != rr->RRSet) rr = rr->RRSet; 555447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(rr); 555547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 555647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 555747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSNULL); 555847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 555947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 556047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// PacketRRConflict is called when we've received an RR (pktrr) which has the same name 556147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// as one of our records (our) but different rdata. 556247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 1. If our record is not a type that's supposed to be unique, we don't care. 556347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 2a. If our record is marked as dependent on some other record for conflict detection, ignore this one. 556447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 2b. If the packet rr exactly matches one of our other RRs, and *that* record's DependentOn pointer 556547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// points to our record, ignore this conflict (e.g. the packet record matches one of our 556647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// TXT records, and that record is marked as dependent on 'our', its SRV record). 556747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 3. If we have some *other* RR that exactly matches the one from the packet, and that record and our record 556847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// are members of the same RRSet, then this is not a conflict. 556947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool PacketRRConflict(const mDNS *const m, const AuthRecord *const our, const CacheRecord *const pktrr) 557047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 557147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If not supposed to be unique, not a conflict 557247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!(our->resrec.RecordType & kDNSRecordTypeUniqueMask)) return(mDNSfalse); 557347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 557447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If a dependent record, not a conflict 557547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (our->DependentOn || MatchDependentOn(m, pktrr, our)) return(mDNSfalse); 557647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 557747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 557847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the pktrr matches a member of ourset, not a conflict 557947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const AuthRecord *ourset = our->RRSet ? our->RRSet : our; 558047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const AuthRecord *pktset = FindRRSet(m, pktrr); 558147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (pktset == ourset) return(mDNSfalse); 558247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 558347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For records we're proxying, where we don't know the full 558447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // relationship between the records, having any matching record 558547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // in our AuthRecords list is sufficient evidence of non-conflict 558647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (our->WakeUp.HMAC.l[0] && pktset) return(mDNSfalse); 558747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 558847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 558947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Okay, this is a conflict 559047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNStrue); 559147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 559247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 559347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change 559447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// the record list and/or question list. 559547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 559647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end, 559747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q, AuthRecord *our) 559847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 559947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 560047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *ptr = LocateAuthorities(query, end); 560147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool FoundUpdate = mDNSfalse; 560247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 560347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i = 0; i < query->h.numAuthorities; i++) 560447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 560547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec); 560647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ptr) break; 560747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && ResourceRecordAnswersQuestion(&m->rec.r.resrec, q)) 560847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 560947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt FoundUpdate = mDNStrue; 561047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (PacketRRConflict(m, our, &m->rec.r)) 561147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 561247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int result = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass; 561347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!result) result = (int)our->resrec.rrtype - (int)m->rec.r.resrec.rrtype; 561447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!result) result = CompareRData(our, &m->rec.r); 561547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (result) 561647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 561747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *const msg = (result < 0) ? "lost:" : (result > 0) ? "won: " : "tie: "; 561847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("ResolveSimultaneousProbe: %p Pkt Record: %08lX %s", q->InterfaceID, m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r)); 561947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("ResolveSimultaneousProbe: %p Our Record %d %s %08lX %s", our->resrec.InterfaceID, our->ProbeCount, msg, our->resrec.rdatahash, ARDisplayString(m, our)); 562047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 562147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we lost the tie-break for simultaneous probes, we don't immediately give up, because we might be seeing stale packets on the network. 562247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Instead we pause for one second, to give the other host (if real) a chance to establish its name, and then try probing again. 562347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If there really is another live host out there with the same name, it will answer our probes and we'll then rename. 562447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (result < 0) 562547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 562647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond); 562747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt our->ProbeCount = DefaultProbeCountForTypeUnique; 562847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt our->AnnounceCount = InitialAnnounceCount; 562947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeLastAPTime(m, our); 563047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt goto exit; 563147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 563247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 563347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if 0 563447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 563547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 563647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("ResolveSimultaneousProbe: %p Pkt Record: %08lX %s", q->InterfaceID, m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r)); 563747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("ResolveSimultaneousProbe: %p Our Record %d ign: %08lX %s", our->resrec.InterfaceID, our->ProbeCount, our->resrec.rdatahash, ARDisplayString(m, our)); 563847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 563947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 564047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 564147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 564247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 564347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!FoundUpdate) 564447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); 564547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit: 564647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 564747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 564847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 564947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const ResourceRecord *const pktrr) 565047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 565147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot = HashSlot(pktrr->name); 565247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr); 565347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr; 565447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool match; 565547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 565647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 565747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt match = !pktrr->InterfaceID ? pktrr->rDNSServer == rr->resrec.rDNSServer : pktrr->InterfaceID == rr->resrec.InterfaceID; 565847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (match && IdenticalSameNameRecord(pktrr, &rr->resrec)) break; 565947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 566047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(rr); 566147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 566247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 566347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Called from mDNSCoreReceiveUpdate when we get a sleep proxy registration request, 566447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// to check our lists and discard any stale duplicates of this record we already have 566547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ClearIdenticalProxyRecords(mDNS *const m, const OwnerOptData *const owner, AuthRecord *const thelist) 566647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 566747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord) 566847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("ClearIdenticalProxyRecords ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 566947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = thelist; 567047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord) 567147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 567247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *const rr = m->CurrentRecord; 567347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rec.r.resrec.InterfaceID == rr->resrec.InterfaceID && mDNSSameEthAddress(&owner->HMAC, &rr->WakeUp.HMAC)) 567447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (IdenticalResourceRecord(&rr->resrec, &m->rec.r.resrec)) 567547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 567647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("ClearIdenticalProxyRecords: Removing %3d H-MAC %.6a I-MAC %.6a %d %d %s", 567747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, owner->seq, ARDisplayString(m, rr)); 567847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->WakeUp.HMAC = zeroEthAddr; // Clear HMAC so that mDNS_Deregister_internal doesn't waste packets trying to wake this host 567947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->RequireGoodbye = mDNSfalse; // and we don't want to send goodbye for it 568047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 568147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetSPSProxyListChanged(m->rec.r.resrec.InterfaceID); 568247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 568347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because 568447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // new records could have been added to the end of the list as a result of that call. 568547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now 568647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = rr->next; 568747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 568847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 568947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 569047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Called from ProcessQuery when we get an mDNS packet with an owner record in it 569147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ClearProxyRecords(mDNS *const m, const OwnerOptData *const owner, AuthRecord *const thelist) 569247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 569347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord) 569447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("ClearProxyRecords ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 569547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = thelist; 569647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord) 569747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 569847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *const rr = m->CurrentRecord; 569947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rec.r.resrec.InterfaceID == rr->resrec.InterfaceID && mDNSSameEthAddress(&owner->HMAC, &rr->WakeUp.HMAC)) 570047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (owner->seq != rr->WakeUp.seq || m->timenow - rr->TimeRcvd > mDNSPlatformOneSecond * 60) 570147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 570247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->AddressProxy.type == mDNSAddrType_IPv6) 570347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 570447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We don't do this here because we know that the host is waking up at this point, so we don't send 570547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Unsolicited Neighbor Advertisements -- even Neighbor Advertisements agreeing with what the host should be 570647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // saying itself -- because it can cause some IPv6 stacks to falsely conclude that there's an address conflict. 570747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #if MDNS_USE_Unsolicited_Neighbor_Advertisements 570847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("NDP Announcement -- Releasing traffic for H-MAC %.6a I-MAC %.6a %s", 570947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr)); 571047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendNDP(m, NDP_Adv, NDP_Override, rr, &rr->AddressProxy.ip.v6, &rr->WakeUp.IMAC, &AllHosts_v6, &AllHosts_v6_Eth); 571147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #endif 571247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 571347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("ClearProxyRecords: Removing %3d AC %2d %02X H-MAC %.6a I-MAC %.6a %d %d %s", 571447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ProxyRecords, rr->AnnounceCount, rr->resrec.RecordType, 571547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, owner->seq, ARDisplayString(m, rr)); 571647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) rr->resrec.RecordType = kDNSRecordTypeShared; 571747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->WakeUp.HMAC = zeroEthAddr; // Clear HMAC so that mDNS_Deregister_internal doesn't waste packets trying to wake this host 571847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->RequireGoodbye = mDNSfalse; // and we don't want to send goodbye for it, since real host is now back and functional 571947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 572047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetSPSProxyListChanged(m->rec.r.resrec.InterfaceID); 572147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 572247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because 572347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // new records could have been added to the end of the list as a result of that call. 572447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now 572547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = rr->next; 572647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 572747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 572847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 572947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ProcessQuery examines a received query to see if we have any answers to give 573047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end, 573147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast, 573247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool QueryWasLocalUnicast, DNSMessage *const response) 573347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 573447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool FromLocalSubnet = srcaddr && mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr); 573547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *ResponseRecords = mDNSNULL; 573647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord **nrp = &ResponseRecords; 573747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *ExpectedAnswers = mDNSNULL; // Records in our cache we expect to see updated 573847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord **eap = &ExpectedAnswers; 573947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *DupQuestions = mDNSNULL; // Our questions that are identical to questions in this packet 574047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion **dqp = &DupQuestions; 574147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 delayresponse = 0; 574247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool SendLegacyResponse = mDNSfalse; 574347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *ptr; 574447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *responseptr = mDNSNULL; 574547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 574647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 574747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 574847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 574947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 1. Look in Additional Section for an OPT record 575047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 575147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = LocateOptRR(query, end, DNSOpt_OwnerData_ID_Space); 575247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ptr) 575347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 575447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAdd, &m->rec); 575547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT) 575647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 575747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const rdataOPT *opt; 575847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength]; 575947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Find owner sub-option(s). We verify that the MAC is non-zero, otherwise we could inadvertently 576047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // delete all our own AuthRecords (which are identified by having zero MAC tags on them). 576147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (opt = &m->rec.r.resrec.rdata->u.opt[0]; opt < e; opt++) 576247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (opt->opt == kDNSOpt_Owner && opt->u.owner.vers == 0 && opt->u.owner.HMAC.l[0]) 576347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 576447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ClearProxyRecords(m, &opt->u.owner, m->DuplicateRecords); 576547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ClearProxyRecords(m, &opt->u.owner, m->ResourceRecords); 576647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 576747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 576847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 576947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 577047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 577147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 577247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 2. Parse Question Section and mark potential answers 577347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 577447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = query->data; 577547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<query->h.numQuestions; i++) // For each question... 577647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 577747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool QuestionNeedsMulticastResponse; 577847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int NumAnswersForThisQuestion = 0; 577947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *NSECAnswer = mDNSNULL; 578047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion pktq, *q; 578147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = getQuestion(query, ptr, end, InterfaceID, &pktq); // get the question... 578247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ptr) goto exit; 578347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 578447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The only queries that *need* a multicast response are: 578547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // * Queries sent via multicast 578647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // * from port 5353 578747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // * that don't have the kDNSQClass_UnicastResponse bit set 578847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // These queries need multicast responses because other clients will: 578947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // * suppress their own identical questions when they see these questions, and 579047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // * expire their cache records if they don't see the expected responses 579147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For other queries, we may still choose to send the occasional multicast response anyway, 579247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to keep our neighbours caches warm, and for ongoing conflict detection. 579347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt QuestionNeedsMulticastResponse = QueryWasMulticast && !LegacyQuery && !(pktq.qclass & kDNSQClass_UnicastResponse); 579447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Clear the UnicastResponse flag -- don't want to confuse the rest of the code that follows later 579547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt pktq.qclass &= ~kDNSQClass_UnicastResponse; 579647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 579747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: We use the m->CurrentRecord mechanism here because calling ResolveSimultaneousProbe 579847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // can result in user callbacks which may change the record list and/or question list. 579947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Also note: we just mark potential answer records here, without trying to build the 580047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // "ResponseRecords" list, because we don't want to risk user callbacks deleting records 580147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // from that list while we're in the middle of trying to build it. 580247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord) 580347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("ProcessQuery ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 580447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = m->ResourceRecords; 580547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord) 580647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 580747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr = m->CurrentRecord; 580847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = rr->next; 580947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (AnyTypeRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery)) 581047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 581147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRTypeAnswersQuestionType(&rr->resrec, pktq.qtype)) 581247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 581347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeUnique) 581447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ResolveSimultaneousProbe(m, query, end, &pktq, rr); 581547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (ResourceRecordIsValidAnswer(rr)) 581647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 581747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NumAnswersForThisQuestion++; 581847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: We should check here if this is a probe-type query, and if so, generate an immediate 581947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // unicast answer back to the source, because timeliness in answering probes is important. 582047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 582147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Notes: 582247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast) 582347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // NR_AnswerTo == (mDNSu8*)~1 means "answer via delayed unicast" (to modern querier; may promote to multicast instead) 582447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // NR_AnswerTo == (mDNSu8*)~0 means "definitely answer via multicast" (can't downgrade to unicast later) 582547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set, 582647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // but the multicast querier is not on a matching subnet (e.g. because of overlaid subnets on one link) 582747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source) 582847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery)) 582947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 583047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We only mark this question for sending if it is at least one second since the last time we multicast it 583147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it. 583247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This is to guard against the case where someone blasts us with queries as fast as they can. 583347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 || 583447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID)) 583547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NR_AnswerTo = (mDNSu8*)~0; 583647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 583747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1; 583847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 583947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 584047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if ((rr->resrec.RecordType & kDNSRecordTypeActiveUniqueMask) && ResourceRecordIsValidAnswer(rr)) 584147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 584247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we don't have any answers for this question, but we do own another record with the same name, 584347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then we'll want to mark it to generate an NSEC record on this interface 584447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!NSECAnswer) NSECAnswer = rr; 584547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 584647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 584747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 584847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 584947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (NumAnswersForThisQuestion == 0 && NSECAnswer) 585047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 585147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NumAnswersForThisQuestion++; 585247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NSECAnswer->SendNSECNow = InterfaceID; 585347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledResponse = m->timenow; 585447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 585547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 585647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we couldn't answer this question, someone else might be able to, 585747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so use random delay on response to reduce collisions 585847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (NumAnswersForThisQuestion == 0) delayresponse = mDNSPlatformOneSecond; // Divided by 50 = 20ms 585947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 586047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 586147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (QuestionNeedsMulticastResponse) 586247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#else 586347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We only do the following accelerated cache expiration and duplicate question suppression processing 586447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // for non-truncated multicast queries with multicast responses. 586547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For any query generating a unicast response we don't do this because we can't assume we will see the response. 586647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For truncated queries we don't do this because a response we're expecting might be suppressed by a subsequent 586747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // known-answer packet, and when there's packet loss we can't safely assume we'll receive *all* known-answer packets. 586847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (QuestionNeedsMulticastResponse && !(query->h.flags.b[0] & kDNSFlag0_TC)) 586947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 587047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 587147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = HashSlot(&pktq.qname); 587247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname); 587347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *cr; 587447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 587547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Make a list indicating which of our own cache records we expect to see updated as a result of this query 587647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated 587747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 587847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!(query->h.flags.b[0] & kDNSFlag0_TC)) 587947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 588047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) 588147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit) 588247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!cr->NextInKAList && eap != &cr->NextInKAList) 588347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 588447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *eap = cr; 588547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt eap = &cr->NextInKAList; 588647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 588747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->MPUnansweredQ == 0 || m->timenow - cr->MPLastUnansweredQT >= mDNSPlatformOneSecond) 588847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 588947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Although MPUnansweredQ is only really used for multi-packet query processing, 589047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we increment it for both single-packet and multi-packet queries, so that it stays in sync 589147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // with the MPUnansweredKA value, which by necessity is incremented for both query types. 589247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->MPUnansweredQ++; 589347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->MPLastUnansweredQT = m->timenow; 589447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->MPExpectingKA = mDNStrue; 589547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 589647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 589747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 589847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 589947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Check if this question is the same as any of mine. 590047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We only do this for non-truncated queries. Right now it would be too complicated to try 590147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to keep track of duplicate suppression state between multiple packets, especially when we 590247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // can't guarantee to receive all of the Known Answer packets that go with a particular query. 590347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 590447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!(query->h.flags.b[0] & kDNSFlag0_TC)) 590547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 590647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) 590747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4) 590847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q->InterfaceID || q->InterfaceID == InterfaceID) 590947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList) 591047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->qtype == pktq.qtype && 591147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qclass == pktq.qclass && 591247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname)) 591347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { *dqp = q; dqp = &q->NextInDQList; } 591447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 591547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 591647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 591747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 591847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 3. Now we can safely build the list of marked answers 591947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 592047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) // Now build our list of potential answers 592147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NR_AnswerTo) // If we marked the record... 592247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AddRecordToResponseList(&nrp, rr, mDNSNULL); // ... add it to the list 592347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 592447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 592547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 4. Add additional records 592647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 592747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID); 592847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 592947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 593047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 5. Parse Answer Section and cancel any records disallowed by Known-Answer list 593147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 593247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<query->h.numAnswers; i++) // For each record in the query's answer section... 593347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 593447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Get the record... 593547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *ourcacherr; 593647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec); 593747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ptr) goto exit; 593847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative) 593947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 594047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // See if this Known-Answer suppresses any of our currently planned answers 594147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr=ResponseRecords; rr; rr=rr->NextResponse) 594247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr)) 594347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; } 594447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 594547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression) 594647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr=m->ResourceRecords; rr; rr=rr->next) 594747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 594847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression 594947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr)) 595047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 595147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (srcaddr->type == mDNSAddrType_IPv4) 595247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 595347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr; 595447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 595547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (srcaddr->type == mDNSAddrType_IPv6) 595647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 595747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr; 595847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 595947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester)) 596047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 596147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAnswer = mDNSNULL; 596247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedUnicast = mDNSfalse; 596347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES 596447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr)); 596547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #endif 596647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 596747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 596847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 596947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 597047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec); 597147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 597247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #if ENABLE_MULTI_PACKET_QUERY_SNOOPING 597347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always, 597447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list). 597547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond) 597647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 597747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ourcacherr->MPUnansweredKA++; 597847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ourcacherr->MPExpectingKA = mDNSfalse; 597947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 598047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #endif 598147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 598247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Having built our ExpectedAnswers list from the questions in this packet, we then remove 598347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // any records that are suppressed by the Known Answer list in this packet. 598447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt eap = &ExpectedAnswers; 598547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*eap) 598647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 598747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *cr = *eap; 598847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &cr->resrec)) 598947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { *eap = cr->NextInKAList; cr->NextInKAList = mDNSNULL; } 599047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else eap = &cr->NextInKAList; 599147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 599247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 599347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query. 599447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ourcacherr) 599547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 599647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dqp = &DupQuestions; 599747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*dqp) 599847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 599947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q = *dqp; 600047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q)) 600147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; } 600247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else dqp = &q->NextInDQList; 600347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 600447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 600547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 600647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 600747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 600847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 600947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 601047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 6. Cancel any additionals that were added because of now-deleted records 601147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 601247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr=ResponseRecords; rr; rr=rr->NextResponse) 601347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NR_AdditionalTo && !MustSendRecord(rr->NR_AdditionalTo)) 601447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; } 601547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 601647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 601747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 7. Mark the send flags on the records we plan to send 601847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 601947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr=ResponseRecords; rr; rr=rr->NextResponse) 602047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 602147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NR_AnswerTo) 602247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 602347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool SendMulticastResponse = mDNSfalse; // Send modern multicast response 602447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool SendUnicastResponse = mDNSfalse; // Send modern unicast response (not legacy unicast response) 602547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 602647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If it's been a while since we multicast this, then send a multicast response for conflict detection, etc. 602747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0) 602847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 602947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendMulticastResponse = mDNStrue; 603047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this record was marked for modern (delayed) unicast response, then mark it as promoted to 603147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below). 603247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value. 603347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NR_AnswerTo == (mDNSu8*)~1) rr->NR_AnswerTo = (mDNSu8*)~0; 603447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 603547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 603647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the client insists on a multicast response, then we'd better send one 603747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NR_AnswerTo == (mDNSu8*)~0) SendMulticastResponse = mDNStrue; 603847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->NR_AnswerTo == (mDNSu8*)~1) SendUnicastResponse = mDNStrue; 603947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->NR_AnswerTo) SendLegacyResponse = mDNStrue; 604047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 604147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SendMulticastResponse || SendUnicastResponse) 604247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 604347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES 604447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAnswerMarkTime = m->timenow; 604547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 604647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledResponse = m->timenow; 604747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we're already planning to send this on another interface, just send it on all interfaces 604847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedAnswer && rr->ImmedAnswer != InterfaceID) 604947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAnswer = mDNSInterfaceMark; 605047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 605147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 605247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAnswer = InterfaceID; // Record interface to send it on 605347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SendUnicastResponse) rr->ImmedUnicast = mDNStrue; 605447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (srcaddr->type == mDNSAddrType_IPv4) 605547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 605647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSIPv4AddressIsZero(rr->v4Requester)) rr->v4Requester = srcaddr->ip.v4; 605747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (!mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = onesIPv4Addr; 605847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 605947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (srcaddr->type == mDNSAddrType_IPv6) 606047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 606147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSIPv6AddressIsZero(rr->v6Requester)) rr->v6Requester = srcaddr->ip.v6; 606247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (!mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = onesIPv6Addr; 606347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 606447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 606547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 606647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If TC flag is set, it means we should expect that additional known answers may be coming in another packet, 606747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11) 606847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses 606947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // else, for a simple unique record reply, we can reply immediately; no need for delay 607047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (query->h.flags.b[0] & kDNSFlag0_TC) delayresponse = mDNSPlatformOneSecond * 20; // Divided by 50 = 400ms 607147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->resrec.RecordType == kDNSRecordTypeShared) delayresponse = mDNSPlatformOneSecond; // Divided by 50 = 20ms 607247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 607347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->NR_AdditionalTo && rr->NR_AdditionalTo->NR_AnswerTo == (mDNSu8*)~0) 607447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 607547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Since additional records are an optimization anyway, we only ever send them on one interface at a time 607647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If two clients on different interfaces do queries that invoke the same optional additional answer, 607747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then the earlier client is out of luck 607847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ImmedAdditional = InterfaceID; 607947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // No need to set m->NextScheduledResponse here 608047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We'll send these additional records when we send them, or not, as the case may be 608147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 608247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 608347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 608447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 608547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 8. If we think other machines are likely to answer these questions, set our packet suppression timer 608647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 608747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (delayresponse && (!m->SuppressSending || (m->SuppressSending - m->timenow) < (delayresponse + 49) / 50)) 608847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 608947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES 609047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 oldss = m->SuppressSending; 609147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (oldss && delayresponse) 609247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Current SuppressSending delay%5ld; require%5ld", m->SuppressSending - m->timenow, (delayresponse + 49) / 50); 609347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 609447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Pick a random delay: 609547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We start with the base delay chosen above (typically either 1 second or 20 seconds), 609647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds). 609747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This is an integer value, with resolution determined by the platform clock rate. 609847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We then divide that by 50 to get the delay value in ticks. We defer the division until last 609947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to get better results on platforms with coarse clock granularity (e.g. ten ticks per second). 610047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The +49 before dividing is to ensure we round up, not down, to ensure that even 610147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // on platforms where the native clock rate is less than fifty ticks per second, 610247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we still guarantee that the final calculated delay is at least one platform tick. 610347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We want to make sure we don't ever allow the delay to be zero ticks, 610447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // because if that happens we'll fail the Bonjour Conformance Test. 610547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Our final computed delay is 20-120ms for normal delayed replies, 610647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // or 400-500ms in the case of multi-packet known-answer lists. 610747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressSending = m->timenow + (delayresponse + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*5) + 49) / 50; 610847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SuppressSending == 0) m->SuppressSending = 1; 610947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES 611047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (oldss && delayresponse) 611147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Set SuppressSending to %5ld", m->SuppressSending - m->timenow); 611247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 611347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 611447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 611547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 611647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 9. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too 611747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 611847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SendLegacyResponse) 611947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt responseptr = GenerateUnicastResponse(query, end, InterfaceID, LegacyQuery, response, ResponseRecords); 612047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 612147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit: 612247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 612347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 612447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 612547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 10. Finally, clear our link chains ready for use next time 612647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *** 612747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (ResponseRecords) 612847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 612947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr = ResponseRecords; 613047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ResponseRecords = rr->NextResponse; 613147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NextResponse = mDNSNULL; 613247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NR_AnswerTo = mDNSNULL; 613347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NR_AdditionalTo = mDNSNULL; 613447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 613547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 613647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (ExpectedAnswers) 613747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 613847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *cr = ExpectedAnswers; 613947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ExpectedAnswers = cr->NextInKAList; 614047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->NextInKAList = mDNSNULL; 614147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 614247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For non-truncated queries, we can definitively say that we should expect 614347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to be seeing a response for any records still left in the ExpectedAnswers list 614447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!(query->h.flags.b[0] & kDNSFlag0_TC)) 614547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->UnansweredQueries == 0 || m->timenow - cr->LastUnansweredTime >= mDNSPlatformOneSecond) 614647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 614747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->UnansweredQueries++; 614847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->LastUnansweredTime = m->timenow; 614947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 615047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->UnansweredQueries > 1) 615147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s", 615247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); 615347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 615447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextCacheCheckTimeForRecord(m, cr); 615547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 615647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 615747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we've seen multiple unanswered queries for this record, 615847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then mark it to expire in five seconds if we don't get a response by then. 615947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->UnansweredQueries >= MaxUnansweredQueries) 616047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 616147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 616247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Only show debugging message if this record was not about to expire anyway 616347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond) 616447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s", 616547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); 616647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 616747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); 616847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 616947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 617047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Make a guess, based on the multi-packet query / known answer counts, whether we think we 617147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for 617247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // possible packet loss of up to 20% of the additional KA packets.) 617347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (cr->MPUnansweredQ * 4 > cr->MPUnansweredKA * 5 + 8) 617447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 617547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We want to do this conservatively. 617647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If there are so many machines on the network that they have to use multi-packet known-answer lists, 617747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then we don't want them to all hit the network simultaneously with their final expiration queries. 617847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // By setting the record to expire in four minutes, we achieve two things: 617947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (a) the 90-95% final expiration queries will be less bunched together 618047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own 618147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 remain = (mDNSu32)(RRExpireTime(cr) - m->timenow) / 4; 618247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (remain > 240 * (mDNSu32)mDNSPlatformOneSecond) 618347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt remain = 240 * (mDNSu32)mDNSPlatformOneSecond; 618447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 618547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Only show debugging message if this record was not about to expire anyway 618647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond) 618747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s", 618847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); 618947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 619047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond) 619147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->UnansweredQueries++; // Treat this as equivalent to one definite unanswered query 619247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->MPUnansweredQ = 0; // Clear MPQ/MPKA statistics 619347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->MPUnansweredKA = 0; 619447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->MPExpectingKA = mDNSfalse; 619547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 619647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (remain < kDefaultReconfirmTimeForNoAnswer) 619747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt remain = kDefaultReconfirmTimeForNoAnswer; 619847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Reconfirm_internal(m, cr, remain); 619947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 620047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 620147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 620247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 620347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (DupQuestions) 620447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 620547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q = DupQuestions; 620647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DupQuestions = q->NextInDQList; 620747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->NextInDQList = mDNSNULL; 620847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt i = RecordDupSuppressInfo(q->DupSuppress, m->timenow, InterfaceID, srcaddr->type); 620947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s %d", q->qname.c, DNSTypeName(q->qtype), InterfaceID, 621047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt srcaddr->type == mDNSAddrType_IPv4 ? "v4" : "v6", i); 621147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 621247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 621347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(responseptr); 621447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 621547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 621647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, 621747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, 621847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSInterfaceID InterfaceID) 621947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 622047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *responseend = mDNSNULL; 622147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool QueryWasLocalUnicast = srcaddr && dstaddr && 622247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !mDNSAddrIsDNSMulticast(dstaddr) && mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr); 622347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 622447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!InterfaceID && dstaddr && mDNSAddrIsDNSMulticast(dstaddr)) 622547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 622647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with " 622747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes (Multicast, but no InterfaceID)", 622847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID, 622947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", 623047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", 623147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,", 623247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numAdditionals, msg->h.numAdditionals == 1 ? " " : "s", end - msg->data); 623347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 623447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 623547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 623647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with " 623747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes", 623847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID, 623947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", 624047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", 624147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,", 624247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numAdditionals, msg->h.numAdditionals == 1 ? " " : "s", end - msg->data); 624347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 624447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID, 624547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !mDNSSameIPPort(srcport, MulticastDNSPort), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg); 624647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 624747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (responseend) // If responseend is non-null, that means we built a unicast response packet 624847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 624947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld", 625047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s", 625147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s", 625247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", 625347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type); 625447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, mDNSNULL, srcaddr, srcport, mDNSNULL, mDNSNULL); 625547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 625647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 625747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 625847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if 0 625947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool TrustedSource(const mDNS *const m, const mDNSAddr *const srcaddr) 626047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 626147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSServer *s; 626247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (void)m; // Unused 626347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (void)srcaddr; // Unused 626447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (s = m->DNSServers; s; s = s->next) 626547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameAddress(srcaddr, &s->addr)) return(mDNStrue); 626647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSfalse); 626747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 626847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 626947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 627047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstruct UDPSocket_struct 627147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 627247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port 627347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt }; 627447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 627547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question, mDNSBool tcp) 627647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 627747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 627847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) 627947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 628047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!tcp && !q->LocalSocket) continue; 628147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameIPPort(tcp ? q->tcpSrcPort : q->LocalSocket->port, port) && 628247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSSameOpaque16(q->TargetQID, id) && 628347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qtype == question->qtype && 628447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qclass == question->qclass && 628547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qnamehash == question->qnamehash && 628647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameDomainName(&q->qname, &question->qname)) 628747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(q); 628847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 628947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSNULL); 629047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 629147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 629247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// This function is called when we receive a unicast response. This could be the case of a unicast response from the 629347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// DNS server or a response to the QU query. Hence, the cache record's InterfaceId can be both NULL or non-NULL (QU case) 629447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m, 629547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSIPPort port, const mDNSOpaque16 id, const CacheRecord *const rr, mDNSBool tcp) 629647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 629747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 629847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (void)id; 629947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (void)srcaddr; 630047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 630147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) 630247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 630347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q->DuplicateOf && ResourceRecordAnswersUnicastResponse(&rr->resrec, q)) 630447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 630547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(q->TargetQID)) 630647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 630747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("ExpectingUnicastResponseForRecord msg->h.id %d q->TargetQID %d for %s", mDNSVal16(id), mDNSVal16(q->TargetQID), CRDisplayString(m, rr)); 630847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 630947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameOpaque16(q->TargetQID, id)) 631047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 631147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSIPPort srcp; 631247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!tcp) 631347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 631447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt srcp = q->LocalSocket ? q->LocalSocket->port : zeroIPPort; 631547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 631647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 631747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 631847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt srcp = q->tcpSrcPort; 631947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 632047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameIPPort(srcp, port)) return(q); 632147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 632247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue); 632347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking 632447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if (TrustedSource(m, srcaddr)) return(mDNStrue); 632547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s", 632647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qname.c, DNSTypeName(q->qtype), &q->Target, mDNSVal16(srcp), srcaddr, mDNSVal16(port), CRDisplayString(m, rr)); 632747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSNULL); 632847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 632947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 633047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 633147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 633247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SrcLocal && q->ExpectUnicastResp && (mDNSu32)(m->timenow - q->ExpectUnicastResp) < (mDNSu32)(mDNSPlatformOneSecond*2)) 633347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(q); 633447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 633547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 633647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 633747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSNULL); 633847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 633947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 634047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Certain data types need more space for in-memory storage than their in-packet rdlength would imply 634147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Currently this applies only to rdata types containing more than one domainname, 634247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// or types where the domainname is not the last item in the structure. 634347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In addition, NSEC currently requires less space for in-memory storage than its in-packet representation. 634447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu16 GetRDLengthMem(const ResourceRecord *const rr) 634547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 634647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt switch (rr->rrtype) 634747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 634847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt case kDNSType_SOA: return sizeof(rdataSOA); 634947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt case kDNSType_RP: return sizeof(rdataRP); 635047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt case kDNSType_PX: return sizeof(rdataPX); 635147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt case kDNSType_NSEC:return sizeof(rdataNSEC); 635247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt default: return rr->rdlength; 635347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 635447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 635547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 635647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg, mDNSs32 delay) 635747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 635847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr = mDNSNULL; 635947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu16 RDLength = GetRDLengthMem(&m->rec.r.resrec); 636047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 636147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->rec.r.resrec.InterfaceID) debugf("CreateNewCacheEntry %s", CRDisplayString(m, &m->rec.r)); 636247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 636347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //if (RDLength > InlineCacheRDSize) 636447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // LogInfo("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r)); 636547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 636647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec); // If we don't have a CacheGroup for this name, make one now 636747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cg) rr = GetCacheRecord(m, cg, RDLength); // Make a cache record, being careful not to recycle cg 636847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rr) NoCacheAnswer(m, &m->rec.r); 636947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 637047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 637147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RData *saveptr = rr->resrec.rdata; // Save the rr->resrec.rdata pointer 637247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *rr = m->rec.r; // Block copy the CacheRecord object 637347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment 637447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header 637547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->DelayDelivery = delay; 637647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 637747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this is an oversized record with external storage allocated, copy rdata to external storage 637847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rdata == (RData*)&rr->smallrdatastorage && RDLength > InlineCacheRDSize) 637947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("rr->resrec.rdata == &rr->rdatastorage but length > InlineCacheRDSize %##s", m->rec.r.resrec.name->c); 638047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->resrec.rdata != (RData*)&rr->smallrdatastorage && RDLength <= InlineCacheRDSize) 638147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c); 638247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RDLength > InlineCacheRDSize) 638347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemCopy(rr->resrec.rdata, m->rec.r.resrec.rdata, sizeofRDataHeader + RDLength); 638447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 638547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->next = mDNSNULL; // Clear 'next' pointer 638647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *(cg->rrcache_tail) = rr; // Append this record to tail of cache slot list 638747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cg->rrcache_tail = &(rr->next); // Advance tail pointer 638847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 638947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTimeForRecord(m, rr); for us 639047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 639147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(rr); 639247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 639347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 639447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl) 639547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 639647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->TimeRcvd = m->timenow; 639747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rroriginalttl = ttl; 639847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UnansweredQueries = 0; 639947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 640047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->MPUnansweredQ = 0; 640147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->MPUnansweredKA = 0; 640247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->MPExpectingKA = mDNSfalse; 640347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 640447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextCacheCheckTimeForRecord(m, rr); 640547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 640647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 640747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease) 640847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 640947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr; 641047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = HashSlot(&q->qname); 641147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 641247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 641347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->CRActiveQuestion == q) 641447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 641547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //LogInfo("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr)); 641647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RefreshCacheRecord(m, rr, lease); 641747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 641847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 641947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 642047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl) // TTL in seconds 642147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 642247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (LLQType == uDNS_LLQ_Entire) ttl = kLLQ_DefLease; 642347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (LLQType == uDNS_LLQ_Events) 642447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 642547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the TTL is -1 for uDNS LLQ event packet, that means "remove" 642647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ttl == 0xFFFFFFFF) ttl = 0; 642747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else ttl = kLLQ_DefLease; 642847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 642947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else // else not LLQ (standard uDNS response) 643047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 643147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we 643247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // also do this check here to make sure we can't get overflow below when we add a quarter to the TTL 643347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ttl > 0x60000000UL / mDNSPlatformOneSecond) ttl = 0x60000000UL / mDNSPlatformOneSecond; 643447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 643547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Adjustment factor to avoid race condition: 643647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Suppose real record as TTL of 3600, and our local caching server has held it for 3500 seconds, so it returns an aged TTL of 100. 643747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another 643847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox. 643947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // To avoid this, we extend the record's effective TTL to give it a little extra grace period. 644047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We adjust the 100 second TTL to 126. This means that when we do our 80% query at 101 seconds, 644147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the cached copy at our local caching server will already have expired, so the server will be forced 644247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds. 644347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ttl += ttl/4 + 2; 644447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 644547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For mDNS, TTL zero means "delete this record" 644647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For uDNS, TTL zero means: this data is true at this moment, but don't cache it. 644747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds. 644847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This means that we'll do our 80, 85, 90, 95% queries at 12.00, 12.75, 13.50, 14.25 seconds 644947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // respectively, and then if we get no response, delete the record from the cache at 15 seconds. 645047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This gives the server up to three seconds to respond between when we send our 80% query at 12 seconds 645147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and when we delete the record at 15 seconds. Allowing cache lifetimes less than 15 seconds would 645247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (with the current code) result in the server having even less than three seconds to respond 645347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // before we deleted the record and reported a "remove" event to any active questions. 645447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Furthermore, with the current code, if we were to allow a TTL of less than 2 seconds 645547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then things really break (e.g. we end up making a negative cache entry). 645647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers. 645747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ttl < 15) ttl = 15; 645847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 645947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 646047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return ttl; 646147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 646247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 646347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change 646447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// the record list and/or question list. 646547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 646647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// InterfaceID non-NULL tells us the interface this multicast response was received on 646747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// InterfaceID NULL tells us this was a unicast response 646847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// dstaddr NULL tells us we received this over an outgoing TCP connection we made 646947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, 647047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const DNSMessage *const response, const mDNSu8 *end, 647147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, 647247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSInterfaceID InterfaceID) 647347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 647447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 647547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool ResponseMCast = dstaddr && mDNSAddrIsDNSMulticast(dstaddr); 647647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool ResponseSrcLocal = !srcaddr || mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr); 647747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *llqMatch = mDNSNULL; 647847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uDNS_LLQType LLQType = uDNS_recvLLQResponse(m, response, end, srcaddr, srcport, &llqMatch); 647947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 648047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // "(CacheRecord*)1" is a special (non-zero) end-of-list marker 648147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList 648247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling. 648347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *CacheFlushRecords = (CacheRecord*)1; 648447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord **cfp = &CacheFlushRecords; 648547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 648647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // All records in a DNS response packet are treated as equally valid statements of truth. If we want 648747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to guard against spoof responses, then the only credible protection against that is cryptographic 648847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record 648947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int firstauthority = response->h.numAnswers; 649047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int firstadditional = firstauthority + response->h.numAuthorities; 649147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int totalrecords = firstadditional + response->h.numAdditionals; 649247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *ptr = response->data; 649347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSServer *uDNSServer = mDNSNULL; 649447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 649547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("Received Response from %#-15a addressed to %#-15a on %p with " 649647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes LLQType %d", 649747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt srcaddr, dstaddr, InterfaceID, 649847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt response->h.numQuestions, response->h.numQuestions == 1 ? ", " : "s,", 649947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,", 650047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,", 650147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt response->h.numAdditionals, response->h.numAdditionals == 1 ? " " : "s", end - response->data, LLQType); 650247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 650347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // According to RFC 2181 <http://www.ietf.org/rfc/rfc2181.txt> 650447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When a DNS client receives a reply with TC 650547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // set, it should ignore that response, and query again, using a 650647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // mechanism, such as a TCP connection, that will permit larger replies. 650747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // It feels wrong to be throwing away data after the network went to all the trouble of delivering it to us, but 650847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // delivering some records of the RRSet first and then the remainder a couple of milliseconds later was causing 650947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // failures in our Microsoft Active Directory client, which expects to get the entire set of answers at once. 651047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // <rdar://problem/6690034> Can't bind to Active Directory 651147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In addition, if the client immediately canceled its query after getting the initial partial response, then we'll 651247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // abort our TCP connection, and not complete the operation, and end up with an incomplete RRSet in our cache. 651347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Next time there's a query for this RRSet we'll see answers in our cache, and assume we have the whole RRSet already, 651447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and not even do the TCP query. 651547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Accordingly, if we get a uDNS reply with kDNSFlag0_TC set, we bail out and wait for the TCP response containing the entire RRSet. 651647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!InterfaceID && (response->h.flags.b[0] & kDNSFlag0_TC)) return; 651747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 651847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (LLQType == uDNS_LLQ_Ignore) return; 651947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 652047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. We ignore questions (if any) in mDNS response packets 652147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. If this is an LLQ response, we handle it much the same 652247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3. If we get a uDNS UDP response with the TC (truncated) bit set, then we can't treat this 652347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // answer as being the authoritative complete RRSet, and respond by deleting all other 652447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // matching cache records that don't appear in this packet. 652547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Otherwise, this is a authoritative uDNS answer, so arrange for any stale records to be purged 652647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ResponseMCast || LLQType == uDNS_LLQ_Events || (response->h.flags.b[0] & kDNSFlag0_TC)) 652747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = LocateAnswers(response, end); 652847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Otherwise, for one-shot queries, any answers in our cache that are not also contained 652947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // in this response packet are immediately deemed to be invalid. 653047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 653147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 653247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 rcode = (mDNSu8)(response->h.flags.b[1] & kDNSFlag1_RC_Mask); 653347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool failure = !(rcode == kDNSFlag1_RC_NoErr || rcode == kDNSFlag1_RC_NXDomain || rcode == kDNSFlag1_RC_NotAuth); 653447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool returnEarly = mDNSfalse; 653547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We could possibly combine this with the similar loop at the end of this function -- 653647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // instead of tagging cache records here and then rescuing them if we find them in the answer section, 653747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we could instead use the "m->PktNum" mechanism to tag each cache record with the packet number in 653847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which it was received (or refreshed), and then at the end if we find any cache records which 653947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // answer questions in this packet's question section, but which aren't tagged with this packet's 654047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // packet number, then we deduce they are old and delete them 654147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++) 654247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 654347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion q, *qptr = mDNSNULL; 654447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = getQuestion(response, ptr, end, InterfaceID, &q); 654547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr))) 654647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 654747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!failure) 654847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 654947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr; 655047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = HashSlot(&q.qname); 655147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname); 655247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 655347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameNameRecordAnswersQuestion(&rr->resrec, qptr)) 655447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 655547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("uDNS marking %p %##s (%s) %p %s", q.InterfaceID, q.qname.c, DNSTypeName(q.qtype), 655647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.InterfaceID, CRDisplayString(m, rr)); 655747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm 655847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->TimeRcvd = m->timenow - TicksTTL(rr) - 1; 655947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UnansweredQueries = MaxUnansweredQueries; 656047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 656147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 656247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 656347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 656447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (qptr) 656547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 656647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to query %##s (%s)", qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype)); 656747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt PenalizeDNSServer(m, qptr); 656847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 656947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt returnEarly = mDNStrue; 657047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 657147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 657247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 657347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (returnEarly) 657447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 657547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("Ignoring %2d Answer%s %2d Authorit%s %2d Additional%s", 657647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,", 657747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,", 657847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s"); 657947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // not goto exit because we won't have any CacheFlushRecords and we do not want to 658047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // generate negative cache entries (we want to query the next server) 658147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 658247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 658347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 658447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 658547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i = 0; i < totalrecords && ptr && ptr < end; i++) 658647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 658747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // All responses sent via LL multicast are acceptable for caching 658847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // All responses received over our outbound TCP connections are acceptable for caching 658947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool AcceptableResponse = ResponseMCast || !dstaddr || LLQType; 659047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer 659147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to any specific question -- any code reading records from the cache needs to make that determination for itself.) 659247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 659347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 RecordType = 659447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (i < firstauthority ) ? (mDNSu8)kDNSRecordTypePacketAns : 659547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (i < firstadditional) ? (mDNSu8)kDNSRecordTypePacketAuth : (mDNSu8)kDNSRecordTypePacketAdd; 659647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec); 659747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ptr) goto exit; // Break out of the loop and clean up our CacheFlushRecords list before exiting 659847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative) { m->rec.r.resrec.RecordType = 0; continue; } 659947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 660047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't want to cache OPT or TSIG pseudo-RRs 660147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rec.r.resrec.rrtype == kDNSType_TSIG) { m->rec.r.resrec.RecordType = 0; continue; } 660247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rec.r.resrec.rrtype == kDNSType_OPT) 660347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 660447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const rdataOPT *opt; 660547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength]; 660647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Find owner sub-option(s). We verify that the MAC is non-zero, otherwise we could inadvertently 660747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // delete all our own AuthRecords (which are identified by having zero MAC tags on them). 660847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (opt = &m->rec.r.resrec.rdata->u.opt[0]; opt < e; opt++) 660947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (opt->opt == kDNSOpt_Owner && opt->u.owner.vers == 0 && opt->u.owner.HMAC.l[0]) 661047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 661147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ClearProxyRecords(m, &opt->u.owner, m->DuplicateRecords); 661247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ClearProxyRecords(m, &opt->u.owner, m->ResourceRecords); 661347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 661447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; 661547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt continue; 661647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 661747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 661847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if a CNAME record points to itself, then don't add it to the cache 661947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((m->rec.r.resrec.rrtype == kDNSType_CNAME) && SameDomainName(m->rec.r.resrec.name, &m->rec.r.resrec.rdata->u.name)) 662047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 662147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreReceiveResponse: CNAME loop domain name %##s", m->rec.r.resrec.name->c); 662247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; 662347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt continue; 662447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 662547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 662647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When we receive uDNS LLQ responses, we assume a long cache lifetime -- 662747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In the case of active LLQs, we'll get remove events when the records actually do go away 662847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In the case of polling LLQs, we assume the record remains valid until the next poll 662947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(response->h.id)) 663047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.rroriginalttl = GetEffectiveTTL(LLQType, m->rec.r.resrec.rroriginalttl); 663147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 663247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If response was not sent via LL multicast, 663347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then see if it answers a recent query of ours, which would also make it acceptable for caching. 663447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ResponseMCast) 663547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 663647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (LLQType) 663747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 663847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For Long Lived queries that are both sent over UDP and Private TCP, LLQType is set. 663947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Even though it is AcceptableResponse, we need a matching DNSServer pointer for the 664047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // queries to get ADD/RMV events. To lookup the question, we can't use 664147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // ExpectingUnicastResponseForRecord as the port numbers don't match. uDNS_recvLLQRespose 664247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // has already matched the question using the 64 bit Id in the packet and we use that here. 664347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 664447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (llqMatch != mDNSNULL) m->rec.r.resrec.rDNSServer = uDNSServer = llqMatch->qDNSServer; 664547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 664647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (!AcceptableResponse || !dstaddr) 664747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 664847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For responses that come over TCP (Responses that can't fit within UDP) or TLS (Private queries 664947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that are not long lived e.g., AAAA lookup in a Private domain), it is indicated by !dstaddr. 665047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Even though it is AcceptableResponse, we still need a DNSServer pointer for the resource records that 665147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we create. 665247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 665347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r, !dstaddr); 665447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 665547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Intialize the DNS server on the resource record which will now filter what questions we answer with 665647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // this record. 665747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 665847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We could potentially lookup the DNS server based on the source address, but that may not work always 665947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and that's why ExpectingUnicastResponseForRecord does not try to verify whether the response came 666047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // from the DNS server that queried. We follow the same logic here. If we can find a matching quetion based 666147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // on the "id" and "source port", then this response answers the question and assume the response 666247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // came from the same DNS server that we sent the query to. 666347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 666447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q != mDNSNULL) 666547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 666647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AcceptableResponse = mDNStrue; 666747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!InterfaceID) 666847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 666947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNSCoreReceiveResponse: InterfaceID %p %##s (%s)", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype)); 667047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.rDNSServer = uDNSServer = q->qDNSServer; 667147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 667247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 667347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 667447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 667547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we can't find a matching question, we need to see whether we have seen records earlier that matched 667647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the question. The code below does that. So, make this record unacceptable for now 667747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!InterfaceID) 667847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 667947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNSCoreReceiveResponse: Can't find question for record name %##s", m->rec.r.resrec.name->c); 668047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AcceptableResponse = mDNSfalse; 668147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 668247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 668347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 668447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 668547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 668647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. Check that this packet resource record does not conflict with any of ours 668747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSOpaque16IsZero(response->h.id) && m->rec.r.resrec.rrtype != kDNSType_NSEC) 668847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 668947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord) 669047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 669147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = m->ResourceRecords; 669247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord) 669347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 669447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr = m->CurrentRecord; 669547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = rr->next; 669647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We accept all multicast responses, and unicast responses resulting from queries we issued 669747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For other unicast responses, this code accepts them only for responses with an 669847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (apparently) local source address that pertain to a record of our own that's in probing state 669947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AcceptableResponse && !(ResponseSrcLocal && rr->resrec.RecordType == kDNSRecordTypeUnique)) continue; 670047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 670147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (PacketRRMatchesSignature(&m->rec.r, rr)) // If interface, name, type (if shared record) and class match... 670247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 670347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // ... check to see if type and rdata are identical 670447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec)) 670547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 670647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us 670747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState) 670847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 670947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we were planning to send on this -- and only this -- interface, then we don't need to any more 671047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; } 671147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 671247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 671347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 671447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ImmedAnswer == mDNSNULL) { rr->ImmedAnswer = InterfaceID; m->NextScheduledResponse = m->timenow; } 671547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; } 671647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 671747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 671847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // else, the packet RR has different type or different rdata -- check to see if this is a conflict 671947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r)) 672047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 672147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r)); 672247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr)); 672347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 672447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this record is marked DependentOn another record for conflict detection purposes, 672547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then *that* record has to be bumped back to probing state to resolve the conflict 672647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->DependentOn) 672747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 672847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (rr->DependentOn) rr = rr->DependentOn; 672947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreReceiveResponse: Dep Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr)); 673047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 673147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 673247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we've just whacked this record's ProbeCount, don't need to do it again 673347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ProbeCount > DefaultProbeCountForTypeUnique) 673447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreReceiveResponse: Already reset to Probing: %s", ARDisplayString(m, rr)); 673547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->ProbeCount == DefaultProbeCountForTypeUnique) 673647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSCoreReceiveResponse: Ignoring response received before we even began probing: %s", ARDisplayString(m, rr)); 673747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 673847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 673947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSCoreReceiveResponse: Received from %#a:%d %s", srcaddr, mDNSVal16(srcport), CRDisplayString(m, &m->rec.r)); 674047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we'd previously verified this record, put it back to probing state and try again 674147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeVerified) 674247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 674347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSCoreReceiveResponse: Resetting to Probing: %s", ARDisplayString(m, rr)); 674447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.RecordType = kDNSRecordTypeUnique; 674547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We set ProbeCount to one more than the usual value so we know we've already touched this record. 674647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This is because our single probe for "example-name.local" could yield a response with (say) two A records and 674747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // three AAAA records in it, and we don't want to call RecordProbeFailure() five times and count that as five conflicts. 674847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This special value is recognised and reset to DefaultProbeCountForTypeUnique in SendQueries(). 674947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ProbeCount = DefaultProbeCountForTypeUnique + 1; 675047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount = InitialAnnounceCount; 675147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeLastAPTime(m, rr); 675247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate 675347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 675447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we're probing for this record, we just failed 675547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->resrec.RecordType == kDNSRecordTypeUnique) 675647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 675747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will deregister %s", rr->ProbeCount, ARDisplayString(m, rr)); 675847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); 675947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 676047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We assumed this record must be unique, but we were wrong. (e.g. There are two mDNSResponders on the 676147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // same machine giving different answers for the reverse mapping record, or there are two machines on the 676247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // network using the same IP address.) This is simply a misconfiguration, and there's nothing we can do 676347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to fix it -- e.g. it's not our job to be trying to change the machine's IP address. We just discard our 676447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // record to avoid continued conflicts (as we do for a conflict on our Unique records) and get on with life. 676547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique) 676647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 676747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m, rr)); 676847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); 676947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 677047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 677147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSCoreReceiveResponse: Unexpected record type %X %s", rr->resrec.RecordType, ARDisplayString(m, rr)); 677247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 677347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 677447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Else, matching signature, different type or rdata, but not a considered a conflict. 677547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the packet record has the cache-flush bit set, then we check to see if we 677647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // have any record(s) of the same type that we should re-assert to rescue them 677747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (see note about "multi-homing and bridged networks" at the end of this function). 677847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype) 677947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2) 678047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; } 678147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 678247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 678347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 678447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 678547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AcceptableResponse) 678647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 678747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const CacheRecord *cr; 678847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (cr = CacheFlushRecords; cr != (CacheRecord*)1; cr = cr->NextInCFList) 678947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 679047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainname *target = GetRRDomainNameTarget(&cr->resrec); 679147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When we issue a query for A record, the response might contain both a CNAME and A records. Only the CNAME would 679247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // match the question and we already created a cache entry in the previous pass of this loop. Now when we process 679347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the A record, it does not match the question because the record name here is the CNAME. Hence we try to 679447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // match with the previous records to make it an AcceptableResponse. We have to be careful about setting the 679547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // DNSServer value that we got in the previous pass. This can happen for other record types like SRV also. 679647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 679747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (target && cr->resrec.rdatahash == m->rec.r.resrec.namehash && SameDomainName(target, m->rec.r.resrec.name)) 679847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 679947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNSCoreReceiveResponse: Found a matching entry for %##s in the CacheFlushRecords", m->rec.r.resrec.name->c); 680047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AcceptableResponse = mDNStrue; 680147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.rDNSServer = uDNSServer; 680247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 680347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 680447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 680547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 680647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 680747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. See if we want to add this packet resource record to our cache 680847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We only try to cache answers if we have a cache to put them in 680947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query 681047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AcceptableResponse) LogInfo("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r)); 681147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rrcache_size && AcceptableResponse) 681247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 681347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = HashSlot(m->rec.r.resrec.name); 681447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec); 681547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr; 681647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 681747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2a. Check if this packet resource record is already in our cache 681847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 681947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 682047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool match = !InterfaceID ? m->rec.r.resrec.rDNSServer == rr->resrec.rDNSServer : rr->resrec.InterfaceID == InterfaceID; 682147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we found this exact resource record, refresh its TTL 682247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (match && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec)) 682347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 682447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rec.r.resrec.rdlength > InlineCacheRDSize) 682547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("Found record size %5d interface %p already in cache: %s", 682647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r)); 682747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 682847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) 682947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 683047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list 683147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList && LLQType != uDNS_LLQ_Events) 683247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; } 683347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 683447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this packet record is marked unique, and our previous cached copy was not, then fix it 683547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)) 683647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 683747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 683847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) if (ResourceRecordAnswersQuestion(&rr->resrec, q)) q->UniqueAnswers++; 683947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.RecordType = m->rec.r.resrec.RecordType; 684047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 684147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 684247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 684347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!SameRDataBody(&m->rec.r.resrec, &rr->resrec.rdata->u, SameDomainNameCS)) 684447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 684547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the rdata of the packet record differs in name capitalization from the record in our cache 684647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get 684747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one. 684847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing 684947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rroriginalttl = 0; 685047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->TimeRcvd = m->timenow; 685147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UnansweredQueries = MaxUnansweredQueries; 685247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextCacheCheckTimeForRecord(m, rr); 685347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("Discarding due to domainname case change old: %s", CRDisplayString(m,rr)); 685447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("Discarding due to domainname case change new: %s", CRDisplayString(m,&m->rec.r)); 685547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("Discarding due to domainname case change in %d slot %3d in %d %d", 685647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NextCacheCheckEvent(rr) - m->timenow, slot, m->rrcache_nextcheck[slot] - m->timenow, m->NextCacheCheck - m->timenow); 685747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // DO NOT break out here -- we want to continue as if we never found it 685847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 685947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (m->rec.r.resrec.rroriginalttl > 0) 686047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 686147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 686247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr)); 686347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl); 686447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 686547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We have to reset the question interval to MaxQuestionInterval so that we don't keep 686647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // polling the network once we get a valid response back. For the first time when a new 686747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // cache entry is created, AnswerCurrentQuestionWithResourceRecord does that. 686847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Subsequently, if we reissue questions from within the mDNSResponder e.g., DNS server 686947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // configuration changed, without flushing the cache, we reset the question interval here. 687047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Currently, we do this for for both multicast and unicast questions as long as the record 687147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // type is unique. For unicast, resource record is always unique and for multicast it is 687247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // true for records like A etc. but not for PTR. 687347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) 687447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 687547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) 687647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 687747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q->DuplicateOf && !q->LongLived && 687847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q)) 687947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 688047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTime = m->timenow; 688147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTxTime = m->timenow; 688247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->RecentAnswerPkts = 0; 688347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval = MaxQuestionInterval; 688447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->RequestUnicast = mDNSfalse; 688547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->unansweredQueries = 0; 688647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNSCoreReceiveResponse: Set MaxQuestionInterval for %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); 688747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; // Why break here? Aren't there other questions we might want to look at?-- SC July 2010 688847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 688947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 689047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 689147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 689247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 689347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 689447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 689547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the packet TTL is zero, that means we're deleting this record. 689647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // To give other hosts on the network a chance to protest, we push the deletion 689747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries. 689847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent 689947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth. 690047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If record's current expiry time is more than a second from now, we set it to expire in one second. 690147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the record is already going to expire in less than one second anyway, we leave it alone -- 690247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we don't want to let the goodbye packet *extend* the record's lifetime in our cache. 690347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("DE for %s", CRDisplayString(m, rr)); 690447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRExpireTime(rr) - m->timenow > mDNSPlatformOneSecond) 690547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 690647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rroriginalttl = 1; 690747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->TimeRcvd = m->timenow; 690847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UnansweredQueries = MaxUnansweredQueries; 690947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextCacheCheckTimeForRecord(m, rr); 691047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 691147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 691247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 691347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 691447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 691547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 691647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If packet resource record not in our cache, add it now 691747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (unless it is just a deletion of a record we never had, in which case we don't care) 691847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rr && m->rec.r.resrec.rroriginalttl > 0) 691947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 692047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSBool AddToCFList = (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && (LLQType != uDNS_LLQ_Events); 692147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSs32 delay = AddToCFList ? NonZeroTime(m->timenow + mDNSPlatformOneSecond) : 692247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CheckForSoonToExpireRecords(m, m->rec.r.resrec.name, m->rec.r.resrec.namehash, slot); 692347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If unique, assume we may have to delay delivery of this 'add' event. 692447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Below, where we walk the CacheFlushRecords list, we either call CacheRecordDeferredAdd() 692547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to immediately to generate answer callbacks, or we call ScheduleNextCacheCheckTime() 692647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to schedule an mDNS_Execute task at the appropriate time. 692747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr = CreateNewCacheEntry(m, slot, cg, delay); 692847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr) 692947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 693047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (AddToCFList) { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; } 693147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->DelayDelivery) ScheduleNextCacheCheckTime(m, slot, rr->DelayDelivery); 693247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 693347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 693447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 693547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 693647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 693747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 693847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit: 693947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 694047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 694147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we've just received one or more records with their cache flush bits set, 694247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then scan that cache slot to see if there are any old stale records we need to flush 694347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (CacheFlushRecords != (CacheRecord*)1) 694447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 694547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *r1 = CacheFlushRecords, *r2; 694647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = HashSlot(r1->resrec.name); 694747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec); 694847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheFlushRecords = CacheFlushRecords->NextInCFList; 694947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r1->NextInCFList = mDNSNULL; 695047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 695147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Look for records in the cache with the same signature as this new one with the cache flush 695247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // bit set, and either (a) if they're fresh, just make sure the whole RRSet has the same TTL 695347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (as required by DNS semantics) or (b) if they're old, mark them for deletion in one second. 695447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We make these TTL adjustments *only* for records that still have *more* than one second 695547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // remaining to live. Otherwise, a record that we tagged for deletion half a second ago 695647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (and now has half a second remaining) could inadvertently get its life extended, by either 695747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (a) if we got an explicit goodbye packet half a second ago, the record would be considered 695847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // "fresh" and would be incorrectly resurrected back to the same TTL as the rest of the RRSet, 695947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // or (b) otherwise, the record would not be fully resurrected, but would be reset to expire 696047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // in one second, thereby inadvertently delaying its actual expiration, instead of hastening it. 696147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this were to happen repeatedly, the record's expiration could be deferred indefinitely. 696247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // To avoid this, we need to ensure that the cache flushing operation will only act to 696347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *decrease* a record's remaining lifetime, never *increase* it. 696447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next) 696547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For Unicast (null InterfaceID) the DNSservers should also match 696647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((r1->resrec.InterfaceID == r2->resrec.InterfaceID) && 696747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (r1->resrec.InterfaceID || (r1->resrec.rDNSServer == r2->resrec.rDNSServer)) && 696847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r1->resrec.rrtype == r2->resrec.rrtype && 696947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r1->resrec.rrclass == r2->resrec.rrclass) 697047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 697147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics) 697247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // else, if record is old, mark it to be flushed 697347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond && RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond) 697447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 697547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we find mismatched TTLs in an RRSet, correct them. 697647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We only do this for records with a TTL of 2 or higher. It's possible to have a 697747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // goodbye announcement with the cache flush bit set (or a case-change on record rdata, 697847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which we treat as a goodbye followed by an addition) and in that case it would be 697947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // inappropriate to synchronize all the other records to a TTL of 0 (or 1). 698047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We suppress the message for the specific case of correcting from 240 to 60 for type TXT, 698147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // because certain early Bonjour devices are known to have this specific mismatch, and 698247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // there's no point filling syslog with messages about something we already know about. 698347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We also don't log this for uDNS responses, since a caching name server is obliged 698447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to give us an aged TTL to correct for how long it has held the record, 698547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so our received TTLs are expected to vary in that case 698647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1) 698747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 698847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!(r2->resrec.rroriginalttl == 240 && r1->resrec.rroriginalttl == 60 && r2->resrec.rrtype == kDNSType_TXT) && 698947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSOpaque16IsZero(response->h.id)) 699047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("Correcting TTL from %4d to %4d for %s", 699147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2)); 699247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->resrec.rroriginalttl = r1->resrec.rroriginalttl; 699347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 699447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->TimeRcvd = m->timenow; 699547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 699647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else // else, if record is old, mark it to be flushed 699747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 699847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("Cache flush new %p age %d expire in %d %s", r1, m->timenow - r1->TimeRcvd, RRExpireTime(r1) - m->timenow, CRDisplayString(m, r1)); 699947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("Cache flush old %p age %d expire in %d %s", r2, m->timenow - r2->TimeRcvd, RRExpireTime(r2) - m->timenow, CRDisplayString(m, r2)); 700047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We set stale records to expire in one second. 700147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This gives the owner a chance to rescue it if necessary. 700247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This is important in the case of multi-homing and bridged networks: 700347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be 700447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit 700547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet 700647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // will promptly delete their cached copies of the (still valid) Ethernet IP address record. 700747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // By delaying the deletion by one second, we give X a change to notice that this bridging has 700847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches. 700947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 701047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary 701147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // final expiration queries for this record. 701247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 701347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache 701447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual 701547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates. 701647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // <rdar://problem/5636422> Updating TXT records is too slow 701747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We check for "rroriginalttl == 1" because we want to include records tagged by the "packet TTL is zero" check above, 701847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which sets rroriginalttl to 1, but not records tagged by the rdata case-change check, which sets rroriginalttl to 0. 701947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2->TimeRcvd == m->timenow && r2->resrec.rroriginalttl == 1 && r2->UnansweredQueries == MaxUnansweredQueries) 702047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 702147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("Cache flush for DE record %s", CRDisplayString(m, r2)); 702247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->resrec.rroriginalttl = 0; 702347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 702447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond) 702547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 702647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We only set a record to expire in one second if it currently has *more* than a second to live 702747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If it's already due to expire in a second or less, we just leave it alone 702847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->resrec.rroriginalttl = 1; 702947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->UnansweredQueries = MaxUnansweredQueries; 703047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->TimeRcvd = m->timenow - 1; 703147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We use (m->timenow - 1) instead of m->timenow, because we use that to identify records 703247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that we marked for deletion via an explicit DE record 703347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 703447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 703547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextCacheCheckTimeForRecord(m, r2); 703647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 703747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 703847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r1->DelayDelivery) // If we were planning to delay delivery of this record, see if we still need to 703947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 704047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot); 704147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If no longer delaying, deliver answer now, else schedule delivery for the appropriate time 704247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1); 704347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else ScheduleNextCacheCheckTime(m, slot, r1->DelayDelivery); 704447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 704547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 704647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 704747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // See if we need to generate negative cache entries for unanswered unicast questions 704847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = response->data; 704947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++) 705047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 705147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion q; 705247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *qptr = mDNSNULL; 705347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = getQuestion(response, ptr, end, InterfaceID, &q); 705447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr))) 705547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 705647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr, *neg = mDNSNULL; 705747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot = HashSlot(&q.qname); 705847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname); 705947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 706047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameNameRecordAnswersQuestion(&rr->resrec, qptr)) 706147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 706247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. If we got a fresh answer to this query, then don't need to generate a negative entry 706347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRExpireTime(rr) - m->timenow > 0) break; 706447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one 706547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = rr; 706647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 706747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft 706847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Active Directory sites) we don't want to waste memory making negative cache entries for all the unicast answers. 706947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Otherwise we just fill up our cache with negative entries for just about every single multicast name we ever look up 707047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (since the Microsoft Active Directory server is going to assert that pretty much every single multicast name doesn't exist). 707147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This is not only a waste of memory, but there's also the problem of those negative entries confusing us later -- e.g. we 707247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // suppress sending our mDNS query packet because we think we already have a valid (negative) answer to that query in our cache. 707347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The one exception is that we *DO* want to make a negative cache entry for "local. SOA", for the (common) case where we're 707447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *not* on a Microsoft Active Directory network, and there is no authoritative server for "local". Note that this is not 707547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // in conflict with the mDNS spec, because that spec says, "Multicast DNS Zones have no SOA record," so it's okay to cache 707647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // negative answers for "local. SOA" from a uDNS server, because the mDNS spec already says that such records do not exist :-) 707747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!InterfaceID && q.qtype != kDNSType_SOA && IsLocalDomain(&q.qname)) 707847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 707947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we did not find a positive answer and we can append search domains to this question, 708047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // generate a negative response (without creating a cache entry) to append search domains. 708147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (qptr->AppendSearchDomains && !rr) 708247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 708347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNSCoreReceiveResponse: Generate negative response for %##s (%s)", q.qname.c, DNSTypeName(q.qtype)); 708447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = qptr; 708547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt GenerateNegativeResponse(m); 708647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 708747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 708847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else LogInfo("mDNSCoreReceiveResponse: Skipping check to see if we need to generate a negative cache entry for %##s (%s)", q.qname.c, DNSTypeName(q.qtype)); 708947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 709047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 709147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 709247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rr) 709347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 709447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We start off assuming a negative caching TTL of 60 seconds 709547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // but then look to see if we can find an SOA authority record to tell us a better value we should be using 709647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 negttl = 60; 709747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int repeat = 0; 709847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainname *name = &q.qname; 709947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 hash = q.qnamehash; 710047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 710147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Special case for our special Microsoft Active Directory "local SOA" check. 710247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Some cheap home gateways don't include an SOA record in the authority section when 710347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // they send negative responses, so we don't know how long to cache the negative result. 710447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Because we don't want to keep hitting the root name servers with our query to find 710547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if we're on a network using Microsoft Active Directory using "local" as a private 710647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // internal top-level domain, we make sure to cache the negative result for at least one day. 710747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q.qtype == kDNSType_SOA && SameDomainName(&q.qname, &localdomain)) negttl = 60 * 60 * 24; 710847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 710947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we're going to make (or update) a negative entry, then look for the appropriate TTL from the SOA record 711047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (response->h.numAuthorities && (ptr = LocateAuthorities(response, end)) != mDNSNULL) 711147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 711247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec); 711347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_SOA) 711447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 711547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const rdataSOA *const soa = (const rdataSOA *)m->rec.r.resrec.rdata->u.data; 711647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 ttl_s = soa->min; 711747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We use the lesser of the SOA.MIN field and the SOA record's TTL, *except* 711847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // for the SOA record for ".", where the record is reported as non-cacheable 711947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (TTL zero) for some reason, so in this case we just take the SOA record's TTL as-is 712047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ttl_s > m->rec.r.resrec.rroriginalttl && m->rec.r.resrec.name->c[0]) 712147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ttl_s = m->rec.r.resrec.rroriginalttl; 712247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (negttl < ttl_s) negttl = ttl_s; 712347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 712447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer, 712547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // with an Authority Section SOA record for d.com, then this is a hint that the authority 712647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // is d.com, and consequently SOA records b.c.d.com and c.d.com don't exist either. 712747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // To do this we set the repeat count so the while loop below will make a series of negative cache entries for us 712847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q.qtype == kDNSType_SOA) 712947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 713047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int qcount = CountLabels(&q.qname); 713147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int scount = CountLabels(m->rec.r.resrec.name); 713247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (qcount - 1 > scount) 713347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameDomainName(SkipLeadingLabels(&q.qname, qcount - scount), m->rec.r.resrec.name)) 713447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt repeat = qcount - 1 - scount; 713547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 713647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 713747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 713847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 713947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 714047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we already had a negative entry in the cache, then we double our existing negative TTL. This is to avoid 714147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the case where the record doesn't exist (e.g. particularly for things like our lb._dns-sd._udp.<domain> query), 714247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and the server returns no SOA record (or an SOA record with a small MIN TTL) so we assume a TTL 714347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // of 60 seconds, and we end up polling the server every minute for a record that doesn't exist. 714447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // With this fix in place, when this happens, we double the effective TTL each time (up to one hour), 714547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so that we back off our polling rate and don't keep hitting the server continually. 714647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (neg) 714747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 714847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (negttl < neg->resrec.rroriginalttl * 2) 714947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt negttl = neg->resrec.rroriginalttl * 2; 715047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (negttl > 3600) 715147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt negttl = 3600; 715247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 715347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 715447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt negttl = GetEffectiveTTL(LLQType, negttl); // Add 25% grace period if necessary 715547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 715647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we already had a negative cache entry just update it, else make one or more new negative cache entries 715747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (neg) 715847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 715947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg)); 716047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RefreshCacheRecord(m, neg, negttl); 716147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 716247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else while (1) 716347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 716447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNSCoreReceiveResponse making negative cache entry TTL %d for %##s (%s)", negttl, name->c, DNSTypeName(q.qtype)); 716547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt MakeNegativeCacheRecord(m, &m->rec.r, name, hash, q.qtype, q.qclass, negttl, mDNSInterface_Any, qptr->qDNSServer); 716647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CreateNewCacheEntry(m, slot, cg, 0); // We never need any delivery delay for these generated negative cache records 716747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 716847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!repeat) break; 716947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt repeat--; 717047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt name = (const domainname *)(name->c + 1 + name->c[0]); 717147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt hash = DomainNameHashValue(name); 717247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt slot = HashSlot(name); 717347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cg = CacheGroupForName(m, slot, hash, name); 717447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 717547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 717647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 717747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 717847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 717947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 718047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 718147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ScheduleWakeup causes all proxy records with WakeUp.HMAC matching mDNSEthAddr 'e' to be deregistered, causing 718247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// multiple wakeup magic packets to be sent if appropriate, and all records to be ultimately freed after a few seconds. 718347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ScheduleWakeup is called on mDNS record conflicts, ARP conflicts, NDP conflicts, or reception of trigger traffic 718447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// that warrants waking the sleeping host. 718547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ScheduleWakeup must be called with the lock held (ScheduleWakeupForList uses mDNS_Deregister_internal) 718647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 718747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ScheduleWakeupForList(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *e, AuthRecord *const thelist) 718847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 718947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We don't need to use the m->CurrentRecord mechanism here because the target HMAC is nonzero, 719047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so all we're doing is marking the record to generate a few wakeup packets 719147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 719247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!e->l[0]) { LogMsg("ScheduleWakeupForList ERROR: Target HMAC is zero"); return; } 719347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = thelist; rr; rr = rr->next) 719447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering && mDNSSameEthAddress(&rr->WakeUp.HMAC, e)) 719547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 719647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("ScheduleWakeupForList: Scheduling wakeup packets for %s", ARDisplayString(m, rr)); 719747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 719847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 719947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 720047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 720147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ScheduleWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *e) 720247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 720347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!e->l[0]) { LogMsg("ScheduleWakeup ERROR: Target HMAC is zero"); return; } 720447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ScheduleWakeupForList(m, InterfaceID, e, m->DuplicateRecords); 720547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ScheduleWakeupForList(m, InterfaceID, e, m->ResourceRecords); 720647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 720747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 720847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SPSRecordCallback(mDNS *const m, AuthRecord *const ar, mStatus result) 720947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 721047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (result && result != mStatus_MemFree) 721147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("SPS Callback %d %s", result, ARDisplayString(m, ar)); 721247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 721347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (result == mStatus_NameConflict) 721447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 721547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 721647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("%-7s Conflicting mDNS -- waking %.6a %s", InterfaceNameForID(m, ar->resrec.InterfaceID), &ar->WakeUp.HMAC, ARDisplayString(m, ar)); 721747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ar->WakeUp.HMAC.l[0]) 721847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 721947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SendWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.IMAC, &ar->WakeUp.password); // Send one wakeup magic packet 722047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ScheduleWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.HMAC); // Schedule all other records with the same owner to be woken 722147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 722247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 722347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 722447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 722547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (result == mStatus_NameConflict || result == mStatus_MemFree) 722647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 722747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ProxyRecords--; 722847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemFree(ar); 722947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_UpdateAllowSleep(m); 723047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 723147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 723247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 723347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m, 723447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const DNSMessage *const msg, const mDNSu8 *end, 723547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, 723647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSInterfaceID InterfaceID) 723747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 723847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 723947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord opt; 724047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *p = m->omsg.data; 724147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt OwnerOptData owner = zeroOwner; // Need to zero this, so we'll know if this Update packet was missing its Owner option 724247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 updatelease = 0; 724347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *ptr; 724447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 724547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("Received Update from %#-15a:%-5d to %#-15a:%-5d on 0x%p with " 724647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes", 724747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID, 724847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", 724947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", 725047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,", 725147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numAdditionals, msg->h.numAdditionals == 1 ? " " : "s", end - msg->data); 725247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 725347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!InterfaceID || !m->SPSSocket || !mDNSSameIPPort(dstport, m->SPSSocket->port)) return; 725447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 725547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNS_PacketLoggingEnabled) 725647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DumpPacket(m, mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end); 725747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 725847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space + DNSOpt_OwnerData_ID_Space); 725947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ptr) 726047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 726147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); 726247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT) 726347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 726447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const rdataOPT *o; 726547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength]; 726647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++) 726747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 726847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (o->opt == kDNSOpt_Lease) updatelease = o->u.updatelease; 726947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (o->opt == kDNSOpt_Owner && o->u.owner.vers == 0) owner = o->u.owner; 727047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 727147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 727247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 727347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 727447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 727547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeDNSMessage(&m->omsg.h, msg->h.id, UpdateRespFlags); 727647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 727747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!updatelease || !owner.HMAC.l[0]) 727847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 727947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static int msgs = 0; 728047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (msgs < 100) 728147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 728247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msgs++; 728347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Refusing sleep proxy registration from %#a:%d:%s%s", srcaddr, mDNSVal16(srcport), 728447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !updatelease ? " No lease" : "", !owner.HMAC.l[0] ? " No owner" : ""); 728547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 728647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.flags.b[1] |= kDNSFlag1_RC_FormErr; 728747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 728847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (m->ProxyRecords + msg->h.mDNS_numUpdates > MAX_PROXY_RECORDS) 728947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 729047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static int msgs = 0; 729147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (msgs < 100) 729247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 729347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msgs++; 729447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Refusing sleep proxy registration from %#a:%d: Too many records %d + %d = %d > %d", srcaddr, mDNSVal16(srcport), 729547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ProxyRecords, msg->h.mDNS_numUpdates, m->ProxyRecords + msg->h.mDNS_numUpdates, MAX_PROXY_RECORDS); 729647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 729747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused; 729847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 729947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 730047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 730147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("Received Update for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq); 730247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 730347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (updatelease > 24 * 60 * 60) 730447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt updatelease = 24 * 60 * 60; 730547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 730647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (updatelease > 0x40000000UL / mDNSPlatformOneSecond) 730747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt updatelease = 0x40000000UL / mDNSPlatformOneSecond; 730847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 730947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = LocateAuthorities(msg, end); 731047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i = 0; i < msg->h.mDNS_numUpdates && ptr && ptr < end; i++) 731147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 731247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec); 731347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative) 731447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 731547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu16 RDLengthMem = GetRDLengthMem(&m->rec.r.resrec); 731647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *ar = mDNSPlatformMemAllocate(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem); 731747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ar) { m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused; break; } 731847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 731947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 732047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 RecordType = m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask ? kDNSRecordTypeUnique : kDNSRecordTypeShared; 732147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.rrclass &= ~kDNSClass_UniqueRRSet; 732247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ClearIdenticalProxyRecords(m, &owner, m->DuplicateRecords); // Make sure we don't have any old stale duplicates of this record 732347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ClearIdenticalProxyRecords(m, &owner, m->ResourceRecords); 732447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(ar, mDNSNULL, InterfaceID, m->rec.r.resrec.rrtype, m->rec.r.resrec.rroriginalttl, RecordType, AuthRecordAny, SPSRecordCallback, ar); 732547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&ar->namestorage, m->rec.r.resrec.name); 732647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->resrec.rdlength = GetRDLength(&m->rec.r.resrec, mDNSfalse); 732747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->resrec.rdata->MaxRDLength = RDLengthMem; 732847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemCopy(ar->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, RDLengthMem); 732947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->ForceMCast = mDNStrue; 733047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->WakeUp = owner; 733147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rec.r.resrec.rrtype == kDNSType_PTR) 733247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 733347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 t = ReverseMapDomainType(m->rec.r.resrec.name); 733447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (t == mDNSAddrType_IPv4) GetIPv4FromName(&ar->AddressProxy, m->rec.r.resrec.name); 733547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (t == mDNSAddrType_IPv6) GetIPv6FromName(&ar->AddressProxy, m->rec.r.resrec.name); 733647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNSCoreReceiveUpdate: PTR %d %d %#a %s", t, ar->AddressProxy.type, &ar->AddressProxy, ARDisplayString(m, ar)); 733747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ar->AddressProxy.type) SetSPSProxyListChanged(InterfaceID); 733847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 733947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->TimeRcvd = m->timenow; 734047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ar->TimeExpire = m->timenow + updatelease * mDNSPlatformOneSecond; 734147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextScheduledSPS - ar->TimeExpire > 0) 734247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledSPS = ar->TimeExpire; 734347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Register_internal(m, ar); 734447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Unsolicited Neighbor Advertisements (RFC 2461 Section 7.2.6) give us fast address cache updating, 734547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // but some older IPv6 clients get confused by them, so for now we don't send them. Without Unsolicited 734647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Neighbor Advertisements we have to rely on Neighbor Unreachability Detection instead, which is slower. 734747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Given this, we'll do our best to wake for existing IPv6 connections, but we don't want to encourage 734847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // new ones for sleeping clients, so we'll we send deletions for our SPS clients' AAAA records. 734947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->KnownBugs & mDNS_KnownBug_LimitedIPv6) 735047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ar->resrec.rrtype == kDNSType_AAAA) ar->resrec.rroriginalttl = 0; 735147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ProxyRecords++; 735247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_UpdateAllowSleep(m); 735347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("SPS Registered %4d %X %s", m->ProxyRecords, RecordType, ARDisplayString(m,ar)); 735447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 735547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 735647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 735747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 735847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 735947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->omsg.h.flags.b[1] & kDNSFlag1_RC_Mask) 736047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 736147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Refusing sleep proxy registration from %#a:%d: Out of memory", srcaddr, mDNSVal16(srcport)); 736247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ClearProxyRecords(m, &owner, m->DuplicateRecords); 736347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ClearProxyRecords(m, &owner, m->ResourceRecords); 736447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 736547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 736647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 736747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); 736847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rrclass = NormalMaxDNSMessageData; 736947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record 737047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdestimate = sizeof(rdataOPT); 737147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; 737247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt opt.resrec.rdata->u.opt[0].u.updatelease = updatelease; 737347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData); 737447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 737547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 737647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 737747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (p) mDNSSendDNSMessage(m, &m->omsg, p, InterfaceID, m->SPSSocket, srcaddr, srcport, mDNSNULL, mDNSNULL); 737847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 737947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 738047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end, const mDNSInterfaceID InterfaceID) 738147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 738247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (InterfaceID) 738347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 738447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 updatelease = 60 * 60; // If SPS fails to indicate lease time, assume one hour 738547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space); 738647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ptr) 738747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 738847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); 738947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT) 739047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 739147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const rdataOPT *o; 739247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength]; 739347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++) 739447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (o->opt == kDNSOpt_Lease) 739547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 739647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt updatelease = o->u.updatelease; 739747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("Sleep Proxy granted lease time %4d seconds", updatelease); 739847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 739947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 740047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 740147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 740247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 740347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord) 740447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNSCoreReceiveUpdateR ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 740547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = m->ResourceRecords; 740647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord) 740747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 740847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *const rr = m->CurrentRecord; 740947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID == InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name)))) 741047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameOpaque16(rr->updateid, msg->h.id)) 741147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 741247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->updateid = zeroID; 741347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->expire = NonZeroTime(m->timenow + updatelease * mDNSPlatformOneSecond); 741447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("Sleep Proxy %s record %5d %s", rr->WakeUp.HMAC.l[0] ? "transferred" : "registered", updatelease, ARDisplayString(m,rr)); 741547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->WakeUp.HMAC.l[0]) 741647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 741747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->WakeUp.HMAC = zeroEthAddr; // Clear HMAC so that mDNS_Deregister_internal doesn't waste packets trying to wake this host 741847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->RequireGoodbye = mDNSfalse; // and we don't want to send goodbye for it 741947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 742047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 742147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 742247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because 742347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // new records could have been added to the end of the list as a result of that call. 742447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now 742547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = rr->next; 742647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 742747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 742847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we were waiting to go to sleep, then this SPS registration or wide-area record deletion 742947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // may have been the thing we were waiting for, so schedule another check to see if we can sleep now. 743047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SleepLimit) m->NextScheduledSPRetry = m->timenow; 743147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 743247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 743347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr, 743447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID, DNSServer *dnsserver) 743547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 743647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr == &m->rec.r && m->rec.r.resrec.RecordType) 743747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 743847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("MakeNegativeCacheRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r)); 743947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ForceAlerts 744047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *(long*)0 = 0; 744147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 744247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 744347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 744447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Create empty resource record 744547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.RecordType = kDNSRecordTypePacketNegative; 744647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.InterfaceID = InterfaceID; 744747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rDNSServer = dnsserver; 744847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.name = name; // Will be updated to point to cg->name when we call CreateNewCacheEntry 744947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rrtype = rrtype; 745047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rrclass = rrclass; 745147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rroriginalttl = ttl_seconds; 745247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rdlength = 0; 745347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rdestimate = 0; 745447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.namehash = namehash; 745547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rdatahash = 0; 745647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rdata = (RData*)&cr->smallrdatastorage; 745747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rdata->MaxRDLength = 0; 745847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 745947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->NextInKAList = mDNSNULL; 746047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->TimeRcvd = m->timenow; 746147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->DelayDelivery = 0; 746247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->NextRequiredQuery = m->timenow; 746347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->LastUsed = m->timenow; 746447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->CRActiveQuestion = mDNSNULL; 746547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->UnansweredQueries = 0; 746647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->LastUnansweredTime = 0; 746747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 746847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->MPUnansweredQ = 0; 746947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->MPLastUnansweredQT = 0; 747047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->MPUnansweredKA = 0; 747147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->MPExpectingKA = mDNSfalse; 747247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 747347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->NextInCFList = mDNSNULL; 747447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 747547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 747647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end, 747747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, 747847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSInterfaceID InterfaceID) 747947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 748047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSInterfaceID ifid = InterfaceID; 748147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSMessage *msg = (DNSMessage *)pkt; 748247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 StdQ = kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery; 748347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery; 748447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 UpdQ = kDNSFlag0_QR_Query | kDNSFlag0_OP_Update; 748547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 UpdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update; 748647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 QR_OP; 748747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *ptr = mDNSNULL; 748847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool TLS = (dstaddr == (mDNSAddr *)1); // For debug logs: dstaddr = 0 means TCP; dstaddr = 1 means TLS 748947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (TLS) dstaddr = mDNSNULL; 749047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 749147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 749247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameAddress(srcaddr, &m->Router)) 749347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 749447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifdef _LEGACY_NAT_TRAVERSAL_ 749547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameIPPort(srcport, SSDPPort) || (m->SSDPSocket && mDNSSameIPPort(dstport, m->SSDPSocket->port))) 749647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 749747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 749847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LNT_ConfigureRouterInfo(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt)); 749947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 750047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 750147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 750247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 750347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameIPPort(srcport, NATPMPPort)) 750447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 750547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 750647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uDNS_ReceiveNATPMPPacket(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt)); 750747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 750847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 750947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 751047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 751147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifdef _LEGACY_NAT_TRAVERSAL_ 751247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (m->SSDPSocket && mDNSSameIPPort(dstport, m->SSDPSocket->port)) { debugf("Ignoring SSDP response from %#a:%d", srcaddr, mDNSVal16(srcport)); return; } 751347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 751447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 751547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 751647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) 751747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 751847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("DNS Message from %#a:%d to %#a:%d length %d too short", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt); 751947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 752047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 752147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask); 752247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Read the integer parts which are in IETF byte-order (MSB first, LSB second) 752347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = (mDNSu8 *)&msg->h.numQuestions; 752447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 752547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); 752647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]); 752747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]); 752847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 752947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; } 753047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 753147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address" 753247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we accept and try to process a packet with zero or all-ones source address, that could really mess things up 753347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (srcaddr && !mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; } 753447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 753547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 753647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->PktNum++; 753747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 753847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!dstaddr || (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdR))) 753947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(msg->h.id)) // uDNS_ReceiveMsg only needs to get real uDNS responses, not "QU" mDNS responses 754047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 754147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ifid = mDNSInterface_Any; 754247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNS_PacketLoggingEnabled) 754347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DumpPacket(m, mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end); 754447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport); 754547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: mDNSCore also needs to get access to received unicast responses 754647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 754747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 754847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (QR_OP == StdQ) mDNSCoreReceiveQuery (m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid); 754947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid); 755047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (QR_OP == UpdQ) mDNSCoreReceiveUpdate (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID); 755147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (QR_OP == UpdR) mDNSCoreReceiveUpdateR (m, msg, end, InterfaceID); 755247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 755347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 755447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d length %d on %p (ignored)", 755547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt, InterfaceID); 755647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNS_LoggingEnabled) 755747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 755847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i = 0; 755947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (i<end - (mDNSu8 *)pkt) 756047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 756147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char buffer[128]; 756247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char *p = buffer + mDNS_snprintf(buffer, sizeof(buffer), "%04X", i); 756347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt do if (i<end - (mDNSu8 *)pkt) p += mDNS_snprintf(p, sizeof(buffer), " %02X", ((mDNSu8 *)pkt)[i]); while (++i & 15); 756447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("%s", buffer); 756547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 756647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 756747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 756847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Packet reception often causes a change to the task list: 756947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. Inbound queries can cause us to need to send responses 757047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses 757147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3. Other hosts announcing deletion of shared records can cause us to need to re-assert those records 757247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 4. Response packets that answer questions may cause our client to issue new questions 757347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 757447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 757547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 757647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// *************************************************************************** 757747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK 757847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - 757947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Searcher Functions 758047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 758147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 758247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Targets are considered the same if both queries are untargeted, or 758347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// if both are targeted to the same address+port 758447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (If Target address is zero, TargetPort is undefined) 758547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \ 758647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (mDNSSameAddress(&(A)->Target, &(B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort))) 758747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 758847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the 758947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV" 759047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails 759147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// doing a standard DNS query for the _dns-query-tls._tcp SRV record for company.com. If we make the latter (public) query 759247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// a duplicate of the former (private) query, then it will block forever waiting for an answer that will never come. 759347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 759447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// We keep SuppressUnusable questions separate so that we can return a quick response to them and not get blocked behind 759547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// the queries that are not marked SuppressUnusable. But if the query is not suppressed, they are treated the same as 759647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// non-SuppressUnusable questions. This should be fine as the goal of SuppressUnusable is to return quickly only if it 759747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// is suppressed. If it is not suppressed, we do try all the DNS servers for valid answers like any other question. 759847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The main reason for this design is that cache entries point to a *single* question and that question is responsible 759947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// for keeping the cache fresh as long as it is active. Having multiple active question for a single cache entry 760047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// breaks this design principle. 760147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 760247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If IsLLQ(Q) is true, it means the question is both: 760347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (a) long-lived and 760447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (b) being performed by a unicast DNS long-lived query (either full LLQ, or polling) 760547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// for multicast questions, we don't want to treat LongLived as anything special 760647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define IsLLQ(Q) ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID)) 760747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 760847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question) 760947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 761047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 761147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list. 761247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This prevents circular references, where two questions are each marked as a duplicate of the other. 761347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Accordingly, we break out of the loop when we get to 'question', because there's no point searching 761447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // further in the list. 761547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q && q != question; q=q->next) // Scan our list for another question 761647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->InterfaceID == question->InterfaceID && // with the same InterfaceID, 761747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameQTarget(q, question) && // and same unicast/multicast target settings 761847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qtype == question->qtype && // type, 761947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qclass == question->qclass && // class, 762047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt IsLLQ(q) == IsLLQ(question) && // and long-lived status matches 762147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (!q->AuthInfo || question->AuthInfo) && // to avoid deadlock, don't make public query dup of a private one 762247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (q->SuppressQuery == question->SuppressQuery) && // Questions that are suppressed/not suppressed 762347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qnamehash == question->qnamehash && 762447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameDomainName(&q->qname, &question->qname)) // and name 762547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(q); 762647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSNULL); 762747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 762847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 762947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// This is called after a question is deleted, in case other identical questions were being suppressed as duplicates 763047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const question) 763147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 763247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 763347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *first = mDNSNULL; 763447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 763547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This is referring to some other question as duplicate. No other question can refer to this 763647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // question as a duplicate. 763747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->DuplicateOf) 763847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 763947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("UpdateQuestionDuplicates: question %p %##s (%s) duplicate of %p %##s (%s)", 764047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question, question->qname.c, DNSTypeName(question->qtype), 764147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->DuplicateOf, question->DuplicateOf->qname.c, DNSTypeName(question->DuplicateOf->qtype)); 764247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 764347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 764447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 764547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) // Scan our list of questions 764647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->DuplicateOf == question) // To see if any questions were referencing this as their duplicate 764747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 764847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->DuplicateOf = first; 764947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!first) 765047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 765147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt first = q; 765247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If q used to be a duplicate, but now is not, 765347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then inherit the state from the question that's going away 765447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTime = question->LastQTime; 765547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval = question->ThisQInterval; 765647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ExpectUnicastResp = question->ExpectUnicastResp; 765747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastAnswerPktNum = question->LastAnswerPktNum; 765847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->RecentAnswerPkts = question->RecentAnswerPkts; 765947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->RequestUnicast = question->RequestUnicast; 766047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTxTime = question->LastQTxTime; 766147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->CNAMEReferrals = question->CNAMEReferrals; 766247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->nta = question->nta; 766347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->servAddr = question->servAddr; 766447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->servPort = question->servPort; 766547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qDNSServer = question->qDNSServer; 766647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->validDNSServers = question->validDNSServers; 766747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->unansweredQueries = question->unansweredQueries; 766847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->noServerResponse = question->noServerResponse; 766947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->triedAllServersOnce = question->triedAllServersOnce; 767047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 767147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->TargetQID = question->TargetQID; 767247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LocalSocket = question->LocalSocket; 767347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 767447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->state = question->state; 767547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // q->tcp = question->tcp; 767647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ReqLease = question->ReqLease; 767747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->expire = question->expire; 767847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ntries = question->ntries; 767947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->id = question->id; 768047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 768147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->LocalSocket = mDNSNULL; 768247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->nta = mDNSNULL; // If we've got a GetZoneData in progress, transfer it to the newly active question 768347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // question->tcp = mDNSNULL; 768447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 768547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->LocalSocket) 768647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 768747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 768847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->nta) 768947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 769047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 769147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->nta->ZoneDataContext = q; 769247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 769347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 769447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Need to work out how to safely transfer this state too -- appropriate context pointers need to be updated or the code will crash 769547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->tcp) LogInfo("UpdateQuestionDuplicates did not transfer tcp pointer"); 769647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 769747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->state == LLQ_Established) 769847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 769947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("UpdateQuestionDuplicates transferred LLQ state for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 770047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->state = 0; // Must zero question->state, or mDNS_StopQuery_internal will clean up and cancel our LLQ from the server 770147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 770247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 770347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextQueryTime(m,q); 770447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 770547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 770647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 770747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 770847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, mDNSu32 timeout) 770947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 771047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt McastResolver **p = &m->McastResolvers; 771147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt McastResolver *tmp = mDNSNULL; 771247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 771347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!d) d = (const domainname *)""; 771447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 771547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_AddMcastResolver: Adding %##s, InterfaceID %p, timeout %u", d->c, interface, timeout); 771647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 771747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->mDNS_busy != m->mDNS_reentrancy+1) 771847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_AddMcastResolver: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); 771947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 772047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*p) // Check if we already have this {interface, domain} tuple registered 772147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 772247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((*p)->interface == interface && SameDomainName(&(*p)->domain, d)) 772347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 772447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!((*p)->flags & DNSServer_FlagDelete)) LogMsg("Note: Mcast Resolver domain %##s (%p) registered more than once", d->c, interface); 772547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (*p)->flags &= ~DNSServer_FlagDelete; 772647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt tmp = *p; 772747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *p = tmp->next; 772847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt tmp->next = mDNSNULL; 772947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 773047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 773147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt p=&(*p)->next; 773247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 773347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 773447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (tmp) *p = tmp; // move to end of list, to ensure ordering from platform layer 773547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 773647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 773747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // allocate, add to list 773847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *p = mDNSPlatformMemAllocate(sizeof(**p)); 773947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!*p) LogMsg("mDNS_AddMcastResolver: ERROR!! - malloc"); 774047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 774147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 774247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (*p)->interface = interface; 774347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (*p)->flags = DNSServer_FlagNew; 774447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (*p)->timeout = timeout; 774547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&(*p)->domain, d); 774647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (*p)->next = mDNSNULL; 774747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 774847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 774947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(*p); 775047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 775147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 775247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSinline mDNSs32 PenaltyTimeForServer(mDNS *m, DNSServer *server) 775347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 775447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 ptime = 0; 775547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (server->penaltyTime != 0) 775647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 775747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptime = server->penaltyTime - m->timenow; 775847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ptime < 0) 775947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 776047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This should always be a positive value between 0 and DNSSERVER_PENALTY_TIME 776147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If it does not get reset in ResetDNSServerPenalties for some reason, we do it 776247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // here 776347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("PenaltyTimeForServer: PenaltyTime negative %d, (server penaltyTime %d, timenow %d) resetting the penalty", 776447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptime, server->penaltyTime, m->timenow); 776547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt server->penaltyTime = 0; 776647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptime = 0; 776747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 776847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 776947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return ptime; 777047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 777147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 777247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//Checks to see whether the newname is a better match for the name, given the best one we have 777347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//seen so far (given in bestcount). 777447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//Returns -1 if the newname is not a better match 777547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//Returns 0 if the newname is the same as the old match 777647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//Returns 1 if the newname is a better match 777747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int BetterMatchForName(const domainname *name, int namecount, const domainname *newname, int newcount, 777847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int bestcount) 777947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 778047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the name contains fewer labels than the new server's domain or the new name 778147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // contains fewer labels than the current best, then it can't possibly be a better match 778247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (namecount < newcount || newcount < bestcount) return -1; 778347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 778447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If there is no match, return -1 and the caller will skip this newname for 778547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // selection 778647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 778747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we find a match and the number of labels is the same as bestcount, then 778847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we return 0 so that the caller can do additional logic to pick one of 778947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the best based on some other factors e.g., penaltyTime 779047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 779147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we find a match and the number of labels is more than bestcount, then we 779247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // return 1 so that the caller can pick this over the old one. 779347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 779447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: newcount can either be equal or greater than bestcount beause of the 779547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // check above. 779647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 779747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameDomainName(SkipLeadingLabels(name, namecount - newcount), newname)) 779847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return bestcount == newcount ? 0 : 1; 779947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 780047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return -1; 780147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 780247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 780347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Normally, we have McastResolvers for .local, in-addr.arpa and ip6.arpa. But there 780447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// can be queries that can forced to multicast (ForceMCast) even though they don't end in these 780547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// names. In that case, we give a default timeout of 5 seconds 780647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define DEFAULT_MCAST_TIMEOUT 5 780747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu32 GetTimeoutForMcastQuestion(mDNS *m, DNSQuestion *question) 780847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 780947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt McastResolver *curmatch = mDNSNULL; 781047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int bestmatchlen = -1, namecount = CountLabels(&question->qname); 781147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt McastResolver *curr; 781247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int bettermatch, currcount; 781347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (curr = m->McastResolvers; curr; curr = curr->next) 781447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 781547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt currcount = CountLabels(&curr->domain); 781647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen); 781747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Take the first best match. If there are multiple equally good matches (bettermatch = 0), we take 781847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the timeout value from the first one 781947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (bettermatch == 1) 782047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 782147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt curmatch = curr; 782247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt bestmatchlen = currcount; 782347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 782447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 782547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("GetTimeoutForMcastQuestion: question %##s curmatch %p, Timeout %d", question->qname.c, curmatch, 782647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt curmatch ? curmatch->timeout : DEFAULT_MCAST_TIMEOUT); 782747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return ( curmatch ? curmatch->timeout : DEFAULT_MCAST_TIMEOUT); 782847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 782947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 783047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Sets all the Valid DNS servers for a question 783147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question) 783247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 783347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSServer *curmatch = mDNSNULL; 783447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int bestmatchlen = -1, namecount = CountLabels(&question->qname); 783547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSServer *curr; 783647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int bettermatch, currcount; 783747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int index = 0; 783847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 timeout = 0; 783947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 784047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->validDNSServers = zeroOpaque64; 784147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (curr = m->DNSServers; curr; curr = curr->next) 784247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 784347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("SetValidDNSServers: Parsing DNS server Address %#a (Domain %##s), Scope: %d", &curr->addr, curr->domain.c, curr->scoped); 784447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // skip servers that will soon be deleted 784547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (curr->flags & DNSServer_FlagDelete) 784647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { debugf("SetValidDNSServers: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scoped); continue; } 784747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 784847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This happens normally when you unplug the interface where we reset the interfaceID to mDNSInterface_Any for all 784947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the DNS servers whose scope match the interfaceID. Few seconds later, we also receive the updated DNS configuration. 785047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // But any questions that has mDNSInterface_Any scope that are started/restarted before we receive the update 785147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (e.g., CheckSuppressUnusableQuestions is called when interfaces are deregistered with the core) should not 785247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // match the scoped entries by mistake. 785347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 785447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: DNS configuration change will help pick the new dns servers but currently it does not affect the timeout 785547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 785647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (curr->scoped && curr->interface == mDNSInterface_Any) 785747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { debugf("SetValidDNSServers: Scoped DNS server %#a (Domain %##s) with Interface Any", &curr->addr, curr->domain.c); continue; } 785847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 785947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt currcount = CountLabels(&curr->domain); 786047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((!curr->scoped && (!question->InterfaceID || (question->InterfaceID == mDNSInterface_Unicast))) || (curr->interface == question->InterfaceID)) 786147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 786247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen); 786347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 786447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we found a better match (bettermatch == 1) then clear all the bits 786547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // corresponding to the old DNSServers that we have may set before and start fresh. 786647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we find an equal match, then include that DNSServer also by setting the corresponding 786747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // bit 786847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((bettermatch == 1) || (bettermatch == 0)) 786947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 787047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt curmatch = curr; 787147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt bestmatchlen = currcount; 787247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (bettermatch) { debugf("SetValidDNSServers: Resetting all the bits"); question->validDNSServers = zeroOpaque64; timeout = 0; } 787347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("SetValidDNSServers: question %##s Setting the bit for DNS server Address %#a (Domain %##s), Scoped:%d index %d," 787447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt " Timeout %d, interface %p", question->qname.c, &curr->addr, curr->domain.c, curr->scoped, index, curr->timeout, 787547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt curr->interface); 787647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt timeout += curr->timeout; 787747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt bit_set_opaque64(question->validDNSServers, index); 787847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 787947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 788047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt index++; 788147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 788247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->noServerResponse = 0; 788347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 788447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("SetValidDNSServers: ValidDNSServer bits 0x%x%x for question %p %##s (%s)", 788547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->validDNSServers.l[1], question->validDNSServers.l[0], question, question->qname.c, DNSTypeName(question->qtype)); 788647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If there are no matching resolvers, then use the default value to timeout 788747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return (timeout ? timeout : DEFAULT_UDNS_TIMEOUT); 788847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 788947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 789047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Get the Best server that matches a name. If you find penalized servers, look for the one 789147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// that will come out of the penalty box soon 789247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal DNSServer *GetBestServer(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID, mDNSOpaque64 validBits, int *selected, mDNSBool nameMatch) 789347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 789447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSServer *curmatch = mDNSNULL; 789547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int bestmatchlen = -1, namecount = name ? CountLabels(name) : 0; 789647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSServer *curr; 789747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 bestPenaltyTime, currPenaltyTime; 789847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int bettermatch, currcount; 789947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int index = 0; 790047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int currindex = -1; 790147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 790247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("GetBestServer: ValidDNSServer bits 0x%x%x", validBits.l[1], validBits.l[0]); 790347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt bestPenaltyTime = DNSSERVER_PENALTY_TIME + 1; 790447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (curr = m->DNSServers; curr; curr = curr->next) 790547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 790647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // skip servers that will soon be deleted 790747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (curr->flags & DNSServer_FlagDelete) 790847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { debugf("GetBestServer: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scoped); continue; } 790947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 791047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Check if this is a valid DNSServer 791147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!bit_get_opaque64(validBits, index)) { debugf("GetBestServer: continuing for index %d", index); index++; continue; } 791247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 791347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt currcount = CountLabels(&curr->domain); 791447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt currPenaltyTime = PenaltyTimeForServer(m, curr); 791547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 791647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("GetBestServer: Address %#a (Domain %##s), PenaltyTime(abs) %d, PenaltyTime(rel) %d", 791747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt &curr->addr, curr->domain.c, curr->penaltyTime, currPenaltyTime); 791847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 791947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If there are multiple best servers for a given question, we will pick the first one 792047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if none of them are penalized. If some of them are penalized in that list, we pick 792147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the least penalized one. BetterMatchForName walks through all best matches and 792247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // "currPenaltyTime < bestPenaltyTime" check lets us either pick the first best server 792347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // in the list when there are no penalized servers and least one among them 792447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // when there are some penalized servers 792547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 792647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Notes on InterfaceID matching: 792747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 792847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1) A DNSServer entry may have an InterfaceID but the scoped flag may not be set. This 792947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // is the old way of specifying an InterfaceID option for DNSServer. We recoginize these 793047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // entries by "scoped" being false. These are like any other unscoped entries except that 793147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if it is picked e.g., domain match, when the packet is sent out later, the packet will 793247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // be sent out on that interface. Theese entries can be matched by either specifying a 793347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // zero InterfaceID or non-zero InterfaceID on the question. Specifying an InterfaceID on 793447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the question will cause an extra check on matching the InterfaceID on the question 793547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // against the DNSServer. 793647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 793747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2) A DNSServer may also have both scoped set and InterfaceID non-NULL. This 793847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // is the new way of specifying an InterfaceID option for DNSServer. These will be considered 793947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // only when the question has non-zero interfaceID. 794047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 794147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((!curr->scoped && !InterfaceID) || (curr->interface == InterfaceID)) 794247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 794347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 794447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we know that all the names are already equally good matches, then skip calling BetterMatchForName. 794547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This happens when we initially walk all the DNS servers and set the validity bit on the question. 794647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Actually we just need PenaltyTime match, but for the sake of readability we just skip the expensive 794747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // part and still do some redundant steps e.g., InterfaceID match 794847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 794947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (nameMatch) bettermatch = BetterMatchForName(name, namecount, &curr->domain, currcount, bestmatchlen); 795047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else bettermatch = 0; 795147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 795247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we found a better match (bettermatch == 1) then we don't need to 795347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // compare penalty times. But if we found an equal match, then we compare 795447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the penalty times to pick a better match 795547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 795647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((bettermatch == 1) || ((bettermatch == 0) && currPenaltyTime < bestPenaltyTime)) 795747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { currindex = index; curmatch = curr; bestmatchlen = currcount; bestPenaltyTime = currPenaltyTime; } 795847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 795947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt index++; 796047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 796147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (selected) *selected = currindex; 796247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return curmatch; 796347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 796447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 796547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Look up a DNS Server, matching by name and InterfaceID 796647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID) 796747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 796847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSServer *curmatch = mDNSNULL; 796947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char *ifname = mDNSNULL; // for logging purposes only 797047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSOpaque64 allValid; 797147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 797247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly)) 797347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InterfaceID = mDNSNULL; 797447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 797547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID); 797647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 797747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // By passing in all ones, we make sure that every DNS server is considered 797847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt allValid.l[0] = allValid.l[1] = 0xFFFFFFFF; 797947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 798047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt curmatch = GetBestServer(m, name, InterfaceID, allValid, mDNSNULL, mDNStrue); 798147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 798247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (curmatch != mDNSNULL) 798347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("GetServerForName: DNS server %#a:%d (Penalty Time Left %d) (Scope %s:%p) found for name %##s", &curmatch->addr, 798447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0), ifname ? ifname : "None", 798547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InterfaceID, name); 798647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 798747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("GetServerForName: no DNS server (Scope %s:%p) found for name %##s", ifname ? ifname : "None", InterfaceID, name); 798847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 798947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(curmatch); 799047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 799147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 799247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Look up a DNS Server for a question within its valid DNSServer bits 799347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question) 799447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 799547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSServer *curmatch = mDNSNULL; 799647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char *ifname = mDNSNULL; // for logging purposes only 799747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSInterfaceID InterfaceID = question->InterfaceID; 799847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainname *name = &question->qname; 799947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int currindex; 800047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 800147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly)) 800247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InterfaceID = mDNSNULL; 800347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 800447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID); 800547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 800647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque64IsZero(&question->validDNSServers)) 800747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 800847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt curmatch = GetBestServer(m, name, InterfaceID, question->validDNSServers, &currindex, mDNSfalse); 800947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (currindex != -1) bit_clr_opaque64(question->validDNSServers, currindex); 801047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 801147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 801247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (curmatch != mDNSNULL) 801347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("GetServerForQuestion: %p DNS server %#a:%d (Penalty Time Left %d) (Scope %s:%p) found for name %##s (%s)", question, &curmatch->addr, 801447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0), ifname ? ifname : "None", 801547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InterfaceID, name, DNSTypeName(question->qtype)); 801647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 801747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("GetServerForQuestion: %p no DNS server (Scope %s:%p) found for name %##s (%s)", question, ifname ? ifname : "None", InterfaceID, name, DNSTypeName(question->qtype)); 801847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 801947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(curmatch); 802047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 802147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 802247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 802347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \ 802447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort))) 802547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 802647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Called in normal client context (lock not held) 802747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n) 802847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 802947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 803047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (void)n; // Unused 803147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 803247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("LLQNATCallback external address:port %.4a:%u, NAT result %d", &n->ExternalAddress, mDNSVal16(n->ExternalPort), n->Result); 803347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) 803447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived) 803547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt startLLQHandshake(m, q); // If ExternalPort is zero, will do StartLLQPolling instead 803647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder 803747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt UpdateAutoTunnelDomainStatuses(m); 803847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 803947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 804047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 804147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 804247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool ShouldSuppressQuery(mDNS *const m, domainname *qname, mDNSu16 qtype, mDNSInterfaceID InterfaceID) 804347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 804447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *i; 804547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 iptype; 804647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DomainAuthInfo *AuthInfo; 804747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 804847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (qtype == kDNSType_A) iptype = mDNSAddrType_IPv4; 804947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (qtype == kDNSType_AAAA) iptype = mDNSAddrType_IPv6; 805047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else { LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, not A/AAAA type", qname, DNSTypeName(qtype)); return mDNSfalse; } 805147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 805247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We still want the ability to be able to listen to the local services and hence 805347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // don't fail .local requests. We always have a loopback interface which we don't 805447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // check here. 805547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (InterfaceID != mDNSInterface_Unicast && IsLocalDomain(qname)) { LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Local question", qname, DNSTypeName(qtype)); return mDNSfalse; } 805647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 805747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Skip Private domains as we have special addresses to get the hosts in the Private domain 805847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthInfo = GetAuthInfoForName_internal(m, qname); 805947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (AuthInfo && !AuthInfo->deltime && AuthInfo->AutoTunnel) 806047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Private Domain", qname, DNSTypeName(qtype)); return mDNSfalse; } 806147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 806247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Match on Type, Address and InterfaceID 806347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 806447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Check whether we are looking for a name that ends in .local, then presence of a link-local 806547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // address on the interface is sufficient. 806647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i = m->HostInterfaces; i; i = i->next) 806747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 806847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (i->ip.type != iptype) continue; 806947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 807047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!InterfaceID || (InterfaceID == mDNSInterface_LocalOnly) || (InterfaceID == mDNSInterface_P2P) || 807147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (InterfaceID == mDNSInterface_Unicast) || (i->InterfaceID == InterfaceID)) 807247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 807347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (iptype == mDNSAddrType_IPv4 && !mDNSv4AddressIsLoopback(&i->ip.ip.v4) && !mDNSv4AddressIsLinkLocal(&i->ip.ip.v4)) 807447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 807547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Local Address %.4a found", qname, DNSTypeName(qtype), 807647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt &i->ip.ip.v4); 807747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNSfalse; 807847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 807947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (iptype == mDNSAddrType_IPv6 && 808047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !mDNSv6AddressIsLoopback(&i->ip.ip.v6) && 808147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !mDNSv6AddressIsLinkLocal(&i->ip.ip.v6) && 808247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !mDNSSameIPv6Address(i->ip.ip.v6, m->AutoTunnelHostAddr) && 808347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !mDNSSameIPv6Address(i->ip.ip.v6, m->AutoTunnelRelayAddrOut)) 808447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 808547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Local Address %.16a found", qname, DNSTypeName(qtype), 808647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt &i->ip.ip.v6); 808747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNSfalse; 808847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 808947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 809047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 809147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("ShouldSuppressQuery: Query suppressed for %##s, qtype %s, because no matching interface found", qname, DNSTypeName(qtype)); 809247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNStrue; 809347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 809447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 809547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void CacheRecordRmvEventsForCurrentQuestion(mDNS *const m, DNSQuestion *q) 809647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 809747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr; 809847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 809947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg; 810047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 810147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt slot = HashSlot(&q->qname); 810247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 810347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 810447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 810547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't deliver RMV events for negative records 810647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) 810747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 810847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CacheRecordRmvEventsForCurrentQuestion: CacheRecord %s Suppressing RMV events for question %p %##s (%s), CRActiveQuestion %p, CurrentAnswers %d", 810947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CRDisplayString(m, rr), q, q->qname.c, DNSTypeName(q->qtype), rr->CRActiveQuestion, q->CurrentAnswers); 811047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt continue; 811147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 811247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 811347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameNameRecordAnswersQuestion(&rr->resrec, q)) 811447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 811547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CacheRecordRmvEventsForCurrentQuestion: Calling AnswerCurrentQuestionWithResourceRecord (RMV) for question %##s using resource record %s LocalAnswers %d", 811647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qname.c, CRDisplayString(m, rr), q->LOAddressAnswers); 811747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 811847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->CurrentAnswers--; 811947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--; 812047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--; 812147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 812247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->CRActiveQuestion == q) 812347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 812447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *qptr; 812547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this was the active question for this cache entry, it was the one that was 812647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // responsible for keeping the cache entry fresh when the cache entry was reaching 812747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // its expiry. We need to handover the responsibility to someone else. Otherwise, 812847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // when the cache entry is about to expire, we won't find an active question 812947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (pointed by CRActiveQuestion) to refresh the cache. 813047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (qptr = m->Questions; qptr; qptr=qptr->next) 813147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (qptr != q && ActiveQuestion(qptr) && ResourceRecordAnswersQuestion(&rr->resrec, qptr)) 813247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 813347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 813447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (qptr) 813547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CacheRecordRmvEventsForCurrentQuestion: Updating CRActiveQuestion to %p for cache record %s, " 813647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "Original question CurrentAnswers %d, new question CurrentAnswers %d, SuppressUnusable %d, SuppressQuery %d", 813747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt qptr, CRDisplayString(m,rr), q->CurrentAnswers, qptr->CurrentAnswers, qptr->SuppressUnusable, qptr->SuppressQuery); 813847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 813947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->CRActiveQuestion = qptr; // Question used to be active; new value may or may not be null 814047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!qptr) m->rrcache_active--; // If no longer active, decrement rrcache_active count 814147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 814247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv); 814347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 814447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 814547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 814647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 814747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 814847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool IsQuestionNew(mDNS *const m, DNSQuestion *question) 814947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 815047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 815147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->NewQuestions; q; q = q->next) 815247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q == question) return mDNStrue; 815347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNSfalse; 815447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 815547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 815647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q) 815747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 815847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 815947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 816047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthGroup *ag; 816147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 816247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 816347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("LocalRecordRmvEventsForQuestion: ERROR m->CurrentQuestion already set: %##s (%s)", 816447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 816547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 816647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (IsQuestionNew(m, q)) 816747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 816847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("LocalRecordRmvEventsForQuestion: New Question %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 816947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNStrue; 817047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 817147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = q; 817247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt slot = AuthHashSlot(&q->qname); 817347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); 817447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ag) 817547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 817647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = ag->members; rr; rr=rr->next) 817747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Filter the /etc/hosts records - LocalOnly, Unique, A/AAAA/CNAME 817847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (LORecordAnswersAddressType(rr) && LocalOnlyRecordAnswersQuestion(rr, q)) 817947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 818047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("LocalRecordRmvEventsForQuestion: Delivering possible Rmv events with record %s", 818147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ARDisplayString(m, rr)); 818247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->CurrentAnswers <= 0 || q->LOAddressAnswers <= 0) 818347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 818447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("LocalRecordRmvEventsForQuestion: ERROR!! CurrentAnswers or LOAddressAnswers is zero %p %##s" 818547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt " (%s) CurrentAnswers %d, LOAddressAnswers %d", q, q->qname.c, DNSTypeName(q->qtype), 818647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->CurrentAnswers, q->LOAddressAnswers); 818747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt continue; 818847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 818947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AnswerLocalQuestionWithLocalAuthRecord(m, rr, QC_rmv); // MUST NOT dereference q again 819047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion != q) { m->CurrentQuestion = mDNSNULL; return mDNSfalse; } 819147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 819247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 819347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 819447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNStrue; 819547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 819647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 819747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Returns false if the question got deleted while delivering the RMV events 819847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The caller should handle the case 819947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q) 820047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 820147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion) 820247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("CacheRecordRmvEventsForQuestion: ERROR m->CurrentQuestion already set: %##s (%s)", 820347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 820447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 820547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If it is a new question, we have not delivered any ADD events yet. So, don't deliver RMV events. 820647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this question was answered using local auth records, then you can't deliver RMVs using cache 820747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!IsQuestionNew(m, q) && !q->LOAddressAnswers) 820847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 820947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = q; 821047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecordRmvEventsForCurrentQuestion(m, q); 821147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion != q) { m->CurrentQuestion = mDNSNULL; return mDNSfalse; } 821247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 821347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 821447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else { LogInfo("CacheRecordRmvEventsForQuestion: Question %p %##s (%s) is a new question", q, q->qname.c, DNSTypeName(q->qtype)); } 821547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNStrue; 821647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 821747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 821847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The caller should hold the lock 821947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void CheckSuppressUnusableQuestions(mDNS *const m) 822047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 822147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 822247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *restart = mDNSNULL; 822347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 822447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We look through all questions including new questions. During network change events, 822547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we potentially restart questions here in this function that ends up as new questions, 822647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which may be suppressed at this instance. Before it is handled we get another network 822747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // event that changes the status e.g., address becomes available. If we did not process 822847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // new questions, we would never change its SuppressQuery status. 822947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 823047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // CurrentQuestion is used by RmvEventsForQuestion below. While delivering RMV events, the 823147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // application callback can potentially stop the current question (detected by CurrentQuestion) or 823247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *any* other question which could be the next one that we may process here. RestartQuestion 823347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // points to the "next" question which will be automatically advanced in mDNS_StopQuery_internal 823447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if the "next" question is stopped while the CurrentQuestion is stopped 823547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->RestartQuestion) 823647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("CheckSuppressUnusableQuestions: ERROR!! m->RestartQuestion already set: %##s (%s)", 823747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RestartQuestion->qname.c, DNSTypeName(m->RestartQuestion->qtype)); 823847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RestartQuestion = m->Questions; 823947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->RestartQuestion) 824047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 824147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q = m->RestartQuestion; 824247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RestartQuestion = q->next; 824347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(q->TargetQID) && q->SuppressUnusable) 824447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 824547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool old = q->SuppressQuery; 824647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->SuppressQuery = ShouldSuppressQuery(m, &q->qname, q->qtype, q->InterfaceID); 824747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->SuppressQuery != old) 824847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 824947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // NOTE: CacheRecordRmvEventsForQuestion will not generate RMV events for queries that have non-zero 825047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // LOddressAnswers. Hence it is important that we call CacheRecordRmvEventsForQuestion before 825147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // LocalRecordRmvEventsForQuestion (which decrements LOAddressAnswers) 825247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 825347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->SuppressQuery) 825447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 825547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Previously it was not suppressed, Generate RMV events for the ADDs that we might have delivered before 825647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // followed by a negative cache response. Temporarily turn off suppression so that 825747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // AnswerCurrentQuestionWithResourceRecord can answer the question 825847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->SuppressQuery = mDNSfalse; 825947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!CacheRecordRmvEventsForQuestion(m, q)) { LogInfo("CheckSuppressUnusableQuestions: Question deleted while delivering RMV events"); continue; } 826047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->SuppressQuery = mDNStrue; 826147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 826247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 826347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // SuppressUnusable does not affect questions that are answered from the local records (/etc/hosts) 826447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and SuppressQuery status does not mean anything for these questions. As we are going to stop the 826547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // question below, we need to deliver the RMV events so that the ADDs that will be delivered during 826647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the restart will not be a duplicate ADD 826747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!LocalRecordRmvEventsForQuestion(m, q)) { LogInfo("CheckSuppressUnusableQuestions: Question deleted while delivering RMV events"); continue; } 826847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 826947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // There are two cases here. 827047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 827147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. Previously it was suppressed and now it is not suppressed, restart the question so 827247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that it will start as a new question. Note that we can't just call ActivateUnicastQuery 827347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // because when we get the response, if we had entries in the cache already, it will not answer 827447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // this question if the cache entry did not change. Hence, we need to restart 827547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the query so that it can be answered from the cache. 827647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 827747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. Previously it was not suppressed and now it is suppressed. We need to restart the questions 827847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so that we redo the duplicate checks in mDNS_StartQuery_internal. A SuppressUnusable question 827947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // is a duplicate of non-SuppressUnusable question if it is not suppressed (SuppressQuery is false). 828047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // A SuppressUnusable question is not a duplicate of non-SuppressUnusable question if it is suppressed 828147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (SuppressQuery is true). The reason for this is that when a question is suppressed, we want an 828247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // immediate response and not want to be blocked behind a question that is querying DNS servers. When 828347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the question is not suppressed, we don't want two active questions sending packets on the wire. 828447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This affects both efficiency and also the current design where there is only one active question 828547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // pointed to from a cache entry. 828647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 828747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We restart queries in a two step process by first calling stop and build a temporary list which we 828847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // will restart at the end. The main reason for the two step process is to handle duplicate questions. 828947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If there are duplicate questions, calling stop inherits the values from another question on the list (which 829047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // will soon become the real question) including q->ThisQInterval which might be zero if it was 829147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // suppressed before. At the end when we have restarted all questions, none of them is active as each 829247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // inherits from one another and we need to reactivate one of the questions here which is a little hacky. 829347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 829447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // It is much cleaner and less error prone to build a list of questions and restart at the end. 829547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 829647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CheckSuppressUnusableQuestions: Stop question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); 829747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopQuery_internal(m, q); 829847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->next = restart; 829947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt restart = q; 830047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 830147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 830247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 830347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (restart) 830447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 830547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q = restart; 830647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt restart = restart->next; 830747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->next = mDNSNULL; 830847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CheckSuppressUnusableQuestions: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); 830947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StartQuery_internal(m, q); 831047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 831147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 831247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 831347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question) 831447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 831547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->Target.type && !ValidQuestionTarget(question)) 831647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 831747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_StartQuery_internal: Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery? for question %##s)", 831847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->Target.type, mDNSVal16(question->TargetPort), question->qname.c); 831947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->Target.type = mDNSAddrType_None; 832047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 832147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 832247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!question->Target.type) question->TargetPort = zeroIPPort; // If no question->Target specified clear TargetPort 832347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 832447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->TargetQID = 832547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 832647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (question->Target.type || Question_uDNS(question)) ? mDNS_NewMessageID(m) : 832747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif // UNICAST_DISABLED 832847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt zeroID; 832947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 833047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_StartQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 833147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 833247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->rrcache_size == 0) // Can't do queries if we have no cache space allocated 833347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoCache); 833447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 833547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 833647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 833747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion **q; 833847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 833947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ValidateDomainName(&question->qname)) 834047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 834147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 834247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_Invalid); 834347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 834447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 834547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: It important that new questions are appended at the *end* of the list, not prepended at the start 834647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q = &m->Questions; 834747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P) q = &m->LocalOnlyQuestions; 834847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*q && *q != question) q=&(*q)->next; 834947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 835047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*q) 835147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 835247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Error! Tried to add a question %##s (%s) %p that's already in the active list", 835347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qname.c, DNSTypeName(question->qtype), question); 835447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_AlreadyRegistered); 835547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 835647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 835747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *q = question; 835847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 835947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this question is referencing a specific interface, verify it exists 836047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_Unicast && question->InterfaceID != mDNSInterface_P2P) 836147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 836247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf = FirstInterfaceForID(m, question->InterfaceID); 836347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!intf) 836447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list", 836547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->InterfaceID, question->qname.c, DNSTypeName(question->qtype)); 836647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 836747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 836847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: In the case where we already have the answer to this question in our cache, that may be all the client 836947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would 837047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // be a waste. For that reason, we schedule our first query to go out in half a second (InitialQuestionInterval). 837147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If AnswerNewQuestion() finds that we have *no* relevant answers currently in our cache, then it will accelerate 837247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that to go out immediately. 837347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->next = mDNSNULL; 837447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qnamehash = DomainNameHashValue(&question->qname); // MUST do this before FindDuplicateQuestion() 837547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname)); 837647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->LastQTime = m->timenow; 837747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question 837847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ExpectUnicastResp = 0; 837947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->LastAnswerPktNum = m->PktNum; 838047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->RecentAnswerPkts = 0; 838147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->CurrentAnswers = 0; 838247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->LargeAnswers = 0; 838347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->UniqueAnswers = 0; 838447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->LOAddressAnswers = 0; 838547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->FlappingInterface1 = mDNSNULL; 838647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->FlappingInterface2 = mDNSNULL; 838747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Must do AuthInfo and SuppressQuery before calling FindDuplicateQuestion() 838847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->AuthInfo = GetAuthInfoForQuestion(m, question); 838947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->SuppressUnusable) 839047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->SuppressQuery = ShouldSuppressQuery(m, &question->qname, question->qtype, question->InterfaceID); 839147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 839247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->SuppressQuery = 0; 839347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->DuplicateOf = FindDuplicateQuestion(m, question); 839447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->NextInDQList = mDNSNULL; 839547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->SendQNow = mDNSNULL; 839647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->SendOnAll = mDNSfalse; 839747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->RequestUnicast = 0; 839847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->LastQTxTime = m->timenow; 839947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->CNAMEReferrals = 0; 840047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 840147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We'll create our question->LocalSocket on demand, if needed. 840247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We won't need one for duplicate questions, or from questions answered immediately out of the cache. 840347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We also don't need one for LLQs because (when we're using NAT) we want them all to share a single 840447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // NAT mapping for receiving inbound add/remove events. 840547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->LocalSocket = mDNSNULL; 840647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->deliverAddEvents = mDNSfalse; 840747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qDNSServer = mDNSNULL; 840847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->unansweredQueries = 0; 840947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->nta = mDNSNULL; 841047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->servAddr = zeroAddr; 841147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->servPort = zeroIPPort; 841247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->tcp = mDNSNULL; 841347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->NoAnswer = NoAnswer_Normal; 841447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 841547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->state = LLQ_InitialRequest; 841647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ReqLease = 0; 841747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->expire = 0; 841847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ntries = 0; 841947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->id = zeroOpaque64; 842047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->validDNSServers = zeroOpaque64; 842147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->triedAllServersOnce = 0; 842247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->noServerResponse = 0; 842347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->StopTime = 0; 842447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->WakeOnResolve) 842547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 842647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->WakeOnResolveCount = InitialWakeOnResolveCount; 842747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_PurgeBeforeResolve(m, question); 842847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 842947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 843047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->WakeOnResolveCount = 0; 843147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 843247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->DuplicateOf) question->AuthInfo = question->DuplicateOf->AuthInfo; 843347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 843447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<DupSuppressInfoSize; i++) 843547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->DupSuppress[i].InterfaceID = mDNSNULL; 843647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 843747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_StartQuery: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)", 843847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, m->timenow, 843947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NextQSendTime(question) - m->timenow, 844047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->DelayAnswering ? question->DelayAnswering - m->timenow : 0, 844147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question, question->DuplicateOf ? "duplicate of" : "not duplicate", question->DuplicateOf); 844247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 844347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->DelayAnswering) 844447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_StartQuery_internal: Delaying answering for %d ticks while cache stabilizes for %##s (%s)", 844547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->DelayAnswering - m->timenow, question->qname.c, DNSTypeName(question->qtype)); 844647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 844747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P) 844847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 844947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question; 845047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 845147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 845247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 845347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->NewQuestions) m->NewQuestions = question; 845447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 845547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the question's id is non-zero, then it's Wide Area 845647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // MUST NOT do this Wide Area setup until near the end of 845747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // mDNS_StartQuery_internal -- this code may itself issue queries (e.g. SOA, 845847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // NS, etc.) and if we haven't finished setting up our own question and setting 845947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // m->NewQuestions if necessary then we could end up recursively re-entering 846047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // this routine with the question list data structures in an inconsistent state. 846147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(question->TargetQID)) 846247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 846347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Duplicate questions should have the same DNSServers so that when we find 846447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // a matching resource record, all of them get the answers. Calling GetServerForQuestion 846547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // for the duplicate question may get a different DNS server from the original question 846647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 timeout = SetValidDNSServers(m, question); 846747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We set the timeout whenever mDNS_StartQuery_internal is called. This means if we have 846847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // a networking change/search domain change that calls this function again we keep 846947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // reinitializing the timeout value which means it may never timeout. If this becomes 847047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // a common case in the future, we can easily fix this by adding extra state that 847147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // indicates that we have already set the StopTime. 847247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->TimeoutQuestion) 847347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->StopTime = NonZeroTime(m->timenow + timeout * mDNSPlatformOneSecond); 847447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->DuplicateOf) 847547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 847647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->validDNSServers = question->DuplicateOf->validDNSServers; 847747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qDNSServer = question->DuplicateOf->qDNSServer; 847847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_StartQuery_internal: Duplicate question %p (%p) %##s (%s), Timeout %d, DNS Server %#a:%d", 847947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question, question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype), timeout, 848047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL, 848147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort)); 848247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 848347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 848447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 848547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qDNSServer = GetServerForQuestion(m, question); 848647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_StartQuery_internal: question %p %##s (%s) Timeout %d, DNS Server %#a:%d", 848747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question, question->qname.c, DNSTypeName(question->qtype), timeout, 848847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL, 848947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort)); 849047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 849147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ActivateUnicastQuery(m, question, mDNSfalse); 849247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 849347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If long-lived query, and we don't have our NAT mapping active, start it now 849447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->LongLived && !m->LLQNAT.clientContext) 849547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 849647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LLQNAT.Protocol = NATOp_MapUDP; 849747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LLQNAT.IntPort = m->UnicastPort4; 849847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LLQNAT.RequestedPort = m->UnicastPort4; 849947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LLQNAT.clientCallback = LLQNATCallback; 850047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LLQNAT.clientContext = (void*)1; // Means LLQ NAT Traversal is active 850147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StartNATOperation_internal(m, &m->LLQNAT); 850247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 850347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 850447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder 850547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->LongLived) 850647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt UpdateAutoTunnelDomainStatuses(m); 850747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 850847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 850947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 851047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 851147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 851247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->TimeoutQuestion) 851347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->StopTime = NonZeroTime(m->timenow + GetTimeoutForMcastQuestion(m, question) * mDNSPlatformOneSecond); 851447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 851547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->StopTime) SetNextQueryStopTime(m, question); 851647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextQueryTime(m,question); 851747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 851847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 851947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); 852047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 852147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 852247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 852347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// CancelGetZoneData is an internal routine (i.e. must be called with the lock already held) 852447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta) 852547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 852647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("CancelGetZoneData %##s (%s)", nta->question.qname.c, DNSTypeName(nta->question.qtype)); 852747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This function may be called anytime to free the zone information.The question may or may not have stopped. 852847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If it was already stopped, mDNS_StopQuery_internal would have set q->ThisQInterval to -1 and should not 852947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // call it again 853047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (nta->question.ThisQInterval != -1) 853147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 853247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopQuery_internal(m, &nta->question); 853347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (nta->question.ThisQInterval != -1) 853447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("CancelGetZoneData: Question %##s (%s) ThisQInterval %d not -1", nta->question.qname.c, DNSTypeName(nta->question.qtype), nta->question.ThisQInterval); 853547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 853647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemFree(nta); 853747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 853847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 853947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question) 854047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 854147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = HashSlot(&question->qname); 854247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname); 854347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr; 854447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion **qp = &m->Questions; 854547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 854647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 854747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 854847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P) qp = &m->LocalOnlyQuestions; 854947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*qp && *qp != question) qp=&(*qp)->next; 855047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*qp) *qp = (*qp)->next; 855147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 855247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 855347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if !ForceAlerts 855447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->ThisQInterval >= 0) // Only log error message if the query was supposed to be active 855547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 855647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list", 855747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qname.c, DNSTypeName(question->qtype)); 855847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ForceAlerts 855947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *(long*)0 = 0; 856047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 856147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_BadReferenceErr); 856247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 856347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 856447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Take care to cut question from list *before* calling UpdateQuestionDuplicates 856547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt UpdateQuestionDuplicates(m, question); 856647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // But don't trash ThisQInterval until afterwards. 856747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ThisQInterval = -1; 856847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 856947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If there are any cache records referencing this as their active question, then see if there is any 857047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL. 857147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 857247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 857347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->CRActiveQuestion == question) 857447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 857547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 857647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Checking for ActiveQuestion filters questions that are suppressed also 857747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // as suppressed questions are not active 857847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) // Scan our list of questions 857947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q)) 858047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 858147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q) 858247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s, Original question CurrentAnswers %d, new question " 858347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "CurrentAnswers %d, SuppressQuery %d", q, CRDisplayString(m,rr), question->CurrentAnswers, q->CurrentAnswers, q->SuppressQuery); 858447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->CRActiveQuestion = q; // Question used to be active; new value may or may not be null 858547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q) m->rrcache_active--; // If no longer active, decrement rrcache_active count 858647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 858747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 858847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 858947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv() is about to look at, 859047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // bump its pointer forward one question. 859147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentQuestion == question) 859247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 859347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_StopQuery_internal: Just deleted the currently active question: %##s (%s)", 859447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qname.c, DNSTypeName(question->qtype)); 859547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = question->next; 859647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 859747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 859847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NewQuestions == question) 859947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 860047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_StopQuery_internal: Just deleted a new question that wasn't even answered yet: %##s (%s)", 860147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qname.c, DNSTypeName(question->qtype)); 860247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NewQuestions = question->next; 860347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 860447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 860547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NewLocalOnlyQuestions == question) m->NewLocalOnlyQuestions = question->next; 860647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 860747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->RestartQuestion == question) 860847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 860947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_StopQuery_internal: Just deleted the current restart question: %##s (%s)", 861047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qname.c, DNSTypeName(question->qtype)); 861147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RestartQuestion = question->next; 861247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 861347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 861447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions 861547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->next = mDNSNULL; 861647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 861747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // LogMsg("mDNS_StopQuery_internal: Question %##s (%s) removed", question->qname.c, DNSTypeName(question->qtype)); 861847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 861947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // And finally, cancel any associated GetZoneData operation that's still running. 862047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Must not do this until last, because there's a good chance the GetZoneData question is the next in the list, 862147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already 862247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary 862347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query. 862447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; } 862547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->LocalSocket) { mDNSPlatformUDPClose(question->LocalSocket); question->LocalSocket = mDNSNULL; } 862647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(question->TargetQID) && question->LongLived) 862747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 862847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Scan our list to see if any more wide-area LLQs remain. If not, stop our NAT Traversal. 862947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 863047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) 863147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived) break; 863247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q) 863347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 863447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->LLQNAT.clientContext) // Should never happen, but just in case... 863547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_StopQuery ERROR LLQNAT.clientContext NULL"); 863647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 863747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 863847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("Stopping LLQNAT"); 863947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopNATOperation_internal(m, &m->LLQNAT); 864047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LLQNAT.clientContext = mDNSNULL; // Means LLQ NAT Traversal not running 864147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 864247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 864347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 864447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If necessary, tell server it can delete this LLQ state 864547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->state == LLQ_Established) 864647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 864747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ReqLease = 0; 864847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sendLLQRefresh(m, question); 864947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we need need to make a TCP connection to cancel the LLQ, that's going to take a little while. 865047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We clear the tcp->question backpointer so that when the TCP connection completes, it doesn't 865147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // crash trying to access our cancelled question, but we don't cancel the TCP operation itself -- 865247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we let that run out its natural course and complete asynchronously. 865347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->tcp) 865447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 865547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->tcp->question = mDNSNULL; 865647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->tcp = mDNSNULL; 865747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 865847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 865947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder 866047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt UpdateAutoTunnelDomainStatuses(m); 866147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 866247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 866347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // wait until we send the refresh above which needs the nta 866447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; } 866547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 866647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); 866747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 866847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 866947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question) 867047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 867147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus status; 867247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 867347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt status = mDNS_StartQuery_internal(m, question); 867447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 867547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(status); 867647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 867747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 867847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) 867947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 868047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus status; 868147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 868247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt status = mDNS_StopQuery_internal(m, question); 868347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 868447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(status); 868547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 868647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 868747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note that mDNS_StopQueryWithRemoves() does not currently implement the full generality of the other APIs 868847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Specifically, question callbacks invoked as a result of this call cannot themselves make API calls. 868947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// We invoke the callback without using mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback 869047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// specifically to catch and report if the client callback does try to make API calls 869147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const question) 869247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 869347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus status; 869447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *qq; 869547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 869647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 869747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Check if question is new -- don't want to give remove events for a question we haven't even answered yet 869847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (qq = m->NewQuestions; qq; qq=qq->next) if (qq == question) break; 869947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 870047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt status = mDNS_StopQuery_internal(m, question); 870147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (status == mStatus_NoError && !qq) 870247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 870347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const CacheRecord *rr; 870447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = HashSlot(&question->qname); 870547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *const cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname); 870647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 870747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 870847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question)) 870947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 871047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls 871147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (question->QuestionCallback) 871247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->QuestionCallback(m, question, &rr->resrec, mDNSfalse); 871347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 871447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 871547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 871647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(status); 871747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 871847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 871947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const cr) 872047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 872147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus status; 872247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 872347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); 872447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0); 872547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 872647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(status); 872747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 872847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 872947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr) 873047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 873147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus status = mStatus_BadReferenceErr; 873247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *cr; 873347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 873447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr = FindIdenticalRecordInCache(m, rr); 873547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_ReconfirmByValue: %p %s", cr, RRDisplayString(m, rr)); 873647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr) status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); 873747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0); 873847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 873947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(status); 874047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 874147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 874247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const question, 874347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainname *const srv, const domainname *const domain, 874447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context) 874547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 874647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->InterfaceID = InterfaceID; 874747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->Target = zeroAddr; 874847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qtype = kDNSType_PTR; 874947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qclass = kDNSClass_IN; 875047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->LongLived = mDNStrue; 875147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ExpectUnique = mDNSfalse; 875247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ForceMCast = ForceMCast; 875347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ReturnIntermed = mDNSfalse; 875447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->SuppressUnusable = mDNSfalse; 875547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->SearchListIndex = 0; 875647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->AppendSearchDomains = 0; 875747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->RetryWithSearchDomains = mDNSfalse; 875847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->TimeoutQuestion = 0; 875947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->WakeOnResolve = 0; 876047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qnameOrig = mDNSNULL; 876147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->QuestionCallback = Callback; 876247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->QuestionContext = Context; 876347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr); 876447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 876547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNS_StartQuery_internal(m, question)); 876647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 876747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 876847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question, 876947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainname *const srv, const domainname *const domain, 877047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context) 877147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 877247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus status; 877347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 877447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt status = mDNS_StartBrowse_internal(m, question, srv, domain, InterfaceID, ForceMCast, Callback, Context); 877547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 877647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(status); 877747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 877847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 877947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m) 878047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 878147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf; 878247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = m->HostInterfaces; intf; intf = intf->next) 878347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->ip.type == mDNSAddrType_IPv6) return(mDNStrue); 878447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNSfalse); 878547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 878647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 878747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 878847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 878947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; 879047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool PortChanged = !mDNSSameIPPort(query->info->port, answer->rdata->u.srv.port); 879147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AddRecord) return; 879247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (answer->rrtype != kDNSType_SRV) return; 879347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 879447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->info->port = answer->rdata->u.srv.port; 879547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 879647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this is our first answer, then set the GotSRV flag and start the address query 879747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!query->GotSRV) 879847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 879947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->GotSRV = mDNStrue; 880047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.InterfaceID = answer->InterfaceID; 880147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target); 880247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.InterfaceID = answer->InterfaceID; 880347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target); 880447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StartQuery(m, &query->qAv4); 880547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Only do the AAAA query if this machine actually has IPv6 active 880647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6); 880747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 880847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this is not our first answer, only re-issue the address query if the target host name has changed 880947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if ((query->qAv4.InterfaceID != query->qSRV.InterfaceID && query->qAv4.InterfaceID != answer->InterfaceID) || 881047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target)) 881147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 881247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopQuery(m, &query->qAv4); 881347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (query->qAv6.ThisQInterval >= 0) mDNS_StopQuery(m, &query->qAv6); 881447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target) && !PortChanged) 881547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 881647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we get here, it means: 881747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. This is not our first SRV answer 881847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. The interface ID is different, but the target host and port are the same 881947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This implies that we're seeing the exact same SRV record on more than one interface, so we should 882047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // make our address queries at least as broad as the original SRV query so that we catch all the answers. 882147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.InterfaceID = query->qSRV.InterfaceID; // Will be mDNSInterface_Any, or a specific interface 882247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.InterfaceID = query->qSRV.InterfaceID; 882347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 882447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 882547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 882647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.InterfaceID = answer->InterfaceID; 882747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target); 882847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.InterfaceID = answer->InterfaceID; 882947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target); 883047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 883147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query->qAv4.qname.c, DNSTypeName(query->qAv4.qtype)); 883247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StartQuery(m, &query->qAv4); 883347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Only do the AAAA query if this machine actually has IPv6 active 883447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6); 883547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 883647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (query->ServiceInfoQueryCallback && query->GotADD && query->GotTXT && PortChanged) 883747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 883847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (++query->Answers >= 100) 883947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u", 884047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->Answers, query->qSRV.qname.c, answer->rdata->u.srv.target.c, 884147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSVal16(answer->rdata->u.srv.port)); 884247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->ServiceInfoQueryCallback(m, query); 884347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 884447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's 884547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // callback function is allowed to do anything, including deleting this query and freeing its memory. 884647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 884747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 884847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 884947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 885047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; 885147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AddRecord) return; 885247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (answer->rrtype != kDNSType_TXT) return; 885347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (answer->rdlength > sizeof(query->info->TXTinfo)) return; 885447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 885547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->GotTXT = mDNStrue; 885647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->info->TXTlen = answer->rdlength; 885747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->info->TXTinfo[0] = 0; // In case answer->rdlength is zero 885847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemCopy(query->info->TXTinfo, answer->rdata->u.txt.c, answer->rdlength); 885947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 886047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD); 886147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 886247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's 886347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // callback function is allowed to do anything, including deleting this query and freeing its memory. 886447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (query->ServiceInfoQueryCallback && query->GotADD) 886547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 886647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (++query->Answers >= 100) 886747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...", 886847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->Answers, query->qSRV.qname.c, answer->rdata->u.txt.c); 886947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->ServiceInfoQueryCallback(m, query); 887047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 887147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 887247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 887347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 887447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 887547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; 887647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //LogInfo("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer)); 887747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AddRecord) return; 887847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 887947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (answer->rrtype == kDNSType_A) 888047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 888147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->info->ip.type = mDNSAddrType_IPv4; 888247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->info->ip.ip.v4 = answer->rdata->u.ipv4; 888347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 888447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (answer->rrtype == kDNSType_AAAA) 888547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 888647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->info->ip.type = mDNSAddrType_IPv6; 888747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->info->ip.ip.v6 = answer->rdata->u.ipv6; 888847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 888947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 889047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 889147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer->name->c, answer->rrtype, DNSTypeName(answer->rrtype)); 889247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 889347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 889447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 889547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->GotADD = mDNStrue; 889647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->info->InterfaceID = answer->InterfaceID; 889747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 889847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query->info->ip.type, query->info->name.c, query->GotTXT); 889947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 890047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's 890147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // callback function is allowed to do anything, including deleting this query and freeing its memory. 890247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (query->ServiceInfoQueryCallback && query->GotTXT) 890347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 890447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (++query->Answers >= 100) 890547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf(answer->rrtype == kDNSType_A ? 890647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "**** WARNING **** have given %lu answers for %##s (A) %.4a" : 890747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a", 890847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->Answers, query->qSRV.qname.c, &answer->rdata->u.data); 890947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->ServiceInfoQueryCallback(m, query); 891047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 891147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 891247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 891347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure 891447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If the query is not interface-specific, then InterfaceID may be zero 891547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Each time the Callback is invoked, the remainder of the fields will have been filled in 891647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In addition, InterfaceID will be updated to give the interface identifier corresponding to that response 891747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_StartResolveService(mDNS *const m, 891847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context) 891947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 892047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus status; 892147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 892247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 892347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question 892447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.InterfaceID = info->InterfaceID; 892547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.Target = zeroAddr; 892647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&query->qSRV.qname, &info->name); 892747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.qtype = kDNSType_SRV; 892847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.qclass = kDNSClass_IN; 892947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.LongLived = mDNSfalse; 893047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.ExpectUnique = mDNStrue; 893147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.ForceMCast = mDNSfalse; 893247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.ReturnIntermed = mDNSfalse; 893347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.SuppressUnusable = mDNSfalse; 893447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.SearchListIndex = 0; 893547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.AppendSearchDomains = 0; 893647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.RetryWithSearchDomains = mDNSfalse; 893747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.TimeoutQuestion = 0; 893847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.WakeOnResolve = 0; 893947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.qnameOrig = mDNSNULL; 894047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.QuestionCallback = FoundServiceInfoSRV; 894147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qSRV.QuestionContext = query; 894247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 894347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question 894447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.InterfaceID = info->InterfaceID; 894547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.Target = zeroAddr; 894647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&query->qTXT.qname, &info->name); 894747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.qtype = kDNSType_TXT; 894847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.qclass = kDNSClass_IN; 894947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.LongLived = mDNSfalse; 895047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.ExpectUnique = mDNStrue; 895147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.ForceMCast = mDNSfalse; 895247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.ReturnIntermed = mDNSfalse; 895347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.SuppressUnusable = mDNSfalse; 895447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.SearchListIndex = 0; 895547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.AppendSearchDomains = 0; 895647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.RetryWithSearchDomains = mDNSfalse; 895747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.TimeoutQuestion = 0; 895847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.WakeOnResolve = 0; 895947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.qnameOrig = mDNSNULL; 896047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.QuestionCallback = FoundServiceInfoTXT; 896147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qTXT.QuestionContext = query; 896247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 896347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question 896447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.InterfaceID = info->InterfaceID; 896547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.Target = zeroAddr; 896647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.qname.c[0] = 0; 896747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.qtype = kDNSType_A; 896847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.qclass = kDNSClass_IN; 896947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.LongLived = mDNSfalse; 897047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.ExpectUnique = mDNStrue; 897147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.ForceMCast = mDNSfalse; 897247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.ReturnIntermed = mDNSfalse; 897347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.SuppressUnusable = mDNSfalse; 897447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.SearchListIndex = 0; 897547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.AppendSearchDomains = 0; 897647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.RetryWithSearchDomains = mDNSfalse; 897747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.TimeoutQuestion = 0; 897847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.WakeOnResolve = 0; 897947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.qnameOrig = mDNSNULL; 898047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.QuestionCallback = FoundServiceInfo; 898147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv4.QuestionContext = query; 898247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 898347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question 898447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.InterfaceID = info->InterfaceID; 898547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.Target = zeroAddr; 898647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.qname.c[0] = 0; 898747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.qtype = kDNSType_AAAA; 898847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.qclass = kDNSClass_IN; 898947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.LongLived = mDNSfalse; 899047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.ExpectUnique = mDNStrue; 899147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.ForceMCast = mDNSfalse; 899247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.ReturnIntermed = mDNSfalse; 899347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.SuppressUnusable = mDNSfalse; 899447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.SearchListIndex = 0; 899547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.AppendSearchDomains = 0; 899647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.RetryWithSearchDomains = mDNSfalse; 899747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.TimeoutQuestion = 0; 899847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.WakeOnResolve = 0; 899947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.qnameOrig = mDNSNULL; 900047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.QuestionCallback = FoundServiceInfo; 900147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->qAv6.QuestionContext = query; 900247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 900347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->GotSRV = mDNSfalse; 900447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->GotTXT = mDNSfalse; 900547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->GotADD = mDNSfalse; 900647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->Answers = 0; 900747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 900847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->info = info; 900947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->ServiceInfoQueryCallback = Callback; 901047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt query->ServiceInfoQueryContext = Context; 901147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 901247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// info->name = Must already be set up by client 901347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// info->interface = Must already be set up by client 901447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt info->ip = zeroAddr; 901547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt info->port = zeroIPPort; 901647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt info->TXTlen = 0; 901747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 901847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We use mDNS_StartQuery_internal here because we're already holding the lock 901947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt status = mDNS_StartQuery_internal(m, &query->qSRV); 902047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (status == mStatus_NoError) status = mDNS_StartQuery_internal(m, &query->qTXT); 902147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (status != mStatus_NoError) mDNS_StopResolveService(m, query); 902247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 902347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 902447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(status); 902547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 902647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 902747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q) 902847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 902947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 903047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We use mDNS_StopQuery_internal here because we're already holding the lock 903147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->qSRV.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qSRV); 903247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->qTXT.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qTXT); 903347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->qAv4.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv4); 903447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->qAv6.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv6); 903547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 903647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 903747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 903847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom, 903947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context) 904047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 904147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->InterfaceID = InterfaceID; 904247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->Target = zeroAddr; 904347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qtype = kDNSType_PTR; 904447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qclass = kDNSClass_IN; 904547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->LongLived = mDNSfalse; 904647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ExpectUnique = mDNSfalse; 904747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ForceMCast = mDNSfalse; 904847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->ReturnIntermed = mDNSfalse; 904947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->SuppressUnusable = mDNSfalse; 905047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->SearchListIndex = 0; 905147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->AppendSearchDomains = 0; 905247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->RetryWithSearchDomains = mDNSfalse; 905347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->TimeoutQuestion = 0; 905447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->WakeOnResolve = 0; 905547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->qnameOrig = mDNSNULL; 905647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->QuestionCallback = Callback; 905747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt question->QuestionContext = Context; 905847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr); 905947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!MakeDomainNameFromDNSNameString(&question->qname, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr); 906047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!dom) dom = &localdomain; 906147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AppendDomainName(&question->qname, dom)) return(mStatus_BadParamErr); 906247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNS_StartQuery(m, question)); 906347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 906447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 906547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// *************************************************************************** 906647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK 906747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - 906847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Responder Functions 906947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 907047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 907147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr) 907247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 907347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus status; 907447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 907547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt status = mDNS_Register_internal(m, rr); 907647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 907747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(status); 907847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 907947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 908047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newttl, 908147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback) 908247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 908347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata)) 908447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 908547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer)); 908647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_Invalid); 908747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 908847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 908947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 909047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 909147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If TTL is unspecified, leave TTL unchanged 909247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newttl == 0) newttl = rr->resrec.rroriginalttl; 909347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 909447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we already have an update queued up which has not gone through yet, give the client a chance to free that memory 909547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->NewRData) 909647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 909747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RData *n = rr->NewRData; 909847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NewRData = mDNSNULL; // Clear the NewRData pointer ... 909947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->UpdateCallback) 910047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UpdateCallback(m, rr, n, rr->newrdlength); // ...and let the client free this memory, if necessary 910147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 910247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 910347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->NewRData = newrdata; 910447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->newrdlength = newrdlength; 910547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UpdateCallback = Callback; 910647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 910747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 910847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->ARType != AuthRecordLocalOnly && rr->ARType != AuthRecordP2P && !IsLocalDomain(rr->resrec.name)) 910947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 911047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus status = uDNS_UpdateRecord(m, rr); 911147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The caller frees the memory on error, don't retain stale pointers 911247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (status != mStatus_NoError) { rr->NewRData = mDNSNULL; rr->newrdlength = 0; } 911347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 911447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(status); 911547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 911647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 911747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 911847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (RRLocalOnly(rr) || (rr->resrec.rroriginalttl == newttl && 911947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))) 912047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CompleteRDataUpdate(m, rr); 912147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 912247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 912347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount = InitialAnnounceCount; 912447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeLastAPTime(m, rr); 912547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr); 912647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--; 912747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rr->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval); 912847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->AnnounceCount > rr->UpdateCredits + 1) rr->AnnounceCount = (mDNSu8)(rr->UpdateCredits + 1); 912947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->UpdateCredits <= 5) 913047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 913147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 delay = 6 - rr->UpdateCredits; // Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum 913247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + (mDNSs32)delay * mDNSPlatformOneSecond); 913347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ThisAPInterval *= 4; 913447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval; 913547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s", 913647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.name->c, delay, delay > 1 ? "s" : ""); 913747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 913847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rroriginalttl = newttl; 913947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 914047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 914147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 914247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); 914347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 914447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 914547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change 914647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// the record list and/or question list. 914747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 914847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) 914947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 915047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus status; 915147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 915247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt status = mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 915347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 915447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(status); 915547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 915647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 915747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface 915847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result); 915947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 916047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m) 916147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 916247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf; 916347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = m->HostInterfaces; intf; intf = intf->next) 916447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->Advertise) break; 916547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(intf); 916647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 916747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 916847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) 916947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 917047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char buffer[MAX_REVERSE_MAPPING_NAME]; 917147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m); 917247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary 917347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 917447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Send dynamic update for non-linklocal IPv4 Addresses 917547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&set->RR_A, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNS_HostNameCallback, set); 917647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&set->RR_PTR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); 917747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL); 917847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 917947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ANSWER_REMOTE_HOSTNAME_QUERIES 918047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->RR_A .AllowRemoteQuery = mDNStrue; 918147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->RR_PTR .AllowRemoteQuery = mDNStrue; 918247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->RR_HINFO.AllowRemoteQuery = mDNStrue; 918347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 918447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. Set up Address record to map from host name ("foo.local.") to IP address 918547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. Set up reverse-lookup PTR record to map from our address back to our host name 918647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&set->RR_A.namestorage, &m->MulticastHostname); 918747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->ip.type == mDNSAddrType_IPv4) 918847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 918947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->RR_A.resrec.rrtype = kDNSType_A; 919047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4; 919147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code 919247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", 919347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]); 919447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 919547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (set->ip.type == mDNSAddrType_IPv6) 919647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 919747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 919847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->RR_A.resrec.rrtype = kDNSType_AAAA; 919947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->RR_A.resrec.rdata->u.ipv6 = set->ip.ip.v6; 920047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i = 0; i < 16; i++) 920147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 920247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const char hexValues[] = "0123456789ABCDEF"; 920347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt buffer[i * 4 ] = hexValues[set->ip.ip.v6.b[15 - i] & 0x0F]; 920447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt buffer[i * 4 + 1] = '.'; 920547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt buffer[i * 4 + 2] = hexValues[set->ip.ip.v6.b[15 - i] >> 4]; 920647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt buffer[i * 4 + 3] = '.'; 920747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 920847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa."); 920947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 921047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 921147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt MakeDomainNameFromDNSNameString(&set->RR_PTR.namestorage, buffer); 921247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->RR_PTR.AutoTarget = Target_AutoHost; // Tell mDNS that the target of this PTR is to be kept in sync with our host name 921347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server 921447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 921547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->RR_A.RRSet = &primary->RR_A; // May refer to self 921647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 921747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Register_internal(m, &set->RR_A); 921847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Register_internal(m, &set->RR_PTR); 921947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 922047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!NO_HINFO && m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254) 922147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 922247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data; 922347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&set->RR_HINFO.namestorage, &m->MulticastHostname); 922447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->RR_HINFO.DependentOn = &set->RR_A; 922547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemCopy(p, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]); 922647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt p += 1 + (int)p[0]; 922747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemCopy(p, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]); 922847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Register_internal(m, &set->RR_HINFO); 922947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 923047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 923147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 923247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("Not creating HINFO record: platform support layer provided no information"); 923347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->RR_HINFO.resrec.RecordType = kDNSRecordTypeUnregistered; 923447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 923547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 923647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 923747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) 923847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 923947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf; 924047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 924147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we still have address records referring to this one, update them 924247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m); 924347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *A = primary ? &primary->RR_A : mDNSNULL; 924447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = m->HostInterfaces; intf; intf = intf->next) 924547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->RR_A.RRSet == &set->RR_A) 924647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->RR_A.RRSet = A; 924747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 924847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Unregister these records. 924947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform 925047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it. 925147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered. 925247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal(). 925347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->RR_A. resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A, mDNS_Dereg_normal); 925447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->RR_PTR. resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR, mDNS_Dereg_normal); 925547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal); 925647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 925747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 925847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_SetFQDN(mDNS *const m) 925947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 926047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainname newmname; 926147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf; 926247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 926347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newmname.c[0] = 0; 926447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 926547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AppendDomainLabel(&newmname, &m->hostlabel)) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; } 926647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AppendLiteralLabelString(&newmname, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; } 926747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 926847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 926947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 927047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameDomainNameCS(&m->MulticastHostname, &newmname)) debugf("mDNS_SetFQDN - hostname unchanged"); 927147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 927247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 927347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&m->MulticastHostname, &newmname); 927447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 927547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. Stop advertising our address records on all interfaces 927647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = m->HostInterfaces; intf; intf = intf->next) 927747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->Advertise) DeadvertiseInterface(m, intf); 927847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 927947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. Start advertising our address records using the new name 928047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = m->HostInterfaces; intf; intf = intf->next) 928147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->Advertise) AdvertiseInterface(m, intf); 928247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 928347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 928447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3. Make sure that any AutoTarget SRV records (and the like) get updated 928547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr); 928647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr); 928747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 928847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 928947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 929047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 929147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 929247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 929347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (void)rr; // Unused parameter 929447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 929547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #if MDNS_DEBUGMSGS 929647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 929747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char *msg = "Unknown result"; 929847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (result == mStatus_NoError) msg = "Name registered"; 929947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (result == mStatus_NameConflict) msg = "Name conflict"; 930047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result); 930147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 930247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #endif 930347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 930447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (result == mStatus_NoError) 930547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 930647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Notify the client that the host name is successfully registered 930747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->MainCallback) 930847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->MainCallback(m, mStatus_NoError); 930947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 931047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (result == mStatus_NameConflict) 931147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 931247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainlabel oldlabel = m->hostlabel; 931347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 931447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. First give the client callback a chance to pick a new name 931547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->MainCallback) 931647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->MainCallback(m, mStatus_NameConflict); 931747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 931847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. If the client callback didn't do it, add (or increment) an index ourselves 931947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This needs to be case-INSENSITIVE compare, because we need to know that the name has been changed so as to 932047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // remedy the conflict, and a name that differs only in capitalization will just suffer the exact same conflict again. 932147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameDomainLabel(m->hostlabel.c, oldlabel.c)) 932247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt IncrementLabelSuffix(&m->hostlabel, mDNSfalse); 932347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 932447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3. Generate the FQDNs from the hostlabel, 932547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and make sure all SRV records, etc., are updated to reference our new hostname 932647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetFQDN(m); 932747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel.c, m->hostlabel.c); 932847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 932947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (result == mStatus_MemFree) 933047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 933147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by 933247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface 933347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_HostNameCallback: MemFree (ignored)"); 933447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 933547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 933647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result, rr->resrec.name->c); 933747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 933847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 933947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active) 934047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 934147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf; 934247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt active->IPv4Available = mDNSfalse; 934347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt active->IPv6Available = mDNSfalse; 934447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = m->HostInterfaces; intf; intf = intf->next) 934547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->InterfaceID == active->InterfaceID) 934647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 934747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->ip.type == mDNSAddrType_IPv4 && intf->McastTxRx) active->IPv4Available = mDNStrue; 934847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->ip.type == mDNSAddrType_IPv6 && intf->McastTxRx) active->IPv6Available = mDNStrue; 934947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 935047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 935147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 935247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void RestartRecordGetZoneData(mDNS * const m) 935347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 935447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 935547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("RestartRecordGetZoneData: ResourceRecords"); 935647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 935747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (AuthRecord_uDNS(rr) && rr->state != regState_NoTarget) 935847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 935947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", rr->resrec.name->c); 936047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Zero out the updateid so that if we have a pending response from the server, it won't 936147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // be accepted as a valid response. If we accept the response, we might free the new "nta" 936247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->nta) { rr->updateid = zeroID; CancelGetZoneData(m, rr->nta); } 936347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr); 936447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 936547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 936647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 936747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void InitializeNetWakeState(mDNS *const m, NetworkInterfaceInfo *set) 936847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 936947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 937047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->NetWakeBrowse.ThisQInterval = -1; 937147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<3; i++) 937247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 937347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->NetWakeResolve[i].ThisQInterval = -1; 937447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->SPSAddr[i].type = mDNSAddrType_None; 937547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 937647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->NextSPSAttempt = -1; 937747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->NextSPSAttemptTime = m->timenow; 937847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 937947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 938047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_ActivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set) 938147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 938247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *p = m->HostInterfaces; 938347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (p && p != set) p=p->next; 938447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!p) { LogMsg("mDNS_ActivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set); return; } 938547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 938647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->InterfaceActive) 938747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 938847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("ActivateNetWake for %s (%#a)", set->ifname, &set->ip); 938947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StartBrowse_internal(m, &set->NetWakeBrowse, &SleepProxyServiceType, &localdomain, set->InterfaceID, mDNSfalse, m->SPSBrowseCallback, set); 939047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 939147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 939247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 939347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set) 939447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 939547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *p = m->HostInterfaces; 939647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (p && p != set) p=p->next; 939747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!p) { LogMsg("mDNS_DeactivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set); return; } 939847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 939947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->NetWakeBrowse.ThisQInterval >= 0) 940047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 940147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 940247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("DeactivateNetWake for %s (%#a)", set->ifname, &set->ip); 940347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 940447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Stop our browse and resolve operations 940547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopQuery_internal(m, &set->NetWakeBrowse); 940647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<3; i++) if (set->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery_internal(m, &set->NetWakeResolve[i]); 940747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 940847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Make special call to the browse callback to let it know it can to remove all records for this interface 940947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SPSBrowseCallback) 941047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 941147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 941247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSBrowseCallback(m, &set->NetWakeBrowse, mDNSNULL, mDNSfalse); 941347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 941447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 941547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 941647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Reset our variables back to initial state, so we're ready for when NetWake is turned back on 941747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (includes resetting NetWakeBrowse.ThisQInterval back to -1) 941847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeNetWakeState(m, set); 941947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 942047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 942147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 942247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping) 942347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 942447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 942547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool FirstOfType = mDNStrue; 942647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo **p = &m->HostInterfaces; 942747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 942847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!set->InterfaceID) 942947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { LogMsg("mDNS_RegisterInterface: Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set->ip); return(mStatus_Invalid); } 943047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 943147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSAddressIsValidNonZero(&set->mask)) 943247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { LogMsg("mDNS_RegisterInterface: Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set->ip, &set->mask); return(mStatus_Invalid); } 943347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 943447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 943547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 943647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Assume this interface will be active now, unless we find a duplicate already in the list 943747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->InterfaceActive = mDNStrue; 943847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->IPv4Available = (mDNSu8)(set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx); 943947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->IPv6Available = (mDNSu8)(set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx); 944047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 944147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeNetWakeState(m, set); 944247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 944347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Scan list to see if this InterfaceID is already represented 944447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*p) 944547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 944647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (*p == set) 944747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 944847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_RegisterInterface: Error! Tried to register a NetworkInterfaceInfo that's already in the list"); 944947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 945047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_AlreadyRegistered); 945147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 945247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 945347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((*p)->InterfaceID == set->InterfaceID) 945447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 945547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now 945647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->InterfaceActive = mDNSfalse; 945747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->ip.type == (*p)->ip.type) FirstOfType = mDNSfalse; 945847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx) (*p)->IPv4Available = mDNStrue; 945947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx) (*p)->IPv6Available = mDNStrue; 946047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 946147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 946247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt p=&(*p)->next; 946347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 946447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 946547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->next = mDNSNULL; 946647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *p = set; 946747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 946847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->Advertise) 946947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AdvertiseInterface(m, set); 947047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 947147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip, 947247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->InterfaceActive ? 947347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "not represented in list; marking active and retriggering queries" : 947447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt "already represented in list; marking inactive for now"); 947547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 947647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->NetWake) mDNS_ActivateNetWake_internal(m, set); 947747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 947847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off, 947947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // giving the false impression that there's an active representative of this interface when there really isn't. 948047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records, 948147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // even if we believe that we previously had an active representative of this interface. 948247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->McastTxRx && (FirstOfType || set->InterfaceActive)) 948347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 948447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 948547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Normally, after an interface comes up, we pause half a second before beginning probing. 948647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This is to guard against cases where there's rapid interface changes, where we could be confused by 948747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // seeing packets we ourselves sent just moments ago (perhaps when this interface had a different address) 948847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which are then echoed back after a short delay by some Ethernet switches and some 802.11 base stations. 948947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We don't want to do a probe, and then see a stale echo of an announcement we ourselves sent, 949047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and think it's a conflicting answer to our probe. 949147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In the case of a flapping interface, we pause for five seconds, and reduce the announcement count to one packet. 949247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSs32 probedelay = flapping ? mDNSPlatformOneSecond * 5 : mDNSPlatformOneSecond / 2; 949347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 numannounce = flapping ? (mDNSu8)1 : InitialAnnounceCount; 949447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 949547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Use a small amount of randomness: 949647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In the case of a network administrator turning on an Ethernet hub so that all the 949747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // connected machines establish link at exactly the same time, we don't want them all 949847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to go and hit the network with identical queries at exactly the same moment. 949947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We set a random delay of up to InitialQuestionInterval (1/3 second). 950047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We must *never* set m->SuppressSending to more than that (or set it repeatedly in a way 950147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that causes mDNSResponder to remain in a prolonged state of SuppressSending, because 950247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // suppressing packet sending for more than about 1/3 second can cause protocol correctness 950347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to start to break down (e.g. we don't answer probes fast enough, and get name conflicts). 950447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // See <rdar://problem/4073853> mDNS: m->SuppressSending set too enthusiastically 950547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval); 950647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 950747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (flapping) LogMsg("mDNS_RegisterInterface: Frequent transitions for interface %s (%#a)", set->ifname, &set->ip); 950847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 950947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_RegisterInterface: %s (%#a) probedelay %d", set->ifname, &set->ip, probedelay); 951047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SuppressProbes == 0 || 951147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressProbes - NonZeroTime(m->timenow + probedelay) < 0) 951247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressProbes = NonZeroTime(m->timenow + probedelay); 951347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 951447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Include OWNER option in packets for 60 seconds after connecting to the network. Setting 951547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // it here also handles the wake up case as the network link comes UP after waking causing 951647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // us to reconnect to the network. If we do this as part of the wake up code, it is possible 951747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that the network link comes UP after 60 seconds and we never set the OWNER option 951847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->AnnounceOwner = NonZeroTime(m->timenow + 60 * mDNSPlatformOneSecond); 951947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_RegisterInterface: Setting AnnounceOwner"); 952047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 952147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) // Scan our list of questions 952247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSOpaque16IsZero(q->TargetQID)) 952347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface, 952447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { // then reactivate this question 952547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If flapping, delay between first and second queries is nine seconds instead of one second 952647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID); 952747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 initial = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval; 952847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 qdelay = dodelay ? mDNSPlatformOneSecond * 5 : 0; 952947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (dodelay) LogInfo("No cache records expired for %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype)); 953047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 953147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q->ThisQInterval || q->ThisQInterval > initial) 953247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 953347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->ThisQInterval = initial; 953447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it 953547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 953647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->LastQTime = m->timenow - q->ThisQInterval + qdelay; 953747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->RecentAnswerPkts = 0; 953847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextQueryTime(m,q); 953947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 954047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 954147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For all our non-specific authoritative resource records (and any dormant records specific to this interface) 954247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we now need them to re-probe if necessary, and then re-announce. 954347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 954447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!AuthRecord_uDNS(rr)) 954547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == set->InterfaceID) 954647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 954747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; 954847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 954947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->AnnounceCount < numannounce) rr->AnnounceCount = numannounce; 955047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->SendNSECNow = mDNSNULL; 955147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeLastAPTime(m, rr); 955247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 955347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 955447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 955547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RestartRecordGetZoneData(m); 955647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 955747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CheckSuppressUnusableQuestions(m); 955847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 955947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_UpdateAllowSleep(m); 956047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 956147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 956247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); 956347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 956447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 956547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change 956647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// the record list and/or question list. 956747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 956847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping) 956947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 957047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo **p = &m->HostInterfaces; 957147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool revalidate = mDNSfalse; 957247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 957347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 957447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 957547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Find this record in our list 957647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*p && *p != set) p=&(*p)->next; 957747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!*p) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m); return; } 957847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 957947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DeactivateNetWake_internal(m, set); 958047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 958147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Unlink this record from our list 958247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *p = (*p)->next; 958347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt set->next = mDNSNULL; 958447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 958547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!set->InterfaceActive) 958647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 958747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this interface not the active member of its set, update the v4/v6Available flags for the active member 958847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf; 958947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = m->HostInterfaces; intf; intf = intf->next) 959047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->InterfaceActive && intf->InterfaceID == set->InterfaceID) 959147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt UpdateInterfaceProtocols(m, intf); 959247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 959347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 959447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 959547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf = FirstInterfaceForID(m, set->InterfaceID); 959647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf) 959747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 959847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;" 959947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt " making it active", set->InterfaceID, set->ifname, &set->ip); 960047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->InterfaceActive) 960147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_DeregisterInterface: ERROR intf->InterfaceActive already set for %s (%#a)", set->ifname, &set->ip); 960247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->InterfaceActive = mDNStrue; 960347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt UpdateInterfaceProtocols(m, intf); 960447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 960547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->NetWake) mDNS_ActivateNetWake_internal(m, intf); 960647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 960747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // See if another representative *of the same type* exists. If not, we mave have gone from 960847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid. 960947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = m->HostInterfaces; intf; intf = intf->next) 961047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->InterfaceID == set->InterfaceID && intf->ip.type == set->ip.type) 961147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 961247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!intf) revalidate = mDNStrue; 961347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 961447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 961547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 961647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 961747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg; 961847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr; 961947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 962047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSServer *s; 962147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 962247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;" 962347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt " marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip); 962447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 962547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->McastTxRx && flapping) 962647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("DeregisterInterface: Frequent transitions for interface %s (%#a)", set->ifname, &set->ip); 962747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 962847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. Deactivate any questions specific to this interface, and tag appropriate questions 962947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them 963047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) 963147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 963247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0; 963347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) 963447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 963547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->FlappingInterface2 = q->FlappingInterface1; 963647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->FlappingInterface1 = set->InterfaceID; // Keep history of the last two interfaces to go away 963747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 963847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 963947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 964047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. Flush any cache records received on this interface 964147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt revalidate = mDNSfalse; // Don't revalidate if we're flushing the records 964247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt FORALL_CACHERECORDS(slot, cg, rr) 964347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID == set->InterfaceID) 964447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 964547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this interface is deemed flapping, 964647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // postpone deleting the cache records in case the interface comes back again 964747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->McastTxRx && flapping) 964847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 964947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For a flapping interface we want these record to go away after 30 seconds 965047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface); 965147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them -- 965247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if the interface does come back, any relevant questions will be reactivated anyway 965347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->UnansweredQueries = MaxUnansweredQueries; 965447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 965547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 965647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_PurgeCacheResourceRecord(m, rr); 965747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 965847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 965947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3. Any DNS servers specific to this interface are now unusable 966047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (s = m->DNSServers; s; s = s->next) 966147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (s->interface == set->InterfaceID) 966247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 966347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt s->interface = mDNSInterface_Any; 966447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt s->teststate = DNSServer_Disabled; 966547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 966647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 966747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 966847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 966947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we were advertising on this interface, deregister those address and reverse-lookup records now 967047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (set->Advertise) DeadvertiseInterface(m, set); 967147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 967247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we have any cache records received on this interface that went away, then re-verify them. 967347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off, 967447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // giving the false impression that there's an active representative of this interface when there really isn't. 967547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't need to do this when shutting down, because *all* interfaces are about to go away 967647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (revalidate && !m->ShutdownTime) 967747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 967847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 967947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg; 968047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rr; 968147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt FORALL_CACHERECORDS(slot, cg, rr) 968247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID == set->InterfaceID) 968347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface); 968447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 968547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 968647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CheckSuppressUnusableQuestions(m); 968747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 968847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_UpdateAllowSleep(m); 968947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 969047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 969147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 969247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 969347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 969447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 969547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext; 969647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (void)m; // Unused parameter 969747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 969847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #if MDNS_DEBUGMSGS 969947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 970047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt char *msg = "Unknown result"; 970147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (result == mStatus_NoError) msg = "Name Registered"; 970247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (result == mStatus_NameConflict) msg = "Name Conflict"; 970347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (result == mStatus_MemFree) msg = "Memory Free"; 970447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("ServiceCallback: %##s (%s) %s (%d)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result); 970547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 970647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #endif 970747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 970847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Only pass on the NoError acknowledgement for the SRV record (when it finishes probing) 970947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (result == mStatus_NoError && rr != &sr->RR_SRV) return; 971047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 971147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that 971247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (result == mStatus_NameConflict) 971347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 971447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->Conflict = mDNStrue; // Record that this service set had a conflict 971547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DeregisterService(m, sr); // Unlink the records from our list 971647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 971747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 971847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 971947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (result == mStatus_MemFree) 972047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 972147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the SRV/TXT/PTR records, or the _services._dns-sd._udp record, or any of the subtype PTR records, 972247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // are still in the process of deregistering, don't pass on the NameConflict/MemFree message until 972347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // every record is finished cleaning up. 972447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 i; 972547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ExtraResourceRecord *e = sr->Extras; 972647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 972747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sr->RR_SRV.resrec.RecordType != kDNSRecordTypeUnregistered) return; 972847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sr->RR_TXT.resrec.RecordType != kDNSRecordTypeUnregistered) return; 972947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return; 973047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sr->RR_ADV.resrec.RecordType != kDNSRecordTypeUnregistered) return; 973147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<sr->NumSubTypes; i++) if (sr->SubTypes[i].resrec.RecordType != kDNSRecordTypeUnregistered) return; 973247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 973347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (e) 973447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 973547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (e->r.resrec.RecordType != kDNSRecordTypeUnregistered) return; 973647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt e = e->next; 973747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 973847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 973947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse, 974047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // then we can now report the NameConflict to the client 974147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sr->Conflict) result = mStatus_NameConflict; 974247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 974347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 974447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 974547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("ServiceCallback: All records %s for %##s", (result == mStatus_MemFree ? "Unregistered": "Registered"), sr->RR_PTR.resrec.name->c); 974647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback 974747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // function is allowed to do anything, including deregistering this service and freeing its memory. 974847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sr->ServiceCallback) 974947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->ServiceCallback(m, sr, result); 975047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 975147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 975247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 975347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 975447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext; 975547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sr->ServiceCallback) 975647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->ServiceCallback(m, sr, result); 975747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 975847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 975947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: 976047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Name is first label of domain name (any dots in the name are actual dots, not label separators) 976147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Type is service type (e.g. "_ipp._tcp.") 976247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Domain is fully qualified domain name (i.e. ending with a null label) 976347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// We always register a TXT, even if it is empty (so that clients are not 976447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// left waiting forever looking for a nonexistent record.) 976547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If the host parameter is mDNSNULL or the root domain (ASCII NUL), 976647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// then the default host name (m->MulticastHostname) is automatically used 976747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If the optional target host parameter is set, then the storage it points to must remain valid for the lifetime of the service registration 976847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, 976947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainlabel *const name, const domainname *const type, const domainname *const domain, 977047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen, 977147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *SubTypes, mDNSu32 NumSubTypes, 977247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context, mDNSu32 flags) 977347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 977447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus err; 977547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 i; 977647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 hostTTL; 977747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecType artype; 977847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu8 recordType = (flags & regFlagKnownUnique) ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique; 977947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 978047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->ServiceCallback = Callback; 978147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->ServiceContext = Context; 978247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->Conflict = mDNSfalse; 978347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 978447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->Extras = mDNSNULL; 978547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->NumSubTypes = NumSubTypes; 978647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->SubTypes = SubTypes; 978747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 978847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (InterfaceID == mDNSInterface_LocalOnly) 978947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordLocalOnly; 979047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (InterfaceID == mDNSInterface_P2P) 979147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordP2P; 979247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if ((InterfaceID == mDNSInterface_Any) && (flags & regFlagIncludeP2P)) 979347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordAnyIncludeP2P; 979447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 979547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordAny; 979647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 979747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Initialize the AuthRecord objects to sane values 979847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Need to initialize everything correctly *before* making the decision whether to do a RegisterNoSuchService and bail out 979947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, artype, ServiceCallback, sr); 980047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, artype, ServiceCallback, sr); 980147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 980247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameDomainName(type, (const domainname *) "\x4" "_ubd" "\x4" "_tcp")) 980347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt hostTTL = kHostNameSmallTTL; 980447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 980547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt hostTTL = kHostNameTTL; 980647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 980747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, hostTTL, recordType, artype, ServiceCallback, sr); 980847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique, artype, ServiceCallback, sr); 980947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 981047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If port number is zero, that means the client is really trying to do a RegisterNoSuchService 981147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSIPPortIsZero(port)) 981247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, InterfaceID, NSSCallback, sr, (flags & regFlagIncludeP2P))); 981347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 981447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the client is registering an oversized TXT record, 981547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it 981647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen) 981747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->RR_TXT.resrec.rdata->MaxRDLength = txtlen; 981847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 981947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Set up the record names 982047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For now we only create an advisory record for the main type, not for subtypes 982147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We need to gain some operational experience before we decide if there's a need to create them for subtypes too 982247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ConstructServiceName(&sr->RR_ADV.namestorage, (const domainlabel*)"\x09_services", (const domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL) 982347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_BadParamErr); 982447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ConstructServiceName(&sr->RR_PTR.namestorage, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr); 982547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ConstructServiceName(&sr->RR_SRV.namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr); 982647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&sr->RR_TXT.namestorage, sr->RR_SRV.resrec.name); 982747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 982847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. Set up the ADV record rdata to advertise our service type 982947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name); 983047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 983147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. Set up the PTR record rdata to point to our service name 983247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too 983347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: uDNS registration code assumes that Additional1 points to the SRV record 983447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&sr->RR_PTR.resrec.rdata->u.name, sr->RR_SRV.resrec.name); 983547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->RR_PTR.Additional1 = &sr->RR_SRV; 983647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->RR_PTR.Additional2 = &sr->RR_TXT; 983747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 983847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2a. Set up any subtype PTRs to point to our service name 983947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the client is using subtypes, it is the client's responsibility to have 984047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // already set the first label of the record name to the subtype being registered 984147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<NumSubTypes; i++) 984247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 984347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainname st; 984447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&st, sr->SubTypes[i].resrec.name); 984547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt st.c[1+st.c[0]] = 0; // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService()) 984647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AppendDomainName(&st, type); 984747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, artype, ServiceCallback, sr); 984847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ConstructServiceName(&sr->SubTypes[i].namestorage, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr); 984947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, &sr->RR_SRV.namestorage); 985047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->SubTypes[i].Additional1 = &sr->RR_SRV; 985147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->SubTypes[i].Additional2 = &sr->RR_TXT; 985247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 985347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 985447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3. Set up the SRV record rdata. 985547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->RR_SRV.resrec.rdata->u.srv.priority = 0; 985647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->RR_SRV.resrec.rdata->u.srv.weight = 0; 985747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->RR_SRV.resrec.rdata->u.srv.port = port; 985847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 985947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Setting AutoTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name 986047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (host && host->c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, host); 986147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else { sr->RR_SRV.AutoTarget = Target_AutoHost; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; } 986247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 986347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 4. Set up the TXT record rdata, 986447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us 986547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: uDNS registration code assumes that DependentOn points to the SRV record 986647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (txtinfo == mDNSNULL) sr->RR_TXT.resrec.rdlength = 0; 986747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (txtinfo != sr->RR_TXT.resrec.rdata->u.txt.c) 986847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 986947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->RR_TXT.resrec.rdlength = txtlen; 987047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sr->RR_TXT.resrec.rdlength > sr->RR_TXT.resrec.rdata->MaxRDLength) return(mStatus_BadParamErr); 987147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemCopy(sr->RR_TXT.resrec.rdata->u.txt.c, txtinfo, txtlen); 987247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 987347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->RR_TXT.DependentOn = &sr->RR_SRV; 987447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 987547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 987647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // It is important that we register SRV first. uDNS assumes that SRV is registered first so 987747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that if the SRV cannot find a target, rest of the records that belong to this service 987847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // will not be activated. 987947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt err = mDNS_Register_internal(m, &sr->RR_SRV); 988047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we can't register the SRV record due to errors, bail out. It has not been inserted in 988147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // any list and hence no need to deregister. We could probably do similar checks for other 988247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // records below and bail out. For now, this seems to be sufficient to address rdar://9304275 988347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (err) 988447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 988547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 988647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return err; 988747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 988847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT); 988947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We register the RR_PTR last, because we want to be sure that in the event of a forced call to 989047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // mDNS_StartExit, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers 989147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to 989247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to 989347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // make sure we've deregistered all our records and done any other necessary cleanup before that happens. 989447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!err) err = mDNS_Register_internal(m, &sr->RR_ADV); 989547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<NumSubTypes; i++) if (!err) err = mDNS_Register_internal(m, &sr->SubTypes[i]); 989647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!err) err = mDNS_Register_internal(m, &sr->RR_PTR); 989747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 989847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 989947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 990047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (err) mDNS_DeregisterService(m, sr); 990147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(err); 990247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 990347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 990447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, 990547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl, mDNSu32 includeP2P) 990647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 990747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ExtraResourceRecord **e; 990847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus status; 990947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecType artype; 991047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSInterfaceID InterfaceID = sr->RR_PTR.resrec.InterfaceID; 991147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 991247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (InterfaceID == mDNSInterface_LocalOnly) 991347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordLocalOnly; 991447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (InterfaceID == mDNSInterface_P2P) 991547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordP2P; 991647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if ((InterfaceID == mDNSInterface_Any) && includeP2P) 991747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordAnyIncludeP2P; 991847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 991947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordAny; 992047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 992147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt extra->next = mDNSNULL; 992247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID, 992347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, artype, ServiceCallback, sr); 992447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&extra->r.namestorage, sr->RR_SRV.resrec.name); 992547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 992647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 992747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt e = &sr->Extras; 992847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*e) e = &(*e)->next; 992947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 993047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ttl == 0) ttl = kStandardTTL; 993147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 993247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt extra->r.DependentOn = &sr->RR_SRV; 993347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 993447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_AddRecordToService adding record to %##s %s %d", 993547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt extra->r.resrec.name->c, DNSTypeName(extra->r.resrec.rrtype), extra->r.resrec.rdlength); 993647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 993747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt status = mDNS_Register_internal(m, &extra->r); 993847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (status == mStatus_NoError) *e = extra; 993947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 994047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 994147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(status); 994247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 994347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 994447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, 994547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSRecordCallback MemFreeCallback, void *Context) 994647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 994747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ExtraResourceRecord **e; 994847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus status; 994947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 995047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 995147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt e = &sr->Extras; 995247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*e && *e != extra) e = &(*e)->next; 995347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!*e) 995447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 995547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra->r.resrec.name->c); 995647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt status = mStatus_BadReferenceErr; 995747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 995847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 995947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 996047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name->c); 996147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt extra->r.RecordCallback = MemFreeCallback; 996247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt extra->r.RecordContext = Context; 996347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *e = (*e)->next; 996447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal); 996547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 996647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 996747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(status); 996847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 996947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 997047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname) 997147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 997247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: Don't need to use mDNS_Lock(m) here, because this code is just using public routines 997347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally. 997447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainlabel name1, name2; 997547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainname type, domain; 997647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainname *host = sr->RR_SRV.AutoTarget ? mDNSNULL : &sr->RR_SRV.resrec.rdata->u.srv.target; 997747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ExtraResourceRecord *extras = sr->Extras; 997847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus err; 997947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 998047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DeconstructServiceName(sr->RR_SRV.resrec.name, &name1, &type, &domain); 998147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!newname) 998247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 998347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt name2 = name1; 998447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt IncrementLabelSuffix(&name2, mDNStrue); 998547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt newname = &name2; 998647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 998747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 998847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameDomainName(&domain, &localdomain)) 998947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c); 999047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else debugf("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c); 999147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 999247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt err = mDNS_RegisterService(m, sr, newname, &type, &domain, 999347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt host, sr->RR_SRV.resrec.rdata->u.srv.port, sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength, 999447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->SubTypes, sr->NumSubTypes, 999547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->RR_PTR.resrec.InterfaceID, sr->ServiceCallback, sr->ServiceContext, 0); 999647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 999747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // mDNS_RegisterService() just reset sr->Extras to NULL. 999847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Fortunately we already grabbed ourselves a copy of this pointer (above), so we can now run 999947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // through the old list of extra records, and re-add them to our freshly created service registration 1000047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (!err && extras) 1000147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1000247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ExtraResourceRecord *e = extras; 1000347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt extras = extras->next; 1000447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt err = mDNS_AddRecordToService(m, sr, e, e->r.resrec.rdata, e->r.resrec.rroriginalttl, 0); 1000547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1000647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1000747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(err); 1000847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1000947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1001047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback, 1001147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// which may change the record list and/or question list. 1001247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 1001347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_DeregisterService_drt(mDNS *const m, ServiceRecordSet *sr, mDNS_Dereg_type drt) 1001447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1001547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService() 1001647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSIPPortIsZero(sr->RR_SRV.resrec.rdata->u.srv.port)) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV)); 1001747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1001847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered) 1001947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1002047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name->c); 1002147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_BadReferenceErr); 1002247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1002347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering) 1002447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1002547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c); 1002647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Avoid race condition: 1002747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If a service gets a conflict, then we set the Conflict flag to tell us to generate 1002847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record. 1002947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the client happens to deregister the service in the middle of that process, then 1003047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we clear the flag back to the normal state, so that we deliver a plain mStatus_MemFree 1003147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // instead of incorrectly promoting it to mStatus_NameConflict. 1003247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This race condition is exposed particularly when the conformance test generates 1003347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // a whole batch of simultaneous conflicts across a range of services all advertised 1003447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // using the same system default name, and if we don't take this precaution then 1003547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we end up incrementing m->nicelabel multiple times instead of just once. 1003647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision 1003747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sr->Conflict = mDNSfalse; 1003847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mStatus_NoError); 1003947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1004047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1004147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1004247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 i; 1004347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus status; 1004447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ExtraResourceRecord *e; 1004547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 1004647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt e = sr->Extras; 1004747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1004847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We use mDNS_Dereg_repeat because, in the event of a collision, some or all of the 1004947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay 1005047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat); 1005147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat); 1005247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1005347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, &sr->RR_ADV, drt); 1005447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1005547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We deregister all of the extra records, but we leave the sr->Extras list intact 1005647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // in case the client wants to do a RenameAndReregister and reinstate the registration 1005747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (e) 1005847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1005947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, &e->r, mDNS_Dereg_repeat); 1006047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt e = e->next; 1006147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1006247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1006347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<sr->NumSubTypes; i++) 1006447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, &sr->SubTypes[i], drt); 1006547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1006647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt status = mDNS_Deregister_internal(m, &sr->RR_PTR, drt); 1006747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 1006847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(status); 1006947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1007047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1007147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1007247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Create a registration that asserts that no such service exists with this name. 1007347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// This can be useful where there is a given function is available through several protocols. 1007447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// For example, a printer called "Stuart's Printer" may implement printing via the "pdl-datastream" and "IPP" 1007547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// protocols, but not via "LPR". In this case it would be prudent for the printer to assert the non-existence of an 1007647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// "LPR" service called "Stuart's Printer". Without this precaution, another printer than offers only "LPR" printing 1007747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// could inadvertently advertise its service under the same name "Stuart's Printer", which might be confusing for users. 1007847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr, 1007947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainlabel *const name, const domainname *const type, const domainname *const domain, 1008047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const domainname *const host, 1008147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context, mDNSBool includeP2P) 1008247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1008347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecType artype; 1008447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1008547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (InterfaceID == mDNSInterface_LocalOnly) 1008647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordLocalOnly; 1008747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (InterfaceID == mDNSInterface_P2P) 1008847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordP2P; 1008947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if ((InterfaceID == mDNSInterface_Any) && includeP2P) 1009047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordAnyIncludeP2P; 1009147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1009247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordAny; 1009347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1009447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, artype, Callback, Context); 1009547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ConstructServiceName(&rr->namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr); 1009647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rdata->u.srv.priority = 0; 1009747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rdata->u.srv.weight = 0; 1009847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.rdata->u.srv.port = zeroIPPort; 1009947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (host && host->c[0]) AssignDomainName(&rr->resrec.rdata->u.srv.target, host); 1010047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else rr->AutoTarget = Target_AutoHost; 1010147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNS_Register(m, rr)); 1010247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1010347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1010447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, 1010547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname) 1010647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1010747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecType artype; 1010847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1010947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (InterfaceID == mDNSInterface_LocalOnly) 1011047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordLocalOnly; 1011147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (InterfaceID == mDNSInterface_P2P) 1011247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordP2P; 1011347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1011447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt artype = AuthRecordAny; 1011547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, artype, mDNSNULL, mDNSNULL); 1011647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!MakeDomainNameFromDNSNameString(&rr->namestorage, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr); 1011747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname)) return(mStatus_BadParamErr); 1011847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(mDNS_Register(m, rr)); 1011947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1012047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1012147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool mDNS_IdUsedInResourceRecordsList(mDNS * const m, mDNSOpaque16 id) 1012247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1012347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *r; 1012447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r = m->ResourceRecords; r; r=r->next) if (mDNSSameOpaque16(id, r->updateid)) return mDNStrue; 1012547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNSfalse; 1012647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1012747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1012847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool mDNS_IdUsedInQuestionsList(mDNS * const m, mDNSOpaque16 id) 1012947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1013047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 1013147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) if (mDNSSameOpaque16(id, q->TargetQID)) return mDNStrue; 1013247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNSfalse; 1013347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1013447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1013547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSOpaque16 mDNS_NewMessageID(mDNS * const m) 1013647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1013747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSOpaque16 id; 1013847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int i; 1013947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1014047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<10; i++) 1014147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1014247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt id = mDNSOpaque16fromIntVal(1 + (mDNSu16)mDNSRandom(0xFFFE)); 1014347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNS_IdUsedInResourceRecordsList(m, id) && !mDNS_IdUsedInQuestionsList(m, id)) break; 1014447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1014547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1014647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_NewMessageID: %5d", mDNSVal16(id)); 1014747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1014847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return id; 1014947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1015047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1015147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// *************************************************************************** 1015247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK 1015347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - 1015447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Sleep Proxy Server 1015547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 1015647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1015747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void RestartARPProbing(mDNS *const m, AuthRecord *const rr) 1015847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1015947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we see an ARP from a machine we think is sleeping, then either 1016047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (i) the machine has woken, or 1016147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (ii) it's just a stray old packet from before the machine slept 1016247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // To handle the second case, we reset ProbeCount, so we'll suppress our own answers for a while, to avoid 1016347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // generating ARP conflicts with a waking machine, and set rr->LastAPTime so we'll start probing again in 10 seconds. 1016447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the machine has just woken then we'll discard our records when we see the first new mDNS probe from that machine. 1016547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If it was a stray old packet, then after 10 seconds we'll probe again and then start answering ARPs again. In this case we *do* 1016647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // need to send new ARP Announcements, because the owner's ARP broadcasts will have updated neighboring ARP caches, so we need to 1016747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // re-assert our (temporary) ownership of that IP address in order to receive subsequent packets addressed to that IPv4 address. 1016847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1016947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.RecordType = kDNSRecordTypeUnique; 1017047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ProbeCount = DefaultProbeCountForTypeUnique; 1017147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1017247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we haven't started announcing yet (and we're not already in ten-second-delay mode) the machine is probably 1017347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // still going to sleep, so we just reset rr->ProbeCount so we'll continue probing until it stops responding. 1017447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we *have* started announcing, the machine is probably in the process of waking back up, so in that case 1017547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we're more cautious and we wait ten seconds before probing it again. We do this because while waking from 1017647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // sleep, some network interfaces tend to lose or delay inbound packets, and without this delay, if the waking machine 1017747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // didn't answer our three probes within three seconds then we'd announce and cause it an unnecessary address conflict. 1017847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->AnnounceCount == InitialAnnounceCount && m->timenow - rr->LastAPTime >= 0) 1017947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InitializeLastAPTime(m, rr); 1018047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1018147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1018247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount = InitialAnnounceCount; 1018347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->ThisAPInterval = mDNSPlatformOneSecond; 1018447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastAPTime = m->timenow + mDNSPlatformOneSecond * 9; // Send first packet at rr->LastAPTime + rr->ThisAPInterval, i.e. 10 seconds from now 1018547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetNextAnnounceProbeTime(m, rr); 1018647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1018747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1018847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1018947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void mDNSCoreReceiveRawARP(mDNS *const m, const ARP_EthIP *const arp, const mDNSInterfaceID InterfaceID) 1019047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1019147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const mDNSOpaque16 ARP_op_request = { { 0, 1 } }; 1019247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 1019347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); 1019447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!intf) return; 1019547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1019647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 1019747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1019847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Pass 1: 1019947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Process ARP Requests and Probes (but not Announcements), and generate an ARP Reply if necessary. 1020047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We also process ARPs from our own kernel (and 'answer' them by injecting a local ARP table entry) 1020147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them. 1020247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The times we might need to react to an ARP Announcement are: 1020347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (i) as an indication that the host in question has not gone to sleep yet (so we should delay beginning to proxy for it) or 1020447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (ii) if it's a conflicting Announcement from another host 1020547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // -- and we check for these in Pass 2 below. 1020647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameOpaque16(arp->op, ARP_op_request) && !mDNSSameIPv4Address(arp->spa, arp->tpa)) 1020747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1020847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 1020947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering && 1021047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->tpa)) 1021147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1021247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const char msg1[] = "ARP Req from owner -- re-probing"; 1021347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const char msg2[] = "Ignoring ARP Request from "; 1021447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const char msg3[] = "Creating Local ARP Cache entry "; 1021547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const char msg4[] = "Answering ARP Request from "; 1021647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *const msg = mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC) ? msg1 : 1021747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rr->AnnounceCount == InitialAnnounceCount) ? msg2 : 1021847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSSameEthAddress(&arp->sha, &intf->MAC) ? msg3 : msg4; 1021947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("%-7s %s %.6a %.4a for %.4a -- H-MAC %.6a I-MAC %.6a %s", 1022047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->ifname, msg, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr)); 1022147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (msg == msg1) RestartARPProbing(m, rr); 1022247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (msg == msg3) mDNSPlatformSetLocalAddressCacheEntry(m, &rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID); 1022347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (msg == msg4) SendARP(m, 2, rr, &arp->tpa, &arp->sha, &arp->spa, &arp->sha); 1022447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1022547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1022647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1022747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Pass 2: 1022847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For all types of ARP packet we check the Sender IP address to make sure it doesn't conflict with any AddressProxy record we're holding. 1022947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (Strictly speaking we're only checking Announcement/Request/Reply packets, since ARP Probes have zero Sender IP address, 1023047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // so by definition (and by design) they can never conflict with any real (i.e. non-zero) IP address). 1023147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We ignore ARPs we sent ourselves (Sender MAC address is our MAC address) because our own proxy ARPs do not constitute a conflict that we need to handle. 1023247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we see an apparently conflicting ARP, we check the sender hardware address: 1023347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the sender hardware address is the original owner this is benign, so we just suppress our own proxy answering for a while longer. 1023447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the sender hardware address is *not* the original owner, then this is a conflict, and we need to wake the sleeping machine to handle it. 1023547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameEthAddress(&arp->sha, &intf->MAC)) 1023647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("ARP from self for %.4a", &arp->tpa); 1023747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1023847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1023947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSSameIPv4Address(arp->spa, zerov4Addr)) 1024047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 1024147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering && 1024247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->spa)) 1024347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1024447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RestartARPProbing(m, rr); 1024547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC)) 1024647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("%-7s ARP %s from owner %.6a %.4a for %-15.4a -- re-starting probing for %s", intf->ifname, 1024747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSSameIPv4Address(arp->spa, arp->tpa) ? "Announcement " : mDNSSameOpaque16(arp->op, ARP_op_request) ? "Request " : "Response ", 1024847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt &arp->sha, &arp->spa, &arp->tpa, ARDisplayString(m, rr)); 1024947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1025047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1025147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("%-7s Conflicting ARP from %.6a %.4a for %.4a -- waking H-MAC %.6a I-MAC %.6a %s", intf->ifname, 1025247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr)); 1025347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ScheduleWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.HMAC); 1025447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1025547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1025647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1025747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1025847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 1025947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1026047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1026147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt/* 1026247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Option 1 is Source Link Layer Address Option 1026347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Option 2 is Target Link Layer Address Option 1026447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal const mDNSEthAddr *GetLinkLayerAddressOption(const IPv6NDP *const ndp, const mDNSu8 *const end, mDNSu8 op) 1026547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1026647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *options = (mDNSu8 *)(ndp+1); 1026747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (options < end) 1026847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1026947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("NDP Option %02X len %2d %d", options[0], options[1], end - options); 1027047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (options[0] == op && options[1] == 1) return (const mDNSEthAddr*)(options+2); 1027147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt options += options[1] * 8; 1027247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1027347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mDNSNULL; 1027447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1027547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt*/ 1027647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1027747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void mDNSCoreReceiveRawND(mDNS *const m, const mDNSEthAddr *const sha, const mDNSv6Addr *spa, 1027847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const IPv6NDP *const ndp, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID) 1027947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1028047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 1028147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); 1028247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!intf) return; 1028347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1028447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 1028547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1028647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Pass 1: Process Neighbor Solicitations, and generate a Neighbor Advertisement if necessary. 1028747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ndp->type == NDP_Sol) 1028847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1028947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt //const mDNSEthAddr *const sha = GetLinkLayerAddressOption(ndp, end, NDP_SrcLL); 1029047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (void)end; 1029147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 1029247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering && 1029347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AddressProxy.type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->AddressProxy.ip.v6, ndp->target)) 1029447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1029547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const char msg1[] = "NDP Req from owner -- re-probing"; 1029647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const char msg2[] = "Ignoring NDP Request from "; 1029747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const char msg3[] = "Creating Local NDP Cache entry "; 1029847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const char msg4[] = "Answering NDP Request from "; 1029947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const char msg5[] = "Answering NDP Probe from "; 1030047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const char *const msg = sha && mDNSSameEthAddress(sha, &rr->WakeUp.IMAC) ? msg1 : 1030147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rr->AnnounceCount == InitialAnnounceCount) ? msg2 : 1030247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sha && mDNSSameEthAddress(sha, &intf->MAC) ? msg3 : 1030347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt spa && mDNSIPv6AddressIsZero(*spa) ? msg4 : msg5; 1030447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("%-7s %s %.6a %.16a for %.16a -- H-MAC %.6a I-MAC %.6a %s", 1030547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt intf->ifname, msg, sha, spa, &ndp->target, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr)); 1030647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (msg == msg1) RestartARPProbing(m, rr); 1030747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (msg == msg3) 1030847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1030947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!(m->KnownBugs & mDNS_KnownBug_LimitedIPv6)) 1031047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformSetLocalAddressCacheEntry(m, &rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID); 1031147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1031247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (msg == msg4) SendNDP(m, NDP_Adv, NDP_Solicited, rr, &ndp->target, mDNSNULL, spa, sha ); 1031347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (msg == msg5) SendNDP(m, NDP_Adv, 0, rr, &ndp->target, mDNSNULL, &AllHosts_v6, &AllHosts_v6_Eth); 1031447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1031547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1031647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1031747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Pass 2: For all types of NDP packet we check the Sender IP address to make sure it doesn't conflict with any AddressProxy record we're holding. 1031847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameEthAddress(sha, &intf->MAC)) 1031947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("NDP from self for %.16a", &ndp->target); 1032047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1032147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1032247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For Neighbor Advertisements we check the Target address field, not the actual IPv6 source address. 1032347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When a machine has both link-local and routable IPv6 addresses, it may send NDP packets making assertions 1032447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // about its routable IPv6 address, using its link-local address as the source address for all NDP packets. 1032547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Hence it is the NDP target address we care about, not the actual packet source address. 1032647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ndp->type == NDP_Adv) spa = &ndp->target; 1032747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSSameIPv6Address(*spa, zerov6Addr)) 1032847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 1032947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering && 1033047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AddressProxy.type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->AddressProxy.ip.v6, *spa)) 1033147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1033247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RestartARPProbing(m, rr); 1033347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameEthAddress(sha, &rr->WakeUp.IMAC)) 1033447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("%-7s NDP %s from owner %.6a %.16a for %.16a -- re-starting probing for %s", intf->ifname, 1033547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ndp->type == NDP_Sol ? "Solicitation " : "Advertisement", sha, spa, &ndp->target, ARDisplayString(m, rr)); 1033647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1033747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1033847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("%-7s Conflicting NDP from %.6a %.16a for %.16a -- waking H-MAC %.6a I-MAC %.6a %s", intf->ifname, 1033947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt sha, spa, &ndp->target, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr)); 1034047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ScheduleWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.HMAC); 1034147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1034247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1034347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1034447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1034547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 1034647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1034747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1034847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void mDNSCoreReceiveRawTransportPacket(mDNS *const m, const mDNSEthAddr *const sha, const mDNSAddr *const src, const mDNSAddr *const dst, const mDNSu8 protocol, 1034947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *const p, const TransportLayerPacket *const t, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID, const mDNSu16 len) 1035047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1035147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSIPPort port = (protocol == 0x06) ? t->tcp.dst : (protocol == 0x11) ? t->udp.dst : zeroIPPort; 1035247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool wake = mDNSfalse; 1035347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1035447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt switch (protocol) 1035547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1035647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #define XX wake ? "Received" : "Ignoring", end-p 1035747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt case 0x01: LogSPS("Ignoring %d-byte ICMP from %#a to %#a", end-p, src, dst); 1035847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 1035947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1036047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt case 0x06: { 1036147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #define SSH_AsNumber 22 1036247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const mDNSIPPort SSH = { { SSH_AsNumber >> 8, SSH_AsNumber & 0xFF } }; 1036347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1036447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Plan to wake if 1036547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (a) RST is not set, AND 1036647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (b) packet is SYN, SYN+FIN, or plain data packet (no SYN or FIN). We won't wake for FIN alone. 1036747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt wake = (!(t->tcp.flags & 4) && (t->tcp.flags & 3) != 1); 1036847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1036947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For now, to reduce spurious wakeups, we wake only for TCP SYN, 1037047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // except for ssh connections, where we'll wake for plain data packets too 1037147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSSameIPPort(port, SSH) && !(t->tcp.flags & 2)) wake = mDNSfalse; 1037247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1037347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("%s %d-byte TCP from %#a:%d to %#a:%d%s%s%s", XX, 1037447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt src, mDNSVal16(t->tcp.src), dst, mDNSVal16(port), 1037547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (t->tcp.flags & 2) ? " SYN" : "", 1037647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (t->tcp.flags & 1) ? " FIN" : "", 1037747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (t->tcp.flags & 4) ? " RST" : ""); 1037847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1037947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 1038047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1038147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt case 0x11: { 1038247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #define ARD_AsNumber 3283 1038347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const mDNSIPPort ARD = { { ARD_AsNumber >> 8, ARD_AsNumber & 0xFF } }; 1038447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu16 udplen = (mDNSu16)((mDNSu16)t->bytes[4] << 8 | t->bytes[5]); // Length *including* 8-byte UDP header 1038547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (udplen >= sizeof(UDPHeader)) 1038647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1038747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu16 datalen = udplen - sizeof(UDPHeader); 1038847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt wake = mDNStrue; 1038947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1039047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For Back to My Mac UDP port 4500 (IPSEC) packets, we do some special handling 1039147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameIPPort(port, IPSECPort)) 1039247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1039347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Specifically ignore NAT keepalive packets 1039447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (datalen == 1 && end >= &t->bytes[9] && t->bytes[8] == 0xFF) wake = mDNSfalse; 1039547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1039647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1039747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Skip over the Non-ESP Marker if present 1039847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSBool NonESP = (end >= &t->bytes[12] && t->bytes[8] == 0 && t->bytes[9] == 0 && t->bytes[10] == 0 && t->bytes[11] == 0); 1039947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const IKEHeader *const ike = (IKEHeader *)(t + (NonESP ? 12 : 8)); 1040047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu16 ikelen = datalen - (NonESP ? 4 : 0); 1040147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ikelen >= sizeof(IKEHeader) && end >= ((mDNSu8 *)ike) + sizeof(IKEHeader)) 1040247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((ike->Version & 0x10) == 0x10) 1040347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1040447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // ExchangeType == 5 means 'Informational' <http://www.ietf.org/rfc/rfc2408.txt> 1040547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // ExchangeType == 34 means 'IKE_SA_INIT' <http://www.iana.org/assignments/ikev2-parameters> 1040647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ike->ExchangeType == 5 || ike->ExchangeType == 34) wake = mDNSfalse; 1040747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("%s %d-byte IKE ExchangeType %d", XX, ike->ExchangeType); 1040847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1040947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1041047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1041147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1041247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the 1041347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port), 1041447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this: 1041547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // UDP header (8 bytes) 1041647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Payload: 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 110 bytes total 1041747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSSameIPPort(port, ARD)) wake = (datalen >= 110 && end >= &t->bytes[10] && t->bytes[8] == 0x13 && t->bytes[9] == 0x88); 1041847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1041947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("%s %d-byte UDP from %#a:%d to %#a:%d", XX, src, mDNSVal16(t->udp.src), dst, mDNSVal16(port)); 1042047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1042147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1042247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 1042347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1042447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt case 0x3A: if (&t->bytes[len] <= end) 1042547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1042647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu16 checksum = IPv6CheckSum(&src->ip.v6, &dst->ip.v6, protocol, t->bytes, len); 1042747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!checksum) mDNSCoreReceiveRawND(m, sha, &src->ip.v6, &t->ndp, &t->bytes[len], InterfaceID); 1042847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else LogInfo("IPv6CheckSum bad %04X %02X%02X from %#a to %#a", checksum, t->bytes[2], t->bytes[3], src, dst); 1042947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1043047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 1043147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1043247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt default: LogSPS("Ignoring %d-byte IP packet unknown protocol %d from %#a to %#a", end-p, protocol, src, dst); 1043347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 1043447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1043547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1043647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (wake) 1043747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1043847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr, *r2; 1043947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1044047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 1044147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr=rr->next) 1044247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.InterfaceID == InterfaceID && 1044347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->resrec.RecordType != kDNSRecordTypeDeregistering && 1044447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AddressProxy.type && mDNSSameAddress(&rr->AddressProxy, dst)) 1044547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1044647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *const tp = (protocol == 6) ? (const mDNSu8 *)"\x4_tcp" : (const mDNSu8 *)"\x4_udp"; 1044747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (r2 = m->ResourceRecords; r2; r2=r2->next) 1044847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2->resrec.InterfaceID == InterfaceID && mDNSSameEthAddress(&r2->WakeUp.HMAC, &rr->WakeUp.HMAC) && 1044947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->resrec.RecordType != kDNSRecordTypeDeregistering && 1045047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt r2->resrec.rrtype == kDNSType_SRV && mDNSSameIPPort(r2->resrec.rdata->u.srv.port, port) && 1045147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SameDomainLabel(ThirdLabel(r2->resrec.name)->c, tp)) 1045247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 1045347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!r2 && mDNSSameIPPort(port, IPSECPort)) r2 = rr; // So that we wake for BTMM IPSEC packets, even without a matching SRV record 1045447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (r2) 1045547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1045647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("Waking host at %s %#a H-MAC %.6a I-MAC %.6a for %s", 1045747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InterfaceNameForID(m, rr->resrec.InterfaceID), dst, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, r2)); 1045847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ScheduleWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.HMAC); 1045947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1046047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1046147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("Sleeping host at %s %#a %.6a has no service on %#s %d", 1046247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt InterfaceNameForID(m, rr->resrec.InterfaceID), dst, &rr->WakeUp.HMAC, tp, mDNSVal16(port)); 1046347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1046447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 1046547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1046647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1046747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1046847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID) 1046947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1047047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const mDNSOpaque16 Ethertype_ARP = { { 0x08, 0x06 } }; // Ethertype 0x0806 = ARP 1047147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const mDNSOpaque16 Ethertype_IPv4 = { { 0x08, 0x00 } }; // Ethertype 0x0800 = IPv4 1047247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const mDNSOpaque16 Ethertype_IPv6 = { { 0x86, 0xDD } }; // Ethertype 0x86DD = IPv6 1047347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const mDNSOpaque16 ARP_hrd_eth = { { 0x00, 0x01 } }; // Hardware address space (Ethernet = 1) 1047447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt static const mDNSOpaque16 ARP_pro_ip = { { 0x08, 0x00 } }; // Protocol address space (IP = 0x0800) 1047547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1047647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Note: BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header. 1047747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // In other words, we can safely assume that pkt below (ARP, IPv4 or IPv6) is properly word aligned, 1047847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // but if pkt is 4-byte aligned, that necessarily means that eth CANNOT also be 4-byte aligned 1047947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // since it points to a an address 14 bytes before pkt. 1048047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const EthernetHeader *const eth = (const EthernetHeader *)p; 1048147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const NetworkLayerPacket *const pkt = (const NetworkLayerPacket *)(eth+1); 1048247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSAddr src, dst; 1048347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt #define RequiredCapLen(P) ((P)==0x01 ? 4 : (P)==0x06 ? 20 : (P)==0x11 ? 8 : (P)==0x3A ? 24 : 0) 1048447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1048547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Is ARP? Length must be at least 14 + 28 = 42 bytes 1048647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (end >= p+42 && mDNSSameOpaque16(eth->ethertype, Ethertype_ARP) && mDNSSameOpaque16(pkt->arp.hrd, ARP_hrd_eth) && mDNSSameOpaque16(pkt->arp.pro, ARP_pro_ip)) 1048747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSCoreReceiveRawARP(m, &pkt->arp, InterfaceID); 1048847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Is IPv4 with zero fragmentation offset? Length must be at least 14 + 20 = 34 bytes 1048947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IPv4) && (pkt->v4.flagsfrags.b[0] & 0x1F) == 0 && pkt->v4.flagsfrags.b[1] == 0) 1049047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1049147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *const trans = p + 14 + (pkt->v4.vlen & 0xF) * 4; 1049247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("Got IPv4 %02X from %.4a to %.4a", pkt->v4.protocol, &pkt->v4.src, &pkt->v4.dst); 1049347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt src.type = mDNSAddrType_IPv4; src.ip.v4 = pkt->v4.src; 1049447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dst.type = mDNSAddrType_IPv4; dst.ip.v4 = pkt->v4.dst; 1049547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (end >= trans + RequiredCapLen(pkt->v4.protocol)) 1049647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSCoreReceiveRawTransportPacket(m, ð->src, &src, &dst, pkt->v4.protocol, p, (TransportLayerPacket*)trans, end, InterfaceID, 0); 1049747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1049847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Is IPv6? Length must be at least 14 + 28 = 42 bytes 1049947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (end >= p+54 && mDNSSameOpaque16(eth->ethertype, Ethertype_IPv6)) 1050047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1050147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu8 *const trans = p + 54; 1050247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("Got IPv6 %02X from %.16a to %.16a", pkt->v6.pro, &pkt->v6.src, &pkt->v6.dst); 1050347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt src.type = mDNSAddrType_IPv6; src.ip.v6 = pkt->v6.src; 1050447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt dst.type = mDNSAddrType_IPv6; dst.ip.v6 = pkt->v6.dst; 1050547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (end >= trans + RequiredCapLen(pkt->v6.pro)) 1050647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSCoreReceiveRawTransportPacket(m, ð->src, &src, &dst, pkt->v6.pro, p, (TransportLayerPacket*)trans, end, InterfaceID, 1050747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (mDNSu16)pkt->bytes[4] << 8 | pkt->bytes[5]); 1050847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1050947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1051047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1051147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ConstructSleepProxyServerName(mDNS *const m, domainlabel *name) 1051247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1051347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt name->c[0] = (mDNSu8)mDNS_snprintf((char*)name->c+1, 62, "%d-%d-%d-%d %#s", 1051447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower, &m->nicelabel); 1051547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1051647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1051747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SleepProxyServerCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result) 1051847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1051947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (result == mStatus_NameConflict) 1052047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_RenameAndReregisterService(m, srs, mDNSNULL); 1052147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (result == mStatus_MemFree) 1052247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1052347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SleepState) 1052447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSState = 3; 1052547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1052647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1052747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSState = (mDNSu8)(m->SPSSocket != mDNSNULL); 1052847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SPSState) 1052947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1053047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainlabel name; 1053147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ConstructSleepProxyServerName(m, &name); 1053247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_RegisterService(m, srs, 1053347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt &name, &SleepProxyServiceType, &localdomain, 1053447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSNULL, m->SPSSocket->port, // Host, port 1053547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (mDNSu8 *)"", 1, // TXT data, length 1053647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSNULL, 0, // Subtypes (none) 1053747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSInterface_Any, // Interface ID 1053847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SleepProxyServerCallback, mDNSNULL, 0); // Callback, context, flags 1053947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1054047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("Sleep Proxy Server %#s %s", srs->RR_SRV.resrec.name->c, m->SPSState ? "started" : "stopped"); 1054147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1054247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1054347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1054447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1054547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Called with lock held 1054647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNSCoreBeSleepProxyServer_internal(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower) 1054747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1054847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This routine uses mDNS_DeregisterService and calls SleepProxyServerCallback, so we execute in user callback context 1054947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DropLockBeforeCallback(); 1055047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1055147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If turning off SPS, close our socket 1055247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // (Do this first, BEFORE calling mDNS_DeregisterService below) 1055347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!sps && m->SPSSocket) { mDNSPlatformUDPClose(m->SPSSocket); m->SPSSocket = mDNSNULL; } 1055447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1055547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If turning off, or changing type, deregister old name 1055647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SPSState == 1 && sps != m->SPSType) 1055747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { m->SPSState = 2; mDNS_DeregisterService_drt(m, &m->SPSRecords, sps ? mDNS_Dereg_rapid : mDNS_Dereg_normal); } 1055847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1055947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Record our new SPS parameters 1056047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSType = sps; 1056147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSPortability = port; 1056247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSMarginalPower = marginalpower; 1056347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSTotalPower = totpower; 1056447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1056547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If turning on, open socket and advertise service 1056647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (sps) 1056747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1056847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->SPSSocket) 1056947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1057047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSSocket = mDNSPlatformUDPSocket(m, zeroIPPort); 1057147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->SPSSocket) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); goto fail; } 1057247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1057347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SPSState == 0) SleepProxyServerCallback(m, &m->SPSRecords, mStatus_MemFree); 1057447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1057547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (m->SPSState) 1057647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1057747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("mDNSCoreBeSleepProxyServer turning off from state %d; will wake clients", m->SPSState); 1057847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledSPS = m->timenow; 1057947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1058047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltfail: 1058147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_ReclaimLockAfterCallback(); 1058247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1058347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1058447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// *************************************************************************** 1058547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK 1058647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - 1058747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Startup and Shutdown 1058847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 1058947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1059047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void mDNS_GrowCache_internal(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords) 1059147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1059247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (storage && numrecords) 1059347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1059447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 i; 1059547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("Adding cache storage for %d more records (%d bytes)", numrecords, numrecords*sizeof(CacheEntity)); 1059647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (i=0; i<numrecords; i++) storage[i].next = &storage[i+1]; 1059747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt storage[numrecords-1].next = m->rrcache_free; 1059847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_free = storage; 1059947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_size += numrecords; 1060047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1060147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1060247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1060347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_GrowCache(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords) 1060447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1060547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 1060647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_GrowCache_internal(m, storage, numrecords); 1060747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 1060847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1060947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1061047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, 1061147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheEntity *rrcachestorage, mDNSu32 rrcachesize, 1061247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context) 1061347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1061447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 1061547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSs32 timenow; 1061647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mStatus result; 1061747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1061847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!rrcachestorage) rrcachesize = 0; 1061947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1062047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->p = p; 1062147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->KnownBugs = 0; 1062247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise 1062347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->AdvertiseLocalAddresses = AdvertiseLocalAddresses; 1062447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->DivertMulticastAdvertisements = mDNSfalse; 1062547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->mDNSPlatformStatus = mStatus_Waiting; 1062647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->UnicastPort4 = zeroIPPort; 1062747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->UnicastPort6 = zeroIPPort; 1062847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->PrimaryMAC = zeroEthAddr; 1062947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->MainCallback = Callback; 1063047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->MainContext = Context; 1063147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rec.r.resrec.RecordType = 0; 1063247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1063347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For debugging: To catch and report locking failures 1063447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->mDNS_busy = 0; 1063547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->mDNS_reentrancy = 0; 1063647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ShutdownTime = 0; 1063747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->lock_rrcache = 0; 1063847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->lock_Questions = 0; 1063947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->lock_Records = 0; 1064047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1064147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Task Scheduling variables 1064247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt result = mDNSPlatformTimeInit(); 1064347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (result != mStatus_NoError) return(result); 1064447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->timenow_adjust = (mDNSs32)mDNSRandom(0xFFFFFFFF); 1064547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt timenow = mDNS_TimeNow_NoLock(m); 1064647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1064747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->timenow = 0; // MUST only be set within mDNS_Lock/mDNS_Unlock section 1064847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->timenow_last = timenow; 1064947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledEvent = timenow; 1065047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressSending = timenow; 1065147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextCacheCheck = timenow + 0x78000000; 1065247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledQuery = timenow + 0x78000000; 1065347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledProbe = timenow + 0x78000000; 1065447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledResponse = timenow + 0x78000000; 1065547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledNATOp = timenow + 0x78000000; 1065647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledSPS = timenow + 0x78000000; 1065747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledStopTime = timenow + 0x78000000; 1065847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RandomQueryDelay = 0; 1065947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RandomReconfirmDelay = 0; 1066047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->PktNum = 0; 1066147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LocalRemoveEvents = mDNSfalse; 1066247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SleepState = SleepState_Awake; 1066347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SleepSeqNum = 0; 1066447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SystemWakeOnLANEnabled = mDNSfalse; 1066547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->AnnounceOwner = NonZeroTime(timenow + 60 * mDNSPlatformOneSecond); 1066647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->DelaySleep = 0; 1066747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SleepLimit = 0; 1066847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1066947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // These fields only required for mDNS Searcher... 1067047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->Questions = mDNSNULL; 1067147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NewQuestions = mDNSNULL; 1067247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentQuestion = mDNSNULL; 1067347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LocalOnlyQuestions = mDNSNULL; 1067447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NewLocalOnlyQuestions = mDNSNULL; 1067547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RestartQuestion = mDNSNULL; 1067647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_size = 0; 1067747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_totalused = 0; 1067847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_active = 0; 1067947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_report = 10; 1068047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_free = mDNSNULL; 1068147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1068247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) 1068347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1068447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_hash[slot] = mDNSNULL; 1068547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrcache_nextcheck[slot] = timenow + 0x78000000;; 1068647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1068747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1068847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize); 1068947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrauth.rrauth_free = mDNSNULL; 1069047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1069147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) 1069247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->rrauth.rrauth_hash[slot] = mDNSNULL; 1069347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1069447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Fields below only required for mDNS Responder... 1069547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->hostlabel.c[0] = 0; 1069647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->nicelabel.c[0] = 0; 1069747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->MulticastHostname.c[0] = 0; 1069847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->HIHardware.c[0] = 0; 1069947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->HISoftware.c[0] = 0; 1070047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ResourceRecords = mDNSNULL; 1070147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->DuplicateRecords = mDNSNULL; 1070247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NewLocalRecords = mDNSNULL; 1070347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NewLocalOnlyRecords = mDNSfalse; 1070447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = mDNSNULL; 1070547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->HostInterfaces = mDNSNULL; 1070647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ProbeFailTime = 0; 1070747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NumFailedProbes = 0; 1070847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressProbes = 0; 1070947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1071047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 1071147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextuDNSEvent = timenow + 0x78000000; 1071247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextSRVUpdate = timenow + 0x78000000; 1071347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1071447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->DNSServers = mDNSNULL; 1071547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1071647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->Router = zeroAddr; 1071747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->AdvertisedV4 = zeroAddr; 1071847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->AdvertisedV6 = zeroAddr; 1071947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1072047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->AuthInfoList = mDNSNULL; 1072147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1072247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ReverseMap.ThisQInterval = -1; 1072347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->StaticHostname.c[0] = 0; 1072447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->FQDN.c[0] = 0; 1072547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->Hostnames = mDNSNULL; 1072647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->AutoTunnelHostAddr.b[0] = 0; 1072747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->AutoTunnelHostAddrActive = mDNSfalse; 1072847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->AutoTunnelLabel.c[0] = 0; 1072947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1073047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->StartWABQueries = mDNSfalse; 1073147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->RegisterAutoTunnel6 = mDNStrue; 1073247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1073347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // NAT traversal fields 1073447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NATTraversals = mDNSNULL; 1073547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentNATTraversal = mDNSNULL; 1073647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->retryIntervalGetAddr = 0; // delta between time sent and retry 1073747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->retryGetAddr = timenow + 0x78000000; // absolute time when we retry 1073847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ExternalAddress = zerov4Addr; 1073947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1074047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NATMcastRecvskt = mDNSNULL; 1074147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LastNATupseconds = 0; 1074247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LastNATReplyLocalTime = timenow; 1074347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->LastNATMapResultCode = NATErr_None; 1074447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1074547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->UPnPInterfaceID = 0; 1074647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SSDPSocket = mDNSNULL; 1074747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SSDPWANPPPConnection = mDNSfalse; 1074847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->UPnPRouterPort = zeroIPPort; 1074947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->UPnPSOAPPort = zeroIPPort; 1075047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->UPnPRouterURL = mDNSNULL; 1075147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->UPnPWANPPPConnection = mDNSfalse; 1075247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->UPnPSOAPURL = mDNSNULL; 1075347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->UPnPRouterAddressString = mDNSNULL; 1075447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->UPnPSOAPAddressString = mDNSNULL; 1075547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSType = 0; 1075647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSPortability = 0; 1075747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSMarginalPower = 0; 1075847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSTotalPower = 0; 1075947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSState = 0; 1076047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSProxyListChanged = mDNSNULL; 1076147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSSocket = mDNSNULL; 1076247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSBrowseCallback = mDNSNULL; 1076347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ProxyRecords = 0; 1076447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1076547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 1076647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1076747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder 1076847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->TunnelClients = mDNSNULL; 1076947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1077047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ! NO_WCF 1077147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CHECK_WCF_FUNCTION(WCFConnectionNew) 1077247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1077347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->WCF = WCFConnectionNew(); 1077447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!m->WCF) { LogMsg("WCFConnectionNew failed"); return -1; } 1077547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1077647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 1077747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1077847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 1077947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1078047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt result = mDNSPlatformInit(m); 1078147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1078247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 1078347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // It's better to do this *after* the platform layer has set up the 1078447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // interface list and security credentials 1078547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uDNS_SetupDNSConfig(m); // Get initial DNS configuration 1078647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 1078747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1078847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return(result); 1078947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1079047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1079147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_ConfigChanged(mDNS *const m) 1079247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1079347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->SPSState == 1) 1079447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1079547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainlabel name, newname; 1079647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainname type, domain; 1079747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DeconstructServiceName(m->SPSRecords.RR_SRV.resrec.name, &name, &type, &domain); 1079847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ConstructSleepProxyServerName(m, &newname); 1079947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!SameDomainLabelCS(name.c, newname.c)) 1080047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1080147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogSPS("Renaming SPS from “%#s” to “%#s”", name.c, newname.c); 1080247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // When SleepProxyServerCallback gets the mStatus_MemFree message, 1080347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // it will reregister the service under the new name 1080447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SPSState = 2; 1080547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DeregisterService_drt(m, &m->SPSRecords, mDNS_Dereg_rapid); 1080647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1080747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1080847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1080947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->MainCallback) 1081047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->MainCallback(m, mStatus_ConfigChanged); 1081147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1081247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1081347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void DynDNSHostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 1081447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1081547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (void)m; // unused 1081647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("NameStatusCallback: result %d for registration of name %##s", result, rr->resrec.name->c); 1081747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformDynDNSHostNameStatusChanged(rr->resrec.name, result); 1081847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1081947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1082047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const DNSServer * const ptr, mDNSBool lameduck) 1082147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1082247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool purge = cr->resrec.RecordType == kDNSRecordTypePacketNegative || 1082347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rrtype == kDNSType_A || 1082447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rrtype == kDNSType_AAAA || 1082547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rrtype == kDNSType_SRV; 1082647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1082747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (void) lameduck; 1082847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (void) ptr; 1082947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("PurgeOrReconfirmCacheRecord: %s cache record due to %s server %p %#a:%d (%##s): %s", 1083047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt purge ? "purging" : "reconfirming", 1083147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt lameduck ? "lame duck" : "new", 1083247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, CRDisplayString(m, cr)); 1083347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1083447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (purge) 1083547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1083647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("PurgeorReconfirmCacheRecord: Purging Resourcerecord %s, RecordType %x", CRDisplayString(m, cr), cr->resrec.RecordType); 1083747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_PurgeCacheResourceRecord(m, cr); 1083847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1083947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1084047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1084147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("PurgeorReconfirmCacheRecord: Reconfirming Resourcerecord %s, RecordType %x", CRDisplayString(m, cr), cr->resrec.RecordType); 1084247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); 1084347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1084447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1084547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1084647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q) 1084747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1084847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = HashSlot(&q->qname); 1084947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 1085047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rp; 1085147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1085247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next) 1085347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1085447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameNameRecordAnswersQuestion(&rp->resrec, q)) 1085547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1085647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_PurgeBeforeResolve: Flushing %s", CRDisplayString(m, rp)); 1085747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_PurgeCacheResourceRecord(m, rp); 1085847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1085947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1086047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1086147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1086247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void CacheRecordResetDNSServer(mDNS *const m, DNSQuestion *q, DNSServer *new) 1086347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1086447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const mDNSu32 slot = HashSlot(&q->qname); 1086547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 1086647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *rp; 1086747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool found = mDNSfalse; 1086847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool foundNew = mDNSfalse; 1086947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSServer *old = q->qDNSServer; 1087047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSBool newQuestion = IsQuestionNew(m, q); 1087147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *qptr; 1087247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1087347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This function is called when the DNSServer is updated to the new question. There may already be 1087447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // some cache entries matching the old DNSServer and/or new DNSServer. There are four cases. In the 1087547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // following table, "Yes" denotes that a cache entry was found for old/new DNSServer. 1087647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1087747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // old DNSServer new DNSServer 1087847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1087947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Case 1 Yes Yes 1088047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Case 2 No Yes 1088147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Case 3 Yes No 1088247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Case 4 No No 1088347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1088447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Case 1: There are cache entries for both old and new DNSServer. We handle this case by simply 1088547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // expiring the old Cache entries, deliver a RMV event (if an ADD event was delivered before) 1088647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // followed by the ADD event of the cache entries corresponding to the new server. This 1088747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // case happens when we pick a DNSServer, issue a query and get a valid response and create 1088847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // cache entries after which it stops responding. Another query (non-duplicate) picks a different 1088947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // DNSServer and creates identical cache entries (perhaps through records in Additional records). 1089047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Now if the first one expires and tries to pick the new DNSServer (the original DNSServer 1089147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // is not responding) we will find cache entries corresponding to both DNSServers. 1089247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1089347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Case 2: There are no cache entries for the old DNSServer but there are some for the new DNSServer. 1089447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This means we should deliver an ADD event. Normally ADD events are delivered by 1089547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // AnswerNewQuestion if it is a new question. So, we check to see if it is a new question 1089647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and if so, leave it to AnswerNewQuestion to deliver it. Otherwise, we use 1089747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // AnswerQuestionsForDNSServerChanges to deliver the ADD event. This case happens when a 1089847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // question picks a DNS server for which AnswerNewQuestion could not deliver an answer even 1089947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // though there were potential cache entries but DNSServer did not match. Now when we 1090047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // pick a new DNSServer, those cache entries may answer this question. 1090147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1090247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Case 3: There are the cache entries for the old DNSServer but none for the new. We just move 1090347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the old cache entries to point to the new DNSServer and the caller is expected to 1090447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // do a purge or reconfirm to delete or validate the RDATA. We don't need to do anything 1090547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // special for delivering ADD events, as it should have been done/will be done by 1090647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // AnswerNewQuestion. This case happens when we picked a DNSServer, sent the query and 1090747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // got a response and the cache is expired now and we are reissuing the question but the 1090847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // original DNSServer does not respond. 1090947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1091047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Case 4: There are no cache entries either for the old or for the new DNSServer. There is nothing 1091147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // much we can do here. 1091247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1091347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Case 2 and 3 are the most common while case 4 is possible when no DNSServers are working. Case 1 1091447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // is relatively less likely to happen in practice 1091547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1091647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Temporarily set the DNSServer to look for the matching records for the new DNSServer. 1091747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qDNSServer = new; 1091847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next) 1091947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1092047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameNameRecordAnswersQuestion(&rp->resrec, q)) 1092147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1092247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CacheRecordResetDNSServer: Found cache record %##s for new DNSServer address: %#a", rp->resrec.name->c, 1092347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rp->resrec.rDNSServer != mDNSNULL ? &rp->resrec.rDNSServer->addr : mDNSNULL)); 1092447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt foundNew = mDNStrue; 1092547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt break; 1092647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1092747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1092847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qDNSServer = old; 1092947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1093047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next) 1093147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1093247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (SameNameRecordAnswersQuestion(&rp->resrec, q)) 1093347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1093447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Case1 1093547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt found = mDNStrue; 1093647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (foundNew) 1093747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1093847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CacheRecordResetDNSServer: Flushing Resourcerecord %##s, before:%#a, after:%#a", rp->resrec.name->c, 1093947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rp->resrec.rDNSServer != mDNSNULL ? &rp->resrec.rDNSServer->addr : mDNSNULL), 1094047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (new != mDNSNULL ? &new->addr : mDNSNULL)); 1094147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_PurgeCacheResourceRecord(m, rp); 1094247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newQuestion) 1094347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1094447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // "q" is not a duplicate question. If it is a newQuestion, then the CRActiveQuestion can't be 1094547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // possibly set as it is set only when we deliver the ADD event to the question. 1094647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rp->CRActiveQuestion != mDNSNULL) 1094747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1094847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("CacheRecordResetDNSServer: ERROR!!: CRActiveQuestion %p set, current question %p, name %##s", rp->CRActiveQuestion, q, q->qname.c); 1094947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp->CRActiveQuestion = mDNSNULL; 1095047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1095147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // if this is a new question, then we never delivered an ADD yet, so don't deliver the RMV. 1095247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt continue; 1095347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1095447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1095547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CacheRecordResetDNSServer: resetting cache record %##s DNSServer address before:%#a," 1095647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt " after:%#a, CRActiveQuestion %p", rp->resrec.name->c, (rp->resrec.rDNSServer != mDNSNULL ? 1095747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt &rp->resrec.rDNSServer->addr : mDNSNULL), (new != mDNSNULL ? &new->addr : mDNSNULL), 1095847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp->CRActiveQuestion); 1095947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Though we set it to the new DNS server, the caller is *assumed* to do either a purge 1096047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // or reconfirm or send out questions to the "new" server to verify whether the cached 1096147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // RDATA is valid 1096247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rp->resrec.rDNSServer = new; 1096347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1096447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1096547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1096647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Case 1 and Case 2 1096747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((found && foundNew) || (!found && foundNew)) 1096847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1096947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (newQuestion) 1097047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CacheRecordResetDNSServer: deliverAddEvents not set for question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); 1097147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (QuerySuppressed(q)) 1097247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CacheRecordResetDNSServer: deliverAddEvents not set for suppressed question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); 1097347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1097447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1097547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("CacheRecordResetDNSServer: deliverAddEvents set for %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); 1097647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->deliverAddEvents = mDNStrue; 1097747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (qptr = q->next; qptr; qptr = qptr->next) 1097847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (qptr->DuplicateOf == q) qptr->deliverAddEvents = mDNStrue; 1097947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1098047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 1098147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1098247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1098347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Case 3 and Case 4 1098447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return; 1098547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1098647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1098747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer *new) 1098847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1098947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *qptr; 1099047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1099147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1. Whenever we change the DNS server, we change the message identifier also so that response 1099247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // from the old server is not accepted as a response from the new server but only messages 1099347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // from the new server are accepted as valid responses. We do it irrespective of whether "new" 1099447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // is NULL or not. It is possible that we send two queries, no responses, pick a new DNS server 1099547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // which is NULL and now the response comes back and will try to penalize the DNS server which 1099647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // is NULL. By setting the messageID here, we will not accept that as a valid response. 1099747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1099847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->TargetQID = mDNS_NewMessageID(m); 1099947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1100047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2. Move the old cache records to point them at the new DNSServer so that we can deliver the ADD/RMV events 1100147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // appropriately. At any point in time, we want all the cache records point only to one DNSServer for a given 1100247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // question. "DNSServer" here is the DNSServer object and not the DNS server itself. It is possible to 1100347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // have the same DNS server address in two objects, one scoped and another not scoped. But, the cache is per 1100447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // DNSServer object. By maintaining the question and the cache entries point to the same DNSServer 1100547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // always, the cache maintenance and delivery of ADD/RMV events becomes simpler. 1100647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1100747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // CacheRecordResetDNSServer should be called only once for the non-duplicate question as once the cache 1100847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // entries are moved to point to the new DNSServer, we don't need to call it for the duplicate question 1100947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and it is wrong to call for the duplicate question as it's decision to mark deliverAddevents will be 1101047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // incorrect. 1101147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1101247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->DuplicateOf) 1101347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("DNSServerChangeForQuestion: ERROR: Called for duplicate question %##s", q->qname.c); 1101447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1101547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecordResetDNSServer(m, q, new); 1101647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1101747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3. Make sure all the duplicate questions point to the same DNSServer so that delivery 1101847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // of events for all of them are consistent. Duplicates for a question are always inserted 1101947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // after in the list. 1102047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qDNSServer = new; 1102147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (qptr = q->next ; qptr; qptr = qptr->next) 1102247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1102347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = new; } 1102447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1102547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1102647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1102747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) 1102847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1102947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 1103047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg; 1103147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *cr; 1103247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1103347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSAddr v4, v6, r; 1103447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt domainname fqdn; 1103547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSServer *ptr, **p = &m->DNSServers; 1103647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt const DNSServer *oldServers = m->DNSServers; 1103747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *q; 1103847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt McastResolver *mr, **mres = &m->McastResolvers; 1103947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1104047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("uDNS_SetupDNSConfig: entry"); 1104147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1104247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Let the platform layer get the current DNS information 1104347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The m->StartWABQueries is set when we get the first domain enumeration query (no need to hit the network 1104447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // with domain enumeration queries until we actually need that information). Even if it is not set, we still 1104547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // need to setup the search domains so that we can append them to queries that need them. 1104647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1104747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt uDNS_SetupSearchDomains(m, m->StartWABQueries ? UDNS_START_WAB_QUERY : 0); 1104847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1104947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 1105047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1105147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (ptr = m->DNSServers; ptr; ptr = ptr->next) 1105247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1105347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr->penaltyTime = 0; 1105447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr->flags |= DNSServer_FlagDelete; 1105547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1105647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1105747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We handle the mcast resolvers here itself as mDNSPlatformSetDNSConfig looks at 1105847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // mcast resolvers. Today we get both mcast and ucast configuration using the same 1105947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // API 1106047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (mr = m->McastResolvers; mr; mr = mr->next) 1106147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mr->flags |= McastResolver_FlagDelete; 1106247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1106347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL); 1106447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1106547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For now, we just delete the mcast resolvers. We don't deal with cache or 1106647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // questions here. Neither question nor cache point to mcast resolvers. Questions 1106747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // do inherit the timeout values from mcast resolvers. But we don't bother 1106847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // affecting them as they never change. 1106947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*mres) 1107047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1107147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (((*mres)->flags & DNSServer_FlagDelete) != 0) 1107247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1107347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mr = *mres; 1107447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *mres = (*mres)->next; 1107547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("uDNS_SetupDNSConfig: Deleting mcast resolver %##s", mr, mr->domain.c); 1107647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemFree(mr); 1107747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1107847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1107947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1108047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (*mres)->flags &= ~McastResolver_FlagNew; 1108147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mres = &(*mres)->next; 1108247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1108347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1108447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1108547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Mark the records to be flushed that match a new resolver. We need to do this before 1108647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we walk the questions below where we change the DNSServer pointer of the cache 1108747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // record 1108847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt FORALL_CACHERECORDS(slot, cg, cr) 1108947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1109047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->resrec.InterfaceID) continue; 1109147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1109247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We just mark them for purge or reconfirm. We can't affect the DNSServer pointer 1109347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // here as the code below that calls CacheRecordResetDNSServer relies on this 1109447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1109547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // The new DNSServer may be a scoped or non-scoped one. We use the active question's 1109647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // InterfaceID for looking up the right DNS server 1109747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = GetServerForName(m, cr->resrec.name, cr->CRActiveQuestion ? cr->CRActiveQuestion->InterfaceID : mDNSNULL); 1109847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1109947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Purge or Reconfirm if this cache entry would use the new DNS server 1110047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (ptr && (ptr != cr->resrec.rDNSServer)) 1110147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1110247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // As the DNSServers for this cache record is not the same anymore, we don't 1110347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // want any new questions to pick this old value 1110447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->CRActiveQuestion == mDNSNULL) 1110547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1110647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("uDNS_SetupDNSConfig: Purging Resourcerecord %s", CRDisplayString(m, cr)); 1110747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_PurgeCacheResourceRecord(m, cr); 1110847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1110947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1111047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1111147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("uDNS_SetupDNSConfig: Purging/Reconfirming Resourcerecord %s", CRDisplayString(m, cr)); 1111247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse); 1111347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1111447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1111547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1111647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Update our qDNSServer pointers before we go and free the DNSServer object memory 1111747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (q = m->Questions; q; q=q->next) 1111847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!mDNSOpaque16IsZero(q->TargetQID)) 1111947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1112047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSServer *s, *t; 1112147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *qptr; 1112247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (q->DuplicateOf) continue; 1112347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SetValidDNSServers(m, q); 1112447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->triedAllServersOnce = 0; 1112547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt s = GetServerForQuestion(m, q); 1112647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt t = q->qDNSServer; 1112747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (t != s) 1112847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1112947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If DNS Server for this question has changed, reactivate it 1113047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("uDNS_SetupDNSConfig: Updating DNS Server from %p %#a:%d (%##s) to %p %#a:%d (%##s) for %##s (%s)", 1113147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt t, t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), t ? t->domain.c : (mDNSu8*)"", 1113247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt s, s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), s ? s->domain.c : (mDNSu8*)"", 1113347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->qname.c, DNSTypeName(q->qtype)); 1113447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1113547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // After we reset the DNSServer pointer on the cache records here, three things could happen: 1113647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1113747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1) The query gets sent out and when the actual response comes back later it is possible 1113847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // that the response has the same RDATA, in which case we update our cache entry. 1113947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If the response is different, then the entry will expire and a new entry gets added. 1114047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For the latter case to generate a RMV followed by ADD events, we need to reset the DNS 1114147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // server here to match the question and the cache record. 1114247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1114347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 2) We might have marked the cache entries for purge above and for us to be able to generate the RMV 1114447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // events for the questions, the DNSServer on the question should match the Cache Record 1114547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1114647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 3) We might have marked the cache entries for reconfirm above, for which we send the query out which is 1114747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // the same as the first case above. 1114847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1114947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSServerChangeForQuestion(m, q, s); 1115047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q->unansweredQueries = 0; 1115147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We still need to pick a new DNSServer for the questions that have been 1115247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // suppressed, but it is wrong to activate the query as DNS server change 1115347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // could not possibly change the status of SuppressUnusable questions 1115447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!QuerySuppressed(q)) 1115547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1115647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("uDNS_SetupDNSConfig: Activating query %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); 1115747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ActivateUnicastQuery(m, q, mDNStrue); 1115847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // ActivateUnicastQuery is called for duplicate questions also as it does something 1115947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // special for AutoTunnel questions 1116047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (qptr = q->next ; qptr; qptr = qptr->next) 1116147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1116247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (qptr->DuplicateOf == q) ActivateUnicastQuery(m, qptr, mDNStrue); 1116347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1116447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1116547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1116647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1116747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1116847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("uDNS_SetupDNSConfig: Not Updating DNS server question %p %##s (%s) DNS server %#a:%d %p %d", 1116947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt q, q->qname.c, DNSTypeName(q->qtype), t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), q->DuplicateOf, q->SuppressUnusable); 1117047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (qptr = q->next ; qptr; qptr = qptr->next) 1117147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; } 1117247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1117347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1117447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1117547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (*p) 1117647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1117747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (((*p)->flags & DNSServer_FlagDelete) != 0) 1117847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1117947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Scan our cache, looking for uDNS records that we would have queried this server for. 1118047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We reconfirm any records that match, because in this world of split DNS, firewalls, etc. 1118147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // different DNS servers can give different answers to the same question. 1118247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ptr = *p; 1118347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt FORALL_CACHERECORDS(slot, cg, cr) 1118447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1118547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->resrec.InterfaceID) continue; 1118647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->resrec.rDNSServer == ptr) 1118747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1118847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we don't have an active question for this cache record, neither Purge can 1118947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // generate RMV events nor Reconfirm can send queries out. Just set the DNSServer 1119047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // pointer on the record NULL so that we don't point to freed memory (We might dereference 1119147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // DNSServer pointers from resource record for logging purposes). 1119247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // 1119347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If there is an active question, point to its DNSServer as long as it does not point to the 1119447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // freed one. We already went through the questions above and made them point at either the 1119547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // new server or NULL if there is no server and also affected the cache entries that match 1119647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // this question. Hence, whenever we hit a resource record with a DNSServer that is just 1119747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // about to be deleted, we should never have an active question. The code below just tries to 1119847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // be careful logging messages if we ever hit this case. 1119947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1120047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->CRActiveQuestion) 1120147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1120247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DNSQuestion *qptr = cr->CRActiveQuestion; 1120347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (qptr->qDNSServer == mDNSNULL) 1120447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("uDNS_SetupDNSConfig: Cache Record %s match: Active question %##s (%s) with DNSServer Address NULL, Server to be deleted %#a", 1120547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype), &ptr->addr); 1120647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1120747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("uDNS_SetupDNSConfig: Cache Record %s match: Active question %##s (%s) DNSServer Address %#a, Server to be deleted %#a", 1120847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype), &qptr->qDNSServer->addr, &ptr->addr); 1120947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1121047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (qptr->qDNSServer == ptr) 1121147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1121247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt qptr->validDNSServers = zeroOpaque64; 1121347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt qptr->qDNSServer = mDNSNULL; 1121447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rDNSServer = mDNSNULL; 1121547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1121647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1121747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1121847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rDNSServer = qptr->qDNSServer; 1121947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1122047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1122147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1122247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1122347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("uDNS_SetupDNSConfig: Cache Record %##s has no Active question, Record's DNSServer Address %#a, Server to be deleted %#a", 1122447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.name, &cr->resrec.rDNSServer->addr, &ptr->addr); 1122547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cr->resrec.rDNSServer = mDNSNULL; 1122647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1122747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1122847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNStrue); 1122947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1123047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1123147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *p = (*p)->next; 1123247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c); 1123347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformMemFree(ptr); 1123447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NumUnicastDNSServers--; 1123547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1123647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1123747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1123847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (*p)->flags &= ~DNSServer_FlagNew; 1123947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt p = &(*p)->next; 1124047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1124147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1124247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1124347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we now have no DNS servers at all and we used to have some, then immediately purge all unicast cache records (including for LLQs). 1124447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless. 1124547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Otherwise, stale data lingers for 5-10 seconds, which is not the user-experience people expect from Bonjour. 1124647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Similarly, if we now have some DNS servers and we used to have none, we want to purge any fake negative results we may have generated. 1124747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if ((m->DNSServers != mDNSNULL) != (oldServers != mDNSNULL)) 1124847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1124947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt int count = 0; 1125047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt FORALL_CACHERECORDS(slot, cg, cr) if (!cr->resrec.InterfaceID) { mDNS_PurgeCacheResourceRecord(m, cr); count++; } 1125147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache", 1125247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->DNSServers ? "DNS server became" : "No DNS servers", count); 1125347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1125447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Force anything that needs to get zone data to get that information again 1125547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt RestartRecordGetZoneData(m); 1125647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1125747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1125847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Did our FQDN change? 1125947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (!SameDomainName(&fqdn, &m->FQDN)) 1126047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1126147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->FQDN.c[0]) mDNS_RemoveDynDNSHostName(m, &m->FQDN); 1126247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1126347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AssignDomainName(&m->FQDN, &fqdn); 1126447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1126547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->FQDN.c[0]) 1126647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1126747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); 1126847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_AddDynDNSHostName(m, &m->FQDN, DynDNSHostNameCallback, mDNSNULL); 1126947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1127047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1127147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1127247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 1127347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1127447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // handle router and primary interface changes 1127547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt v4 = v6 = r = zeroAddr; 1127647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt v4.type = r.type = mDNSAddrType_IPv4; 1127747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1127847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (mDNSPlatformGetPrimaryInterface(m, &v4, &v6, &r) == mStatus_NoError && !mDNSv4AddressIsLinkLocal(&v4.ip.v4)) 1127947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1128047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetPrimaryInterfaceInfo(m, 1128147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !mDNSIPv4AddressIsZero(v4.ip.v4) ? &v4 : mDNSNULL, 1128247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !mDNSIPv6AddressIsZero(v6.ip.v6) ? &v6 : mDNSNULL, 1128347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt !mDNSIPv4AddressIsZero(r .ip.v4) ? &r : mDNSNULL); 1128447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1128547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else 1128647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1128747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_SetPrimaryInterfaceInfo(m, mDNSNULL, mDNSNULL, mDNSNULL); 1128847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->FQDN.c[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); // Set status to 1 to indicate temporary failure 1128947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1129047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1129147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("uDNS_SetupDNSConfig: number of unicast DNS servers %d", NumUnicastDNSServers); 1129247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt return mStatus_NoError; 1129347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1129447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1129547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result) 1129647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1129747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->mDNSPlatformStatus = result; 1129847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->MainCallback) 1129947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1130047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 1130147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 1130247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->MainCallback(m, mStatus_NoError); 1130347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 1130447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 1130547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1130647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1130747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1130847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void DeregLoop(mDNS *const m, AuthRecord *const start) 1130947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1131047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = start; 1131147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->CurrentRecord) 1131247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1131347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr = m->CurrentRecord; 1131447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("DeregLoop: %s deregistration for %p %02X %s", 1131547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt (rr->resrec.RecordType != kDNSRecordTypeDeregistering) ? "Initiating " : "Accelerating", 1131647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr, rr->resrec.RecordType, ARDisplayString(m, rr)); 1131747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rr->resrec.RecordType != kDNSRecordTypeDeregistering) 1131847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, rr, mDNS_Dereg_rapid); 1131947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else if (rr->AnnounceCount > 1) 1132047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1132147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->AnnounceCount = 1; 1132247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rr->LastAPTime = m->timenow - rr->ThisAPInterval; 1132347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1132447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because 1132547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // new records could have been added to the end of the list as a result of that call. 1132647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now 1132747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->CurrentRecord = rr->next; 1132847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1132947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1133047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1133147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_StartExit(mDNS *const m) 1133247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1133347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NetworkInterfaceInfo *intf; 1133447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 1133547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1133647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Lock(m); 1133747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1133847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_StartExit"); 1133947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->ShutdownTime = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5); 1134047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1134147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSCoreBeSleepProxyServer_internal(m, 0, 0, 0, 0); 1134247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1134347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder 1134447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ! NO_WCF 1134547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CHECK_WCF_FUNCTION(WCFConnectionDealloc) 1134647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1134747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->WCF) WCFConnectionDealloc((WCFConnection *)m->WCF); 1134847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1134947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 1135047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 1135147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1135247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED 1135347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1135447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SearchListElem *s; 1135547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt SuspendLLQs(m); 1135647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Don't need to do SleepRecordRegistrations() here 1135747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // because we deregister all records and services later in this routine 1135847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn); 1135947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1136047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // For each member of our SearchList, deregister any records it may have created, and cut them from the list. 1136147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Otherwise they'll be forcibly deregistered for us (without being cut them from the appropriate list) 1136247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // and we may crash because the list still contains dangling pointers. 1136347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (s = SearchList; s; s = s->next) 1136447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (s->AuthRecs) 1136547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1136647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ARListElem *dereg = s->AuthRecs; 1136747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt s->AuthRecs = s->AuthRecs->next; 1136847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Deregister_internal(m, &dereg->ar, mDNS_Dereg_normal); // Memory will be freed in the FreeARElemCallback 1136947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1137047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1137147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif 1137247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1137347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (intf = m->HostInterfaces; intf; intf = intf->next) 1137447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (intf->Advertise) 1137547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DeadvertiseInterface(m, intf); 1137647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1137747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Shut down all our active NAT Traversals 1137847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->NATTraversals) 1137947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1138047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt NATTraversalInfo *t = m->NATTraversals; 1138147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_StopNATOperation_internal(m, t); // This will cut 't' from the list, thereby advancing m->NATTraversals in the process 1138247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1138347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // After stopping the NAT Traversal, we zero out the fields. 1138447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // This has particularly important implications for our AutoTunnel records -- 1138547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree 1138647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // handlers to just turn around and attempt to re-register those same records. 1138747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Clearing t->ExternalPort/t->RequestedPort will cause the mStatus_MemFree callback handlers 1138847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // to not do this. 1138947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt t->ExternalAddress = zerov4Addr; 1139047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt t->ExternalPort = zeroIPPort; 1139147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt t->RequestedPort = zeroIPPort; 1139247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt t->Lifetime = 0; 1139347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt t->Result = mStatus_NoError; 1139447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1139547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1139647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Make sure there are nothing but deregistering records remaining in the list 1139747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->CurrentRecord) 1139847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_StartExit: ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 1139947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1140047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // We're in the process of shutting down, so queries, etc. are no longer available. 1140147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Consequently, determining certain information, e.g. the uDNS update server's IP 1140247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // address, will not be possible. The records on the main list are more likely to 1140347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // already contain such information, so we deregister the duplicate records first. 1140447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_StartExit: Deregistering duplicate resource records"); 1140547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DeregLoop(m, m->DuplicateRecords); 1140647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_StartExit: Deregistering resource records"); 1140747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt DeregLoop(m, m->ResourceRecords); 1140847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1140947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If we scheduled a response to send goodbye packets, we set NextScheduledResponse to now. Normally when deregistering records, 1141047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // we allow up to 100ms delay (to help improve record grouping) but when shutting down we don't want any such delay. 1141147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->NextScheduledResponse - m->timenow < mDNSPlatformOneSecond) 1141247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1141347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->NextScheduledResponse = m->timenow; 1141447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt m->SuppressSending = 0; 1141547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1141647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1141747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->ResourceRecords) LogInfo("mDNS_StartExit: Sending final record deregistrations"); 1141847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt else LogInfo("mDNS_StartExit: No deregistering records remain"); 1141947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1142047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->DuplicateRecords; rr; rr = rr->next) 1142147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_StartExit: Should not still have Duplicate Records remaining: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr)); 1142247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1142347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // If any deregistering records remain, send their deregistration announcements before we exit 1142447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m); 1142547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1142647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNS_Unlock(m); 1142747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1142847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_StartExit: done"); 1142947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1143047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1143147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_FinalExit(mDNS *const m) 1143247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1143347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 rrcache_active = 0; 1143447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 rrcache_totalused = 0; 1143547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSu32 slot; 1143647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt AuthRecord *rr; 1143747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1143847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_FinalExit: mDNSPlatformClose"); 1143947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt mDNSPlatformClose(m); 1144047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1144147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt rrcache_totalused = m->rrcache_totalused; 1144247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) 1144347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1144447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (m->rrcache_hash[slot]) 1144547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1144647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheGroup *cg = m->rrcache_hash[slot]; 1144747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt while (cg->members) 1144847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt { 1144947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt CacheRecord *cr = cg->members; 1145047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cg->members = cg->members->next; 1145147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (cr->CRActiveQuestion) rrcache_active++; 1145247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ReleaseCacheRecord(m, cr); 1145347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1145447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt cg->rrcache_tail = &cg->members; 1145547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt ReleaseCacheGroup(m, &m->rrcache_hash[slot]); 1145647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1145747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 1145847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt debugf("mDNS_FinalExit: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active); 1145947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt if (rrcache_active != m->rrcache_active) 1146047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active); 1146147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1146247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt for (rr = m->ResourceRecords; rr; rr = rr->next) 1146347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogMsg("mDNS_FinalExit failed to send goodbye for: %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr)); 1146447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 1146547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt LogInfo("mDNS_FinalExit: done"); 1146647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt } 11467