diff options
| author | pettai <pettai@NetBSD.org> | 2014-03-24 00:23:27 +0000 |
|---|---|---|
| committer | pettai <pettai@NetBSD.org> | 2014-03-24 00:23:27 +0000 |
| commit | 09fa7e98e105d1936a7dab2aa5f48698d0f027ff (patch) | |
| tree | cd86a1ac0558659005d018866df6740c623fbcf9 /external/apache2 | |
| parent | 43f5f9503bc98f1f337041a3a9b4f8803c08aeb0 (diff) | |
Import mDNSResponder-258-14 as per discussion with gdt@ and cristos@
Diffstat (limited to 'external/apache2')
17 files changed, 2104 insertions, 3492 deletions
diff --git a/external/apache2/mDNSResponder/dist/Clients/ClientCommon.c b/external/apache2/mDNSResponder/dist/Clients/ClientCommon.c index 5e645f52c9a..812efbeb470 100644 --- a/external/apache2/mDNSResponder/dist/Clients/ClientCommon.c +++ b/external/apache2/mDNSResponder/dist/Clients/ClientCommon.c @@ -36,18 +36,7 @@ * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Change History (most recent first): - -Log: ClientCommon.c,v $ -Revision 1.2 2008/05/08 00:42:03 cheshire -Removed some unnecessary header files - -Revision 1.1 2008/05/08 00:25:48 cheshire -<rdar://problem/5919272> GetNextLabel insufficiently defensive - - -*/ + */ #include <ctype.h> #include <stdio.h> // For stdout, stderr diff --git a/external/apache2/mDNSResponder/dist/Clients/ClientCommon.h b/external/apache2/mDNSResponder/dist/Clients/ClientCommon.h index eb9435e0497..afe5b7a5015 100644 --- a/external/apache2/mDNSResponder/dist/Clients/ClientCommon.h +++ b/external/apache2/mDNSResponder/dist/Clients/ClientCommon.h @@ -36,14 +36,6 @@ * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Change History (most recent first): - -Log: ClientCommon.h,v $ -Revision 1.1 2008/05/08 00:25:48 cheshire -<rdar://problem/5919272> GetNextLabel insufficiently defensive - - -*/ + */ extern const char *GetNextLabel(const char *cstr, char label[64]); diff --git a/external/apache2/mDNSResponder/dist/mDNSCore/DNSCommon.h b/external/apache2/mDNSResponder/dist/mDNSCore/DNSCommon.h index 80527fdc6bd..401d57102d6 100644 --- a/external/apache2/mDNSResponder/dist/mDNSCore/DNSCommon.h +++ b/external/apache2/mDNSResponder/dist/mDNSCore/DNSCommon.h @@ -13,146 +13,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - - Change History (most recent first): - -Log: DNSCommon.h,v $ -Revision 1.73 2009/04/24 00:28:05 cheshire -<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists -Added definitions for RRTypeAnswersQuestionType/RRAssertsNonexistence/AnyTypeRecordAnswersQuestion - -Revision 1.72 2009/04/01 21:12:56 herscher -<rdar://problem/5925472> Current Bonjour code does not compile on Windows - -Revision 1.71 2009/04/01 17:50:10 mcguire -cleanup mDNSRandom - -Revision 1.70 2009/03/04 00:40:12 cheshire -Updated DNS server error codes to be more consistent with definitions at -<http://www.iana.org/assignments/dns-parameters> - -Revision 1.69 2008/11/26 20:57:37 cheshire -For consistency with other similar macros, renamed mdnsIsDigit/mdnsIsLetter/mdnsValidHostChar -to mDNSIsDigit/mDNSIsLetter/mDNSValidHostChar - -Revision 1.68 2008/11/14 21:56:31 cheshire -Moved debugging routine ShowTaskSchedulingError() from daemon.c into DNSCommon.c - -Revision 1.67 2008/11/13 19:05:09 cheshire -Added definition of LocateOptRR() - -Revision 1.66 2008/10/22 19:56:54 cheshire -Removed unused SameRData() macro -- it duplicates the functionality of IdenticalSameNameRecord() - -Revision 1.65 2008/10/20 15:39:20 cheshire -Group "#define PutResourceRecord ..." with related definitions - -Revision 1.64 2008/10/08 01:03:33 cheshire -Change GetFirstActiveInterface() so the NetworkInterfaceInfo it returns is not "const" - -Revision 1.63 2008/09/23 02:30:07 cheshire -Get rid of PutResourceRecordCappedTTL() - -Revision 1.62 2008/09/23 02:26:09 cheshire -Don't need to export putEmptyResourceRecord (it's only used from DNSCommon.c) - -Revision 1.61 2008/08/13 00:47:53 mcguire -Handle failures when packet logging - -Revision 1.60 2008/07/24 20:23:03 cheshire -<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning - -Revision 1.59 2008/03/14 19:58:38 mcguire -<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client -Make sure we add the record when sending LLQ refreshes - -Revision 1.58 2008/03/06 21:26:10 cheshire -Moved duplicated STRINGIFY macro from individual C files to DNSCommon.h - -Revision 1.57 2007/12/13 20:20:17 cheshire -Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and -SameRData from functions to macros, which allows the code to be inlined (the compiler can't -inline a function defined in a different compilation unit) and therefore optimized better. - -Revision 1.56 2007/12/13 00:13:03 cheshire -Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody - -Revision 1.55 2007/12/13 00:09:28 cheshire -For completeness added MX, AFSDB, RT, KX to list of RRTYPES that are considered to have a target domainname in their rdata - -Revision 1.54 2007/10/05 17:56:10 cheshire -Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files - -Revision 1.53 2007/09/27 17:42:49 cheshire -Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask" - -Revision 1.52 2007/09/26 00:49:46 cheshire -Improve packet logging to show sent and received packets, -transport protocol (UDP/TCP/TLS) and source/destination address:port - -Revision 1.51 2007/09/21 21:12:36 cheshire -<rdar://problem/5498009> BTMM: Need to log updates and query packet contents - -Revision 1.50 2007/09/20 01:12:06 cheshire -Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files - -Revision 1.49 2007/08/30 00:31:20 cheshire -Improve "locking failure" debugging messages to show function name using __func__ macro - -Revision 1.48 2007/05/25 00:25:44 cheshire -<rdar://problem/5227737> Need to enhance putRData to output all current known types - -Revision 1.47 2007/05/01 21:46:31 cheshire -Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them - -Revision 1.46 2007/04/22 20:18:10 cheshire -Add comment about mDNSRandom() - -Revision 1.45 2007/04/22 06:02:02 cheshire -<rdar://problem/4615977> Query should immediately return failure when no server - -Revision 1.44 2007/03/28 01:20:05 cheshire -<rdar://problem/4883206> Improve/create logging for secure browse - -Revision 1.43 2007/03/20 17:07:15 cheshire -Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket" - -Revision 1.42 2007/03/10 03:26:44 cheshire -<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache - -Revision 1.41 2007/01/18 23:18:17 cheshire -Source code tidying: Delete extraneous white space - -Revision 1.40 2007/01/05 08:30:40 cheshire -Trim excessive "Log" checkin history from before 2006 -(checkin history still available via "cvs log ..." of course) - -Revision 1.39 2007/01/04 21:45:20 cheshire -Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros, -to do additional lock sanity checking around callback invocations - -Revision 1.38 2006/12/22 20:59:49 cheshire -<rdar://problem/4742742> Read *all* DNS keys from keychain, - not just key for the system-wide default registration domain - -Revision 1.37 2006/08/14 23:24:22 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.36 2006/07/05 22:56:07 cheshire -<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder -Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int" - -Revision 1.35 2006/06/29 07:42:14 cheshire -<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks - -Revision 1.34 2006/03/18 21:47:56 cheshire -<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions - -Revision 1.33 2006/03/10 21:51:41 cheshire -<rdar://problem/4111464> After record update, old record sometimes remains in cache -Split out SameRDataBody() into a separate routine so it can be called from other code - -*/ + */ #ifndef __DNSCOMMON_H_ #define __DNSCOMMON_H_ @@ -254,7 +115,7 @@ extern const domainname *SkipLeadingLabels(const domainname *d, int skip); extern mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32 max); extern mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText); extern mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText); -extern void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText); +extern void AppendLabelSuffix(domainlabel *const name, mDNSu32 val, const mDNSBool RichText); #define ValidateDomainName(N) (DomainNameLength(N) <= MAX_DOMAIN_NAME) // *************************************************************************** @@ -283,7 +144,7 @@ extern void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText) (r1)->namehash == (r2)->namehash && \ (r1)->rdlength == (r2)->rdlength && \ (r1)->rdatahash == (r2)->rdatahash && \ - SameRDataBody((r1), &(r2)->rdata->u) && \ + SameRDataBody((r1), &(r2)->rdata->u, SameDomainName) && \ SameDomainName((r1)->name, (r2)->name)) #define IdenticalSameNameRecord(r1,r2) ( \ @@ -291,18 +152,19 @@ extern void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText) (r1)->rrclass == (r2)->rrclass && \ (r1)->rdlength == (r2)->rdlength && \ (r1)->rdatahash == (r2)->rdatahash && \ - SameRDataBody((r1), &(r2)->rdata->u)) + SameRDataBody((r1), &(r2)->rdata->u, SameDomainName)) // A given RRType answers a QuestionType if RRType is CNAME, or types match, or QuestionType is ANY, // or the RRType is NSEC and positively asserts the nonexistence of the type being requested -#define RRTypeAnswersQuestionType(R,T) ((R)->rrtype == kDNSType_CNAME || (R)->rrtype == (T) || (T) == kDNSQType_ANY || RRAssertsNonexistence((R),(T))) +#define RRTypeAnswersQuestionType(R,Q) ((R)->rrtype == kDNSType_CNAME || (R)->rrtype == (Q) || (Q) == kDNSQType_ANY || RRAssertsNonexistence((R),(Q))) #define RRAssertsNonexistence(R,T) ((R)->rrtype == kDNSType_NSEC && (T) < kDNSQType_ANY && !((R)->rdata->u.nsec.bitmap[(T)>>3] & (128 >> ((T)&7)))) extern mDNSu32 RDataHashValue(const ResourceRecord *const rr); -extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2); +extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename); extern mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q); extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q); extern mDNSBool AnyTypeRecordAnswersQuestion (const ResourceRecord *const rr, const DNSQuestion *const q); +extern mDNSBool UnicastResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q); extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate); extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd); @@ -311,7 +173,7 @@ extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, cons ((RR)->rrtype == kDNSType_MX || (RR)->rrtype == kDNSType_AFSDB || (RR)->rrtype == kDNSType_RT || (RR)->rrtype == kDNSType_KX ) ? &(RR)->rdata->u.mx.exchange : \ ((RR)->rrtype == kDNSType_SRV ) ? &(RR)->rdata->u.srv.target : mDNSNULL ) -#define LocalRecordReady(X) ((X)->resrec.RecordType != kDNSRecordTypeUnique && (X)->resrec.RecordType != kDNSRecordTypeDeregistering) +#define LocalRecordReady(X) ((X)->resrec.RecordType != kDNSRecordTypeUnique) // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK @@ -326,24 +188,37 @@ extern mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 * // If we have a single large record to put in the packet, then we allow the packet to be up to 9K bytes, // but in the normal case we try to keep the packets below 1500 to avoid IP fragmentation on standard Ethernet + +#define AllowedRRSpace(msg) (((msg)->h.numAnswers || (msg)->h.numAuthorities || (msg)->h.numAdditionals) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData) + extern mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit); #define PutResourceRecordTTL(msg, ptr, count, rr, ttl) \ - PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), \ - ((msg)->h.numAnswers || (msg)->h.numAuthorities || (msg)->h.numAdditionals) ? (msg)->data + NormalMaxDNSMessageData : (msg)->data + AbsoluteMaxDNSMessageData) + PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), (msg)->data + AllowedRRSpace(msg)) + #define PutResourceRecordTTLJumbo(msg, ptr, count, rr, ttl) \ PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), (msg)->data + AbsoluteMaxDNSMessageData) + #define PutResourceRecord(MSG, P, C, RR) PutResourceRecordTTL((MSG), (P), (C), (RR), (RR)->rroriginalttl) +// The PutRR_OS variants assume a local variable 'm', put build the packet at m->omsg, +// and assume a local variable 'OwnerRecordSpace' indicating how many bytes (if any) to reserve to add an OWNER option at the end +#define PutRR_OS_TTL(ptr, count, rr, ttl) \ + PutResourceRecordTTLWithLimit(&m->omsg, (ptr), (count), (rr), (ttl), m->omsg.data + AllowedRRSpace(&m->omsg) - OwnerRecordSpace) + +#define PutRR_OS(P, C, RR) PutRR_OS_TTL((P), (C), (RR), (RR)->rroriginalttl) + extern mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass); extern mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass); -extern mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end); +extern mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *const msg, mDNSu8 *const ptr, mDNSu8 *const end); extern mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr); -extern mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype); +extern mDNSu8 *putDeletionRecordWithLimit(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr, mDNSu8 *limit); +extern mDNSu8 *putDeleteRRSetWithLimit(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype, mDNSu8 *limit); extern mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name); extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease); +extern mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease, mDNSu8 *limit); -extern mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, DomainAuthInfo *authInfo); +extern mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *ptr, DomainAuthInfo *authInfo, mDNSu8 *limit); // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK @@ -359,7 +234,7 @@ extern const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *pt domainname *const name); extern const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end); extern const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr, - const mDNSu8 * end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *largecr); + const mDNSu8 * end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr); extern const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end); extern const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID, DNSQuestion *question); @@ -389,20 +264,16 @@ extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 * #endif extern void ShowTaskSchedulingError(mDNS *const m); -extern void mDNS_Lock_(mDNS *const m); -extern void mDNS_Unlock_(mDNS *const m); +extern void mDNS_Lock_(mDNS *const m, const char * const functionname); +extern void mDNS_Unlock_(mDNS *const m, const char * const functionname); #if defined(_WIN32) #define __func__ __FUNCTION__ #endif -#define mDNS_Lock(X) do { \ - if ((X)->mDNS_busy != (X)->mDNS_reentrancy) LogMsg("%s: mDNS_Lock locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, (X)->mDNS_busy, (X)->mDNS_reentrancy); \ - mDNS_Lock_(X); } while (0) +#define mDNS_Lock(X) mDNS_Lock_((X), __func__) -#define mDNS_Unlock(X) do { mDNS_Unlock_(X); \ - if ((X)->mDNS_busy != (X)->mDNS_reentrancy) LogMsg("%s: mDNS_Unlock locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, (X)->mDNS_busy, (X)->mDNS_reentrancy); \ - } while (0) +#define mDNS_Unlock(X) mDNS_Unlock_((X), __func__) #define mDNS_DropLockBeforeCallback() do { m->mDNS_reentrancy++; \ if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("%s: Locking Failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, m->mDNS_busy, m->mDNS_reentrancy); \ diff --git a/external/apache2/mDNSResponder/dist/mDNSCore/mDNSDebug.h b/external/apache2/mDNSResponder/dist/mDNSCore/mDNSDebug.h index 54f9e477383..07647b52d45 100755 --- a/external/apache2/mDNSResponder/dist/mDNSCore/mDNSDebug.h +++ b/external/apache2/mDNSResponder/dist/mDNSCore/mDNSDebug.h @@ -13,150 +13,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - - Change History (most recent first): - -Log: mDNSDebug.h,v $ -Revision 1.51 2009/06/25 23:36:59 cheshire -To facilitate testing, added command-line switch "-OfferSleepProxyService" -to re-enable the previously-supported mode of operation where we offer -sleep proxy service on desktop Macs that are set to never sleep. - -Revision 1.50 2009/05/19 23:34:06 cheshire -Updated comment to show correct metric of 80 for a low-priority sleep proxy - -Revision 1.49 2009/04/24 23:32:28 cheshire -To facilitate testing, put back code to be a sleep proxy when set to never sleep, compiled out by compile-time switch - -Revision 1.48 2009/04/11 01:43:27 jessic2 -<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically - -Revision 1.47 2009/04/11 00:19:41 jessic2 -<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically - -Revision 1.46 2009/02/13 06:36:50 cheshire -Update LogSPS definition - -Revision 1.45 2009/02/13 06:03:12 cheshire -Added LogInfo for informational message logging - -Revision 1.44 2009/02/12 20:57:25 cheshire -Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch - -Revision 1.43 2008/12/10 02:27:14 cheshire -Commented out definitions of LogClientOperations, LogTimeStamps, ForceAlerts and MACOSX_MDNS_MALLOC_DEBUGGING -to allow overriding values to be easily defined in a Makefile or similar build environment - -Revision 1.42 2008/11/02 21:22:05 cheshire -Changed mallocL size parameter back to "unsigned int" - -Revision 1.41 2008/11/02 21:14:58 cheshire -Fixes to make mallocL/freeL debugging checks work on 64-bit - -Revision 1.40 2008/10/24 20:53:37 cheshire -For now, define USE_SEPARATE_UDNS_SERVICE_LIST, so that we use the old service list code for this submission - -Revision 1.39 2008/02/26 21:17:11 cheshire -Grouped all user settings together near the start of the file; added LogTimeStamps option - -Revision 1.38 2007/12/13 20:27:07 cheshire -Remove unused VerifySameNameAssumptions symbol - -Revision 1.37 2007/12/01 00:33:17 cheshire -Fixes from Bob Bradley for building on EFI - -Revision 1.36 2007/10/01 19:06:19 cheshire -Defined symbolic constant MDNS_LOG_INITIAL_LEVEL to set the logging level we start out at - -Revision 1.35 2007/07/27 20:19:56 cheshire -For now, comment out unused log levels MDNS_LOG_ERROR, MDNS_LOG_WARN, MDNS_LOG_INFO, MDNS_LOG_DEBUG - -Revision 1.34 2007/07/24 17:23:33 cheshire -<rdar://problem/5357133> Add list validation checks for debugging - -Revision 1.33 2007/06/15 21:54:50 cheshire -<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS - -Revision 1.32 2007/05/25 16:03:03 cheshire -Remove unused LogMalloc - -Revision 1.31 2007/04/06 19:50:05 cheshire -Add ProgramName declaration - -Revision 1.30 2007/03/24 01:22:44 cheshire -Add validator for uDNS data structures - -Revision 1.29 2006/08/14 23:24:23 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.28 2006/07/07 01:09:09 cheshire -<rdar://problem/4472013> Add Private DNS server functionality to dnsextd -Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd - -Revision 1.27 2006/06/29 07:42:14 cheshire -<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks - -Revision 1.26 2005/07/04 22:40:26 cheshire -Additional debugging code to help catch memory corruption - -Revision 1.25 2004/12/14 21:34:16 cheshire -Add "#define ANSWER_REMOTE_HOSTNAME_QUERIES 0" and comment - -Revision 1.24 2004/09/16 01:58:21 cheshire -Fix compiler warnings - -Revision 1.23 2004/05/18 23:51:25 cheshire -Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers - -Revision 1.22 2004/04/22 04:27:42 cheshire -Spacing tidyup - -Revision 1.21 2004/04/14 23:21:41 ksekar -Removed accidental checkin of MALLOC_DEBUGING flag in 1.20 - -Revision 1.20 2004/04/14 23:09:28 ksekar -Support for TSIG signed dynamic updates. - -Revision 1.19 2004/03/15 18:57:59 cheshire -Undo last checkin that accidentally made verbose debugging the default for all targets - -Revision 1.18 2004/03/13 01:57:33 ksekar -<rdar://problem/3192546>: DynDNS: Dynamic update of service records - -Revision 1.17 2004/01/28 21:14:23 cheshire -Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode) - -Revision 1.16 2003/12/09 01:30:06 rpantos -Fix usage of ARGS... macros to build properly on Windows. - -Revision 1.15 2003/12/08 20:55:26 rpantos -Move some definitions here from mDNSMacOSX.h. - -Revision 1.14 2003/08/12 19:56:24 cheshire -Update to APSL 2.0 - -Revision 1.13 2003/07/02 21:19:46 cheshire -<rdar://problem/3313413> Update copyright notices, etc., in source code comments - -Revision 1.12 2003/05/26 03:01:27 cheshire -<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead - -Revision 1.11 2003/05/21 17:48:10 cheshire -Add macro to enable GCC's printf format string checking - -Revision 1.10 2003/04/26 02:32:57 cheshire -Add extern void LogMsg(const char *format, ...); - -Revision 1.9 2002/09/21 20:44:49 zarzycki -Added APSL info - -Revision 1.8 2002/09/19 04:20:43 cheshire -Remove high-ascii characters that confuse some systems - -Revision 1.7 2002/09/16 18:41:42 cheshire -Merge in license terms from Quinn's copy, in preparation for Darwin release - -*/ + */ #ifndef __mDNSDebug_h #define __mDNSDebug_h @@ -198,8 +55,6 @@ typedef enum //#define ForceAlerts 1 //#define LogTimeStamps 1 -#define USE_SEPARATE_UDNS_SERVICE_LIST 1 - // Developer-settings section ends here #if MDNS_CHECK_PRINTF_STYLE_FUNCTIONS @@ -240,31 +95,31 @@ typedef enum #if (MDNS_HAS_VA_ARG_MACROS) #if (MDNS_C99_VA_ARGS) #define debug_noop( ... ) ((void)0) - #define LogMsg( ... ) LogMsgWithLevel(MDNS_LOG_MSG, __VA_ARGS__) - #define LogOperation( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, __VA_ARGS__); } while (0) - #define LogSPS( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, __VA_ARGS__); } while (0) - #define LogInfo( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, __VA_ARGS__); } while (0) + #define LogMsg( ... ) LogMsgWithLevel(MDNS_LOG_MSG, __VA_ARGS__) + #define LogOperation( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, __VA_ARGS__); } while (0) + #define LogSPS( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, __VA_ARGS__); } while (0) + #define LogInfo( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, __VA_ARGS__); } while (0) #elif (MDNS_GNU_VA_ARGS) #define debug_noop( ARGS... ) ((void)0) - #define LogMsg( ARGS... ) LogMsgWithLevel(MDNS_LOG_MSG, ARGS) + #define LogMsg( ARGS... ) LogMsgWithLevel(MDNS_LOG_MSG, ARGS) #define LogOperation( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, ARGS); } while (0) - #define LogSPS( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, ARGS); } while (0) - #define LogInfo( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, ARGS); } while (0) + #define LogSPS( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, ARGS); } while (0) + #define LogInfo( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, ARGS); } while (0) #else #error Unknown variadic macros #endif #else // If your platform does not support variadic macros, you need to define the following variadic functions. // See mDNSShared/mDNSDebug.c for sample implementation - extern void debug_noop(const char *format, ...); + #define debug_noop 1 ? (void)0 : (void) #define LogMsg LogMsg_ - #define LogOperation mDNS_LoggingEnabled == 0 ? ((void)0) : LogOperation_ - #define LogSPS mDNS_LoggingEnabled == 0 ? ((void)0) : LogSPS_ - #define LogInfo mDNS_LoggingEnabled == 0 ? ((void)0) : LogInfo_ - extern void LogMsg_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); + #define LogOperation (mDNS_LoggingEnabled == 0) ? ((void)0) : LogOperation_ + #define LogSPS (mDNS_LoggingEnabled == 0) ? ((void)0) : LogSPS_ + #define LogInfo (mDNS_LoggingEnabled == 0) ? ((void)0) : LogInfo_ + extern void LogMsg_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); extern void LogOperation_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); - extern void LogSPS_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); - extern void LogInfo_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); + extern void LogSPS_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); + extern void LogInfo_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); #endif #if MDNS_DEBUGMSGS @@ -287,6 +142,8 @@ extern int mDNS_DebugMode; // If non-zero, LogMsg() writes to stderr inst extern const char ProgramName[]; extern void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(2,3); +// LogMsgNoIdent needs to be fixed so that it logs without the ident prefix like it used to +// (or completely overhauled to use the new "log to a separate file" facility) #define LogMsgNoIdent LogMsg #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 diff --git a/external/apache2/mDNSResponder/dist/mDNSCore/uDNS.c b/external/apache2/mDNSResponder/dist/mDNSCore/uDNS.c index 7a29dad16af..dcfcf6583fd 100755 --- a/external/apache2/mDNSResponder/dist/mDNSCore/uDNS.c +++ b/external/apache2/mDNSResponder/dist/mDNSCore/uDNS.c @@ -18,1307 +18,7 @@ * Elimate all mDNSPlatformMemAllocate/mDNSPlatformMemFree from this code -- the core code * is supposed to be malloc-free so that it runs in constant memory determined at compile-time. * Any dynamic run-time requirements should be handled by the platform layer below or client layer above - - Change History (most recent first): - -Log: uDNS.c,v $ -Revision 1.617 2009/06/30 20:51:02 cheshire -Improved "Error! Tried to add a NAT traversal that's already in the active list" debugging message - -Revision 1.616 2009/05/27 20:29:36 cheshire -<rdar://problem/6926465> Sleep is delayed by 10 seconds if BTMM is on -After receiving confirmation of LLQ deletion, need to schedule another evaluation of whether we're ready to sleep yet - -Revision 1.615 2009/05/05 01:32:50 jessic2 -<rdar://problem/6830541> regservice_callback: instance->request is NULL 0 -- Clean up spurious logs resulting from fixing this bug. - -Revision 1.614 2009/04/24 02:17:57 mcguire -<rdar://problem/5264124> uDNS: Not always respecting preference order of DNS servers - -Revision 1.613 2009/04/23 22:06:29 cheshire -Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for: -<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists - -Revision 1.612 2009/04/22 01:19:57 jessic2 -<rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32 - -Revision 1.611 2009/04/15 20:42:51 mcguire -<rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures - -Revision 1.610 2009/04/15 01:10:39 jessic2 -<rdar://problem/6466541> BTMM: Add support for setting kDNSServiceErr_NoSuchRecord in DynamicStore - -Revision 1.609 2009/04/11 00:19:45 jessic2 -<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically - -Revision 1.608 2009/04/06 23:44:59 cheshire -<rdar://problem/6757838> mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance - -Revision 1.607 2009/04/02 22:36:34 jessic2 -Fix crash when calling debugf with null opt - -Revision 1.606 2009/03/26 03:59:00 jessic2 -Changes for <rdar://problem/6492552&6492593&6492609&6492613&6492628&6492640&6492699> - -Revision 1.605 2009/03/04 00:40:14 cheshire -Updated DNS server error codes to be more consistent with definitions at -<http://www.iana.org/assignments/dns-parameters> - -Revision 1.604 2009/02/27 03:08:47 cheshire -<rdar://problem/6547720> Crash while shutting down when "local" is in the user's DNS searchlist - -Revision 1.603 2009/02/27 02:56:57 cheshire -Moved struct SearchListElem definition from uDNS.c into mDNSEmbeddedAPI.h - -Revision 1.602 2009/02/13 06:29:54 cheshire -Converted LogOperation messages to LogInfo - -Revision 1.601 2009/02/12 20:57:25 cheshire -Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch - -Revision 1.600 2009/01/31 21:05:12 cheshire -Improved "Failed to obtain NAT port mapping" debugging log message - -Revision 1.599 2009/01/23 00:38:36 mcguire -<rdar://problem/5570906> BTMM: Doesn't work with Linksys WRT54GS firmware 4.71.1 - -Revision 1.598 2009/01/21 03:43:57 mcguire -<rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore - -Revision 1.597 2009/01/10 01:55:49 cheshire -Added LogOperation message showing when domains are added and removed in FoundDomain - -Revision 1.596 2008/12/19 20:23:33 mcguire -<rdar://problem/6459269> Lots of duplicate log messages about failure to bind to NAT-PMP Announcement port - -Revision 1.595 2008/12/18 23:32:19 mcguire -<rdar://problem/6019470> BTMM: Include the question in the LLQ notification acknowledgment - -Revision 1.594 2008/12/10 02:25:31 cheshire -Minor fixes to use of LogClientOperations symbol - -Revision 1.593 2008/12/10 02:11:42 cheshire -ARMv5 compiler doesn't like uncommented stuff after #endif - -Revision 1.592 2008/12/06 01:42:55 mcguire -<rdar://problem/6418958> Need to exponentially back-off after failure to get public address - -Revision 1.591 2008/12/06 00:17:11 cheshire -<rdar://problem/6380477> mDNS_StopNATOperation doesn't handle duplicate NAT mapping requests properly -Refinement: For duplicate ssh mappings we want to suppress the syslog warning message, but not the "unmap = mDNSfalse" - -Revision 1.590 2008/12/04 20:57:36 mcguire -fix build - -Revision 1.589 2008/12/04 02:24:09 cheshire -Improved NAT-PMP debugging messages - -Revision 1.588 2008/11/26 20:38:08 cheshire -Changed some "LogOperation" debugging messages to "debugf" - -Revision 1.587 2008/11/26 19:53:26 cheshire -Don't overwrite srs->NATinfo.IntPort in StartSRVNatMap() - -Revision 1.586 2008/11/25 23:43:07 cheshire -<rdar://problem/5745355> Crashes at ServiceRegistrationGotZoneData + 397 -Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object - -Revision 1.585 2008/11/25 22:46:30 cheshire -For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta" - -Revision 1.584 2008/11/24 19:46:40 cheshire -When sending query over TCP, don't include LLQ option when we're talking to a conventional DNS server or cache - -Revision 1.583 2008/11/21 00:34:58 cheshire -<rdar://problem/6380477> mDNS_StopNATOperation doesn't handle duplicate NAT mapping requests properly - -Revision 1.582 2008/11/20 02:23:37 mcguire -<rdar://problem/6041208> need to handle URLBase - -Revision 1.581 2008/11/20 01:51:19 cheshire -Exported RecreateNATMappings so it's callable from other files - -Revision 1.580 2008/11/13 19:08:45 cheshire -Fixed code to handle rdataOPT properly - -Revision 1.579 2008/11/07 00:18:01 mcguire -<rdar://problem/6351068> uDNS: Supress reverse DNS query until required - -Revision 1.578 2008/11/04 22:21:46 cheshire -Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord - -Revision 1.577 2008/10/29 21:37:01 cheshire -Removed some old debugging messages - -Revision 1.576 2008/10/23 22:25:57 cheshire -Renamed field "id" to more descriptive "updateid" - -Revision 1.575 2008/10/20 02:07:49 mkrochma -<rdar://problem/6296804> Remove Note: DNS Server <ip> for domain <d> registered more than once - -Revision 1.574 2008/10/14 19:06:45 cheshire -In uDNS_ReceiveMsg(), only do checkUpdateResult() for uDNS records - -Revision 1.573 2008/09/25 20:43:44 cheshire -<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list -In UpdateSRVRecords, call mDNS_SetFQDN(m) to update AutoTarget SRV records on the main m->ResourceRecords list - -Revision 1.572 2008/09/24 23:48:05 cheshire -Don't need to pass whole ServiceRecordSet reference to GetServiceTarget; -it only needs to access the embedded SRV member of the set - -Revision 1.571 2008/09/23 22:56:53 cheshire -<rdar://problem/5298845> Remove dnsbugtest query - -Revision 1.570 2008/09/23 01:30:18 cheshire -The putLLQ() routine was not setting the OPT record's rrclass to NormalMaxDNSMessageData - -Revision 1.569 2008/07/25 22:34:11 mcguire -fix sizecheck issues for 64bit - -Revision 1.568 2008/07/24 20:23:03 cheshire -<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning - -Revision 1.567 2008/07/01 01:40:00 mcguire -<rdar://problem/5823010> 64-bit fixes - -Revision 1.566 2008/06/26 17:24:11 mkrochma -<rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements - -Revision 1.565 2008/06/21 19:06:58 mcguire -<rdar://problem/4206534> Use all configured DNS servers - -Revision 1.564 2008/06/19 23:42:03 mcguire -<rdar://problem/4206534> Use all configured DNS servers - -Revision 1.563 2008/06/19 17:46:14 mcguire -<rdar://problem/4206534> Use all configured DNS servers -Don't do extra work for log messages if we're not going to log - -Revision 1.562 2008/06/19 17:35:19 mcguire -<rdar://problem/4206534> Use all configured DNS servers -cleanup log messages -check for null pointers - -Revision 1.561 2008/06/19 01:20:49 mcguire -<rdar://problem/4206534> Use all configured DNS servers - -Revision 1.560 2008/05/31 01:51:09 mcguire -fixed typo in log message - -Revision 1.559 2008/04/15 22:37:58 mkrochma -Change LogMsg to LogOperation - -Revision 1.558 2008/03/17 18:02:35 mkrochma -Add space to log message for consistency - -Revision 1.557 2008/03/14 19:58:38 mcguire -<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client -Make sure we add the record when sending LLQ refreshes - -Revision 1.556 2008/03/07 23:55:05 cheshire -<rdar://problem/5787898> LLQ refresh randomization not working properly - -Revision 1.555 2008/03/07 23:25:56 cheshire -Improved debugging messages - -Revision 1.554 2008/03/07 18:56:03 cheshire -<rdar://problem/5777647> dnsbugtest query every three seconds when source IP address of response doesn't match - -Revision 1.553 2008/03/06 02:48:34 mcguire -<rdar://problem/5321824> write status to the DS - -Revision 1.552 2008/03/05 01:56:42 cheshire -<rdar://problem/5687667> BTMM: Don't fallback to unencrypted operations when SRV lookup fails - -Revision 1.551 2008/03/01 01:43:04 cheshire -<rdar://problem/5631565> BTMM: Lots of "Error getting external address 3" when double-NATed prevents sleep -Added code to suppress logging of multiple identical error results - -Revision 1.550 2008/03/01 01:34:47 cheshire -<rdar://problem/5736313> BTMM: Double-NAT'd machines register all but AutoTunnel v4 address records -Further refinements - -Revision 1.549 2008/02/29 01:35:37 mcguire -<rdar://problem/5736313> BTMM: Double-NAT'd machines register all but AutoTunnel v4 address records - -Revision 1.548 2008/02/20 23:54:18 cheshire -<rdar://problem/5661518> "Failed to obtain NAT port mapping" syslog messages -Improved log message so it tells us more about what's going on - -Revision 1.547 2008/02/20 00:41:09 cheshire -Change "PrivateQueryGotZoneData ... invoked with error code" from LogMsg to LogOperation - -Revision 1.546 2008/02/19 23:26:50 cheshire -<rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries - -Revision 1.545 2007/12/22 02:25:29 cheshire -<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep - -Revision 1.544 2007/12/18 00:40:11 cheshire -<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown -Reordered code to avoid double-TSIGs in some cases - -Revision 1.543 2007/12/17 23:57:43 cheshire -<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown -Need to include TSIG signature when sending LLQ cancellations over TLS - -Revision 1.542 2007/12/15 01:12:27 cheshire -<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown - -Revision 1.541 2007/12/15 00:18:51 cheshire -Renamed question->origLease to question->ReqLease - -Revision 1.540 2007/12/14 23:55:28 cheshire -Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h - -Revision 1.539 2007/12/14 20:44:24 cheshire -<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep -SleepRecordRegistrations/WakeRecordRegistrations should only operate on uDNS records - -Revision 1.538 2007/12/14 01:13:40 cheshire -<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep -Additional fixes (existing code to deregister private records and services didn't work at all) - -Revision 1.537 2007/12/11 00:18:25 cheshire -<rdar://problem/5569316> BTMM: My iMac has a "ghost" ID associated with it -There were cases where the code was incorrectly clearing the "uselease" flag, and never resetting it. - -Revision 1.536 2007/12/10 23:07:00 cheshire -Removed some unnecessary log messages - -Revision 1.535 2007/12/06 00:22:27 mcguire -<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp) - -Revision 1.534 2007/12/04 00:49:37 cheshire -<rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1 - -Revision 1.533 2007/12/01 01:21:27 jgraessley -<rdar://problem/5623140> mDNSResponder unicast DNS improvements - -Revision 1.532 2007/11/30 20:16:44 cheshire -Fixed compile warning: declaration of 'end' shadows a previous local - -Revision 1.531 2007/11/28 22:00:09 cheshire -In StartSRVNatMap, change "mDNSu8 *p" to "const mDNSu8 *p" - -Revision 1.530 2007/11/16 22:19:40 cheshire -<rdar://problem/5547474> mDNSResponder leaks on network changes -The "connection failed" code path in MakeTCPConn was not disposing of the TCPSocket it had created - -Revision 1.529 2007/11/15 22:52:29 cheshire -<rdar://problem/5589039> ERROR: mDNSPlatformWriteTCP - send Broken pipe - -Revision 1.528 2007/11/02 21:32:30 cheshire -<rdar://problem/5575593> BTMM: Deferring deregistration of record log messages on sleep/wake - -Revision 1.527 2007/11/01 16:08:51 cheshire -Tidy up alignment of "SetRecordRetry refresh" log messages - -Revision 1.526 2007/10/31 19:26:55 cheshire -Don't need to log "Permanently abandoning service registration" message when we're intentionally deleting a service - -Revision 1.525 2007/10/30 23:58:59 cheshire -<rdar://problem/5496734> BTMM: Need to retry registrations after failures -After failure, double retry interval up to maximum of 30 minutes - -Revision 1.524 2007/10/30 20:10:47 cheshire -<rdar://problem/5496734> BTMM: Need to retry registrations after failures - -Revision 1.523 2007/10/30 00:54:31 cheshire -<rdar://problem/5496734> BTMM: Need to retry registrations after failures -Fixed timing logic to double retry interval properly - -Revision 1.522 2007/10/30 00:04:43 cheshire -<rdar://problem/5496734> BTMM: Need to retry registrations after failures -Made the code not give up and abandon the record when it gets an error in regState_UpdatePending state - -Revision 1.521 2007/10/29 23:58:52 cheshire -<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events -Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet - -Revision 1.520 2007/10/29 21:48:36 cheshire -<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep -Added 10% random variation on LLQ renewal time, to reduce unintended timing correlation between multiple machines - -Revision 1.519 2007/10/29 21:37:00 cheshire -<rdar://problem/5496734> BTMM: Need to retry registrations after failures -Added 10% random variation on record refresh time, to reduce accidental timing correlation between multiple machines - -Revision 1.518 2007/10/26 23:41:29 cheshire -<rdar://problem/5496734> BTMM: Need to retry registrations after failures - -Revision 1.517 2007/10/25 23:30:12 cheshire -Private DNS registered records now deregistered on sleep and re-registered on wake - -Revision 1.516 2007/10/25 22:53:52 cheshire -<rdar://problem/5496734> BTMM: Need to retry registrations after failures -Don't unlinkSRS and permanently give up at the first sign of trouble - -Revision 1.515 2007/10/25 21:08:07 cheshire -Don't try to send record registrations/deletions before we have our server address - -Revision 1.514 2007/10/25 20:48:47 cheshire -For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer' - -Revision 1.513 2007/10/25 20:06:13 cheshire -Don't try to do SOA queries using private DNS (TLS over TCP) queries - -Revision 1.512 2007/10/25 18:25:15 cheshire -<rdar://problem/5496734> BTMM: Need to retry registrations after failures -Don't need a NAT mapping for autotunnel services - -Revision 1.511 2007/10/25 00:16:23 cheshire -<rdar://problem/5496734> BTMM: Need to retry registrations after failures -Fixed retry timing logic; when DNS server returns an error code, we should retry later, -instead of just deleting our record ("UnlinkAuthRecord") and completely giving up - -Revision 1.510 2007/10/24 22:40:06 cheshire -Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData -Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData - -Revision 1.509 2007/10/24 00:54:07 cheshire -<rdar://problem/5496734> BTMM: Need to retry registrations after failures - -Revision 1.508 2007/10/24 00:05:03 cheshire -<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep -When sending TLS/TCP LLQ setup request over VPN, need to set EventPort to 5353, not zero - -Revision 1.507 2007/10/23 00:33:36 cheshire -Improved debugging messages - -Revision 1.506 2007/10/22 19:54:13 cheshire -<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep -Only put EventPort in LLQ request when sending from an RFC 1918 source address, not when sending over VPN - -Revision 1.505 2007/10/19 22:08:49 cheshire -<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep -Additional fixes and refinements - -Revision 1.504 2007/10/18 23:06:43 cheshire -<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep -Additional fixes and refinements - -Revision 1.503 2007/10/18 20:23:17 cheshire -Moved SuspendLLQs into mDNS.c, since it's only called from one place - -Revision 1.502 2007/10/17 22:49:54 cheshire -<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep - -Revision 1.501 2007/10/17 22:37:23 cheshire -<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events - -Revision 1.500 2007/10/17 21:53:51 cheshire -Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData - -Revision 1.499 2007/10/16 21:16:50 cheshire -Get rid of unused uDNS_Sleep() routine - -Revision 1.498 2007/10/16 20:59:41 cheshire -Export SuspendLLQs/SleepServiceRegistrations/SleepRecordRegistrations so they're callable from other files - -Revision 1.497 2007/10/05 18:09:44 cheshire -<rdar://problem/5524841> Services advertised with wrong target host - -Revision 1.496 2007/10/04 22:38:59 cheshire -Added LogOperation message showing new q->ThisQInterval after sending uDNS query packet - -Revision 1.495 2007/10/03 00:16:19 cheshire -In PrivateQueryGotZoneData, need to grab lock before calling SetNextQueryTime - -Revision 1.494 2007/10/02 21:11:08 cheshire -<rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing - -Revision 1.493 2007/10/02 19:50:23 cheshire -Improved debugging message - -Revision 1.492 2007/09/29 03:15:43 cheshire -<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal -Use AutoTunnelUnregistered macro instead of checking record state directly - -Revision 1.491 2007/09/29 01:33:45 cheshire -<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal - -Revision 1.490 2007/09/29 01:06:17 mcguire -<rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute - -Revision 1.489 2007/09/27 22:02:33 cheshire -<rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord - -Revision 1.488 2007/09/27 21:20:17 cheshire -Improved debugging syslog messages - -Revision 1.487 2007/09/27 18:55:11 cheshire -<rdar://problem/5477165> BTMM: Multiple SRV records get registered after changing Computer Name - -Revision 1.486 2007/09/27 17:42:49 cheshire -Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask" - -Revision 1.485 2007/09/27 02:16:30 cheshire -<rdar://problem/5500111> BTMM: LLQ refreshes being sent in the clear to the wrong port - -Revision 1.484 2007/09/27 00:25:39 cheshire -Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for: -<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers - -Revision 1.483 2007/09/26 23:16:58 cheshire -<rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac - -Revision 1.482 2007/09/26 22:06:02 cheshire -<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names - -Revision 1.481 2007/09/26 00:49:46 cheshire -Improve packet logging to show sent and received packets, -transport protocol (UDP/TCP/TLS) and source/destination address:port - -Revision 1.480 2007/09/21 21:08:52 cheshire -Get rid of unnecessary DumpPacket() calls -- it makes more sense -to do this in mDNSSendDNSMessage and mDNSCoreReceive instead - -Revision 1.479 2007/09/21 20:01:17 cheshire -<rdar://problem/5496750> BTMM: Skip directly to member name in SOA queries to avoid sending names in the clear - -Revision 1.478 2007/09/21 19:29:14 cheshire -Added dump of uDNS questions when in MDNS_LOG_VERBOSE_DEBUG mode - -Revision 1.477 2007/09/20 02:29:37 cheshire -<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network - -Revision 1.476 2007/09/20 01:19:49 cheshire -Improve debugging messages: report startLLQHandshake errors; show state in uDNS_StopLongLivedQuery message - -Revision 1.475 2007/09/19 23:51:26 cheshire -<rdar://problem/5480517> BTMM: Need to log a message when NAT port mapping fails - -Revision 1.474 2007/09/19 20:32:09 cheshire -Export GetAuthInfoForName so it's callable from other files - -Revision 1.473 2007/09/18 21:42:29 cheshire -To reduce programming mistakes, renamed ExtPort to RequestedPort - -Revision 1.472 2007/09/14 21:26:08 cheshire -<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways - -Revision 1.471 2007/09/14 01:07:10 cheshire -If UPnP NAT gateway returns 0.0.0.0 as external address (e.g. because it hasn't -got a DHCP address yet) then retry periodically until it gives us a real address. - -Revision 1.470 2007/09/13 00:36:26 cheshire -<rdar://problem/5477360> NAT Reboot detection logic incorrect - -Revision 1.469 2007/09/13 00:28:50 cheshire -<rdar://problem/5477354> Host records not updated on NAT address change - -Revision 1.468 2007/09/13 00:16:41 cheshire -<rdar://problem/5468706> Miscellaneous NAT Traversal improvements - -Revision 1.467 2007/09/12 23:03:08 cheshire -<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index - -Revision 1.466 2007/09/12 22:19:29 cheshire -<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements - -Revision 1.465 2007/09/12 19:22:19 cheshire -Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport -Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers - -Revision 1.464 2007/09/12 01:22:13 cheshire -Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0 - -Revision 1.463 2007/09/11 20:23:28 vazquez -<rdar://problem/5466719> CrashTracer: 3 crashes in mDNSResponder at mDNSResponder: natTraversalHandlePortMapReply + 107 -Make sure we clean up NATTraversals before free'ing HostnameInfo - -Revision 1.462 2007/09/11 19:19:16 cheshire -Correct capitalization of "uPNP" to "UPnP" - -Revision 1.461 2007/09/10 22:08:17 cheshire -Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds - -Revision 1.460 2007/09/07 21:47:43 vazquez -<rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on -Try to allocate using port 5350 if we get a failure, and only log message if that fails too. - -Revision 1.459 2007/09/07 01:01:05 cheshire -<rdar://problem/5464844> BTMM: Services being registered and deregistered in a loop -In hndlServiceUpdateReply, need to clear SRVUpdateDeferred - -Revision 1.458 2007/09/06 19:14:33 cheshire -Fixed minor error introduced in 1.379 (an "if" statement was deleted but the "else" following it was left there) - -Revision 1.457 2007/09/05 21:48:01 cheshire -<rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone. -Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs -to update the cache lifetimes of all relevant records every time it successfully renews an LLQ, -otherwise those records will expire and vanish from the cache. - -Revision 1.456 2007/09/05 21:00:17 cheshire -<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions -Additional refinement: ThisQInterval needs to be restored in tcpCallback, not in PrivateQueryGotZoneData - -Revision 1.455 2007/09/05 20:53:06 cheshire -Tidied up alignment of code layout; code was clearing m->tcpAddrInfo.sock instead of m->tcpDeviceInfo.sock - -Revision 1.454 2007/09/05 02:32:55 cheshire -Fixed posix build error (mixed declarations and code) - -Revision 1.453 2007/09/05 02:26:57 cheshire -<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions -In PrivateQueryGotZoneData, restore q->ThisQInterval to non-zero value after GetZoneData completes - -Revision 1.452 2007/08/31 22:58:22 cheshire -If we have an existing TCP connection we should re-use it instead of just bailing out -After receiving dnsbugtest response, need to set m->NextScheduledQuery to cause queries to be re-issued - -Revision 1.451 2007/08/31 18:49:49 vazquez -<rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM - -Revision 1.450 2007/08/30 22:50:04 mcguire -<rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup - -Revision 1.449 2007/08/30 00:43:17 cheshire -Need to clear m->rec.r.resrec.RecordType before returning from uDNS_recvLLQResponse - -Revision 1.448 2007/08/30 00:18:46 cheshire -<rdar://problem/5448804> Error messages: "SendServiceRegistration: Already have TCP connection..." - -Revision 1.447 2007/08/29 01:18:33 cheshire -<rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings -Only create NAT mappings for SRV records with AutoTarget set to Target_AutoHostAndNATMAP - -Revision 1.446 2007/08/28 23:58:42 cheshire -Rename HostTarget -> AutoTarget - -Revision 1.445 2007/08/28 23:53:21 cheshire -Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete - -Revision 1.444 2007/08/27 20:29:20 cheshire -Additional debugging messages - -Revision 1.443 2007/08/24 23:18:28 cheshire -mDNS_SetSecretForDomain is called with lock held; needs to use -GetAuthInfoForName_internal() instead of external version GetAuthInfoForName() - -Revision 1.442 2007/08/24 22:43:06 cheshire -Tidied up coded layout - -Revision 1.441 2007/08/24 01:20:55 cheshire -<rdar://problem/5434381> BTMM: Memory corruption in KeychainChanged event handling - -Revision 1.440 2007/08/24 00:15:20 cheshire -Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held - -Revision 1.439 2007/08/23 21:47:09 vazquez -<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network -make sure we clean up port mappings on base stations by sending a lease value of 0, -and only send NAT-PMP packets on private networks; also save some memory by -not using packet structs in NATTraversals. - -Revision 1.438 2007/08/22 17:50:08 vazquez -<rdar://problem/5399276> Need to handle errors returned by NAT-PMP routers properly -Propagate router errors to clients, and stop logging spurious "message too short" logs. - -Revision 1.437 2007/08/18 00:54:15 mcguire -<rdar://problem/5413147> BTMM: Should not register private addresses or zeros - -Revision 1.436 2007/08/08 21:07:48 vazquez -<rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour - -Revision 1.435 2007/08/03 02:04:09 vazquez -<rdar://problem/5371843> BTMM: Private LLQs never fall back to polling -Fix case where NAT-PMP returns an external address but does not support -port mappings. Undo previous change and now, if the router returns an -error in the reply packet we respect it. - -Revision 1.434 2007/08/02 21:03:05 vazquez -Change NAT logic to fix case where base station with port mapping turned off -returns an external address but does not make port mappings. - -Revision 1.433 2007/08/02 03:30:11 vazquez -<rdar://problem/5371843> BTMM: Private LLQs never fall back to polling - -Revision 1.432 2007/08/01 18:15:19 cheshire -Fixed crash in tcpCallback; fixed some problems with LLQ setup behind NAT - -Revision 1.431 2007/08/01 16:11:06 cheshire -Fixed "mixed declarations and code" compiler error in Posix build - -Revision 1.430 2007/08/01 16:09:13 cheshire -Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly - -Revision 1.429 2007/08/01 03:09:22 cheshire -<rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port - -Revision 1.428 2007/08/01 01:43:36 cheshire -Need to do mDNS_DropLockBeforeCallback/ReclaimLock around invokation of NAT client callback - -Revision 1.427 2007/08/01 01:31:13 cheshire -Need to initialize traversal->tcpInfo fields or code may crash - -Revision 1.426 2007/08/01 01:15:57 cheshire -<rdar://problem/5375791> Need to invoke NAT client callback when not on RFC1918 private network - -Revision 1.425 2007/08/01 00:04:14 cheshire -<rdar://problem/5261696> Crash in tcpKQSocketCallback -Half-open TCP connections were not being cancelled properly - -Revision 1.424 2007/07/31 02:28:35 vazquez -<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot - -Revision 1.423 2007/07/30 23:31:26 cheshire -Code for respecting TTL received in uDNS responses should exclude LLQ-type responses - -Revision 1.422 2007/07/28 01:25:57 cheshire -<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT - -Revision 1.421 2007/07/28 00:04:14 cheshire -Various fixes for comments and debugging messages - -Revision 1.420 2007/07/27 23:59:18 cheshire -Added compile-time structure size checks - -Revision 1.419 2007/07/27 20:52:29 cheshire -Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events - -Revision 1.418 2007/07/27 20:32:05 vazquez -Flag a UPnP NAT traversal before starting a UPnP port mapping, and make sure all -calls to mDNS_StopNATOperation() go through the UPnP code - -Revision 1.417 2007/07/27 20:19:42 cheshire -Use MDNS_LOG_VERBOSE_DEBUG for dumping out packets instead of MDNS_LOG_DEBUG - -Revision 1.416 2007/07/27 19:59:28 cheshire -MUST NOT touch m->CurrentQuestion (or q) after calling AnswerCurrentQuestionWithResourceRecord() - -Revision 1.415 2007/07/27 19:51:01 cheshire -Use symbol QC_addnocache instead of literal constant "2" - -Revision 1.414 2007/07/27 19:30:39 cheshire -Changed mDNSQuestionCallback parameter from mDNSBool to QC_result, -to properly reflect tri-state nature of the possible responses - -Revision 1.413 2007/07/27 18:44:01 cheshire -Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord" - -Revision 1.412 2007/07/27 18:38:56 cheshire -Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion" - -Revision 1.411 2007/07/27 00:57:13 cheshire -Create hostname address records using standard kHostNameTTL (2 minutes) instead of 1 second - -Revision 1.410 2007/07/25 21:41:00 vazquez -Make sure we clean up opened sockets when there are network transitions and when changing -port mappings - -Revision 1.409 2007/07/25 03:05:02 vazquez -Fixes for: -<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow -<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow -and a myriad of other security problems - -Revision 1.408 2007/07/24 21:47:51 cheshire -Don't do mDNS_StopNATOperation() for operations we never started - -Revision 1.407 2007/07/24 17:23:33 cheshire -<rdar://problem/5357133> Add list validation checks for debugging - -Revision 1.406 2007/07/24 04:14:30 cheshire -<rdar://problem/5356281> LLQs not working in with NAT Traversal - -Revision 1.405 2007/07/24 01:29:03 cheshire -<rdar://problem/5356026> DNSServiceNATPortMappingCreate() returns stale external address information - -Revision 1.404 2007/07/20 23:10:51 cheshire -Fix code layout - -Revision 1.403 2007/07/20 20:12:37 cheshire -Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic" - -Revision 1.402 2007/07/20 00:54:20 cheshire -<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings - -Revision 1.401 2007/07/18 03:23:33 cheshire -In GetServiceTarget, need to call SetupLocalAutoTunnelInterface_internal to bring up tunnel on demand, if necessary - -Revision 1.400 2007/07/18 02:30:25 cheshire -Defer AutoTunnel server record advertising until we have at least one service to advertise -Do AutoTunnel target host selection in GetServiceTarget (instead of uDNS_RegisterService) - -Revision 1.399 2007/07/18 01:02:28 cheshire -<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings -Declare records as kDNSRecordTypeKnownUnique so we don't get name conflicts with ourselves - -Revision 1.398 2007/07/16 23:54:48 cheshire -<rdar://problem/5338850> Crash when removing or changing DNS keys - -Revision 1.397 2007/07/16 20:13:31 vazquez -<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite - -Revision 1.396 2007/07/14 00:33:04 cheshire -Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working - -Revision 1.395 2007/07/12 23:56:23 cheshire -Change "GetZoneData GOT SRV" message to debugf to reduce verbosity in syslog - -Revision 1.394 2007/07/12 23:36:08 cheshire -Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog - -Revision 1.393 2007/07/12 22:15:10 cheshire -Modified mDNS_SetSecretForDomain() so it can be called to update an existing entry - -Revision 1.392 2007/07/12 02:51:27 cheshire -<rdar://problem/5303834> Automatically configure IPSec policy when resolving services - -Revision 1.391 2007/07/11 23:16:31 cheshire -<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings -Need to prepend _autotunnel._udp to start of AutoTunnel SRV record name - -Revision 1.390 2007/07/11 22:47:55 cheshire -<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services -In mDNS_SetSecretForDomain(), don't register records until after we've validated the parameters - -Revision 1.389 2007/07/11 21:33:10 cheshire -<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings -Set up and register AutoTunnelTarget and AutoTunnelService DNS records - -Revision 1.388 2007/07/11 19:27:10 cheshire -<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services -For temporary testing fake up an IPv4LL address instead of IPv6 ULA - -Revision 1.387 2007/07/11 03:04:08 cheshire -<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services -Add AutoTunnel parameter to mDNS_SetSecretForDomain; Set up AutoTunnel information for domains that require it - -Revision 1.386 2007/07/10 01:57:28 cheshire -<rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server -Turned vast chunks of replicated code into a subroutine MakeTCPConn(...); -Made routines hold on to the reference it returns instead of leaking it - -Revision 1.385 2007/07/09 23:50:18 cheshire -unlinkSRS needs to call mDNS_StopNATOperation_internal(), not mDNS_StopNATOperation() - -Revision 1.384 2007/07/06 21:20:21 cheshire -Fix scheduling error (was causing "Task Scheduling Error: Continuously busy for more than a second") - -Revision 1.383 2007/07/06 18:59:59 cheshire -Avoid spinning in an infinite loop when uDNS_SendNATMsg() returns an error - -Revision 1.382 2007/07/04 00:49:43 vazquez -Clean up extraneous comments - -Revision 1.381 2007/07/03 00:41:14 vazquez - More changes for <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes) - Safely deal with packet replies and client callbacks - -Revision 1.380 2007/07/02 22:08:47 cheshire -Fixed crash in "Received public IP address" message - -Revision 1.379 2007/06/29 00:08:49 vazquez -<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes) - -Revision 1.378 2007/06/27 20:25:10 cheshire -Expanded dnsbugtest comment, explaining requirement that we also need these -test queries to black-hole before they get to the root name servers. - -Revision 1.377 2007/06/22 21:27:21 cheshire -Modified "could not convert shared secret from base64" log message - -Revision 1.376 2007/06/20 01:10:12 cheshire -<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code - -Revision 1.375 2007/06/15 21:54:51 cheshire -<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS - -Revision 1.374 2007/06/12 02:15:26 cheshire -Fix incorrect "DNS Server passed" LogOperation message - -Revision 1.373 2007/05/31 00:25:43 cheshire -<rdar://problem/5238688> Only send dnsbugtest query for questions where it's warranted - -Revision 1.372 2007/05/25 17:03:45 cheshire -lenptr needs to be declared unsigned, otherwise sign extension can mess up the shifting and ORing operations - -Revision 1.371 2007/05/24 00:11:44 cheshire -Remove unnecessary lenbuf field from tcpInfo_t - -Revision 1.370 2007/05/23 00:30:59 cheshire -Don't change question->TargetQID when repeating query over TCP - -Revision 1.369 2007/05/21 18:04:40 cheshire -Updated comments -- port_mapping_create_reply renamed to port_mapping_reply - -Revision 1.368 2007/05/17 19:12:16 cheshire -Updated comment about finding matching pair of sockets - -Revision 1.367 2007/05/15 23:38:00 cheshire -Need to grab lock before calling SendRecordRegistration(); - -Revision 1.366 2007/05/15 00:43:05 cheshire -<rdar://problem/4983538> uDNS serviceRegistrationCallback locking failures - -Revision 1.365 2007/05/10 21:19:18 cheshire -Rate-limit DNS test queries to at most one per three seconds -(useful when we have a dozen active WAB queries, and then we join a new network) - -Revision 1.364 2007/05/07 20:43:45 cheshire -<rdar://problem/4241419> Reduce the number of queries and announcements - -Revision 1.363 2007/05/04 22:12:48 cheshire -Work towards solving <rdar://problem/5176892> "uDNS_CheckQuery: LastQTime" log messages -When code gets in this invalid state, double ThisQInterval each time, to avoid excessive logging - -Revision 1.362 2007/05/04 21:23:05 cheshire -<rdar://problem/5167263> Private DNS always returns no answers in the initial LLQ setup response -Preparatory work to enable us to do a four-way LLQ handshake over TCP, if we decide that's what we want - -Revision 1.361 2007/05/03 23:50:48 cheshire -<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record -In the case of negative answers for the address record, set the server address to zerov4Addr - -Revision 1.360 2007/05/03 22:40:38 cheshire -<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record - -Revision 1.359 2007/05/02 22:21:33 cheshire -<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData - -Revision 1.358 2007/05/01 21:46:31 cheshire -Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them - -Revision 1.357 2007/05/01 01:33:49 cheshire -Removed "#define LLQ_Info DNSQuestion" and manually reconciled code that was still referring to "LLQ_Info" - -Revision 1.356 2007/04/30 21:51:06 cheshire -Updated comments - -Revision 1.355 2007/04/30 21:33:38 cheshire -Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop -is iterating through the m->ServiceRegistrations list - -Revision 1.354 2007/04/30 01:30:04 cheshire -GetZoneData_QuestionCallback needs to call client callback function on error, so client knows operation is finished -RecordRegistrationCallback and serviceRegistrationCallback need to clear nta reference when they're invoked - -Revision 1.353 2007/04/28 01:28:25 cheshire -Fixed memory leak on error path in FoundDomain - -Revision 1.352 2007/04/27 19:49:53 cheshire -In uDNS_ReceiveTestQuestionResponse, also check that srcport matches - -Revision 1.351 2007/04/27 19:28:02 cheshire -Any code that calls StartGetZoneData needs to keep a handle to the structure, so -it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop --- it would start a query and then quickly cancel it, and then when -StartGetZoneData completed, it had a dangling pointer and crashed.) - -Revision 1.350 2007/04/26 22:47:14 cheshire -Defensive coding: tcpCallback only needs to check "if (closed)", not "if (!n && closed)" - -Revision 1.349 2007/04/26 16:04:06 cheshire -In mDNS_AddDNSServer, check whether port matches -In uDNS_CheckQuery, handle case where startLLQHandshake changes q->llq->state to LLQ_Poll - -Revision 1.348 2007/04/26 04:01:59 cheshire -Copy-and-paste error: Test should be "if (result == DNSServer_Passed)" not "if (result == DNSServer_Failed)" - -Revision 1.347 2007/04/26 00:35:15 cheshire -<rdar://problem/5140339> uDNS: Domain discovery not working over VPN -Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server -inside the firewall may give answers where a public one gives none, and vice versa.) - -Revision 1.346 2007/04/25 19:16:59 cheshire -Don't set SuppressStdPort53Queries unless we do actually send a DNS packet - -Revision 1.345 2007/04/25 18:05:11 cheshire -Don't try to restart inactive (duplicate) queries - -Revision 1.344 2007/04/25 17:54:07 cheshire -Don't cancel Private LLQs using a clear-text UDP packet - -Revision 1.343 2007/04/25 16:40:08 cheshire -Add comment explaining uDNS_recvLLQResponse logic - -Revision 1.342 2007/04/25 02:14:38 cheshire -<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query -Additional fixes to make LLQs work properly - -Revision 1.341 2007/04/24 02:07:42 cheshire -<rdar://problem/4246187> Identical client queries should reference a single shared core query -Deleted some more redundant code - -Revision 1.340 2007/04/23 22:01:23 cheshire -<rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour -As of March 2007, AirPort base stations now block incoming IPv6 connections by default, so there's no point -advertising IPv6 addresses in DNS any more -- we have to assume that most of the time a host's IPv6 address -probably won't work for incoming connections (but its IPv4 address probably will, using NAT-PMP). - -Revision 1.339 2007/04/22 06:02:03 cheshire -<rdar://problem/4615977> Query should immediately return failure when no server - -Revision 1.338 2007/04/21 19:44:11 cheshire -Improve uDNS_HandleNATPortMapReply log message - -Revision 1.337 2007/04/21 02:03:00 cheshire -Also need to set AddressRec->resrec.RecordType in the NAT case too - -Revision 1.336 2007/04/20 21:16:12 cheshire -Fixed bogus double-registration of host name -- was causing these warning messages in syslog: -Error! Tried to register AuthRecord 0181FB0C host.example.com. (Addr) that's already in the list - -Revision 1.335 2007/04/19 23:57:20 cheshire -Temporary workaround for some AirPort base stations that don't seem to like us requesting public port zero - -Revision 1.334 2007/04/19 23:21:51 cheshire -Fixed a couple of places where the StartGetZoneData check was backwards - -Revision 1.333 2007/04/19 22:50:53 cheshire -<rdar://problem/4246187> Identical client queries should reference a single shared core query - -Revision 1.332 2007/04/19 20:34:32 cheshire -Add debugging log message in uDNS_CheckQuery() - -Revision 1.331 2007/04/19 20:06:41 cheshire -Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer) - -Revision 1.330 2007/04/19 19:51:54 cheshire -Get rid of unnecessary initializeQuery() routine - -Revision 1.329 2007/04/19 18:03:52 cheshire -Improved "mDNS_AddSearchDomain" log message - -Revision 1.328 2007/04/18 20:57:20 cheshire -Commented out "GetAuthInfoForName none found" debugging message - -Revision 1.327 2007/04/17 19:21:29 cheshire -<rdar://problem/5140339> Domain discovery not working over VPN - -Revision 1.326 2007/04/16 20:49:39 cheshire -Fix compile errors for mDNSPosix build - -Revision 1.325 2007/04/05 22:55:35 cheshire -<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information - -Revision 1.324 2007/04/05 20:43:30 cheshire -Collapse sprawling code onto one line -- this is part of a bigger block of identical -code that has been copied-and-pasted into six different places in the same file. -This really needs to be turned into a subroutine. - -Revision 1.323 2007/04/04 21:48:52 cheshire -<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list - -Revision 1.322 2007/04/03 19:53:06 cheshire -Use mDNSSameIPPort (and similar) instead of accessing internal fields directly - -Revision 1.321 2007/04/02 23:44:09 cheshire -Minor code tidying - -Revision 1.320 2007/03/31 01:26:13 cheshire -Take out GetAuthInfoForName syslog message - -Revision 1.319 2007/03/31 01:10:53 cheshire -Add debugging - -Revision 1.318 2007/03/31 00:17:11 cheshire -Remove some LogMsgs - -Revision 1.317 2007/03/29 00:09:31 cheshire -Improve "uDNS_InitLongLivedQuery" log message - -Revision 1.316 2007/03/28 21:16:27 cheshire -Remove DumpPacket() call now that OPT pseudo-RR rrclass bug is fixed - -Revision 1.315 2007/03/28 21:02:18 cheshire -<rdar://problem/3810563> Wide-Area Bonjour should work on multi-subnet private network - -Revision 1.314 2007/03/28 15:56:37 cheshire -<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output - -Revision 1.313 2007/03/28 01:27:32 cheshire -<rdar://problem/4996439> Unicast DNS polling server every three seconds -StartLLQPolling was using INIT_UCAST_POLL_INTERVAL instead of LLQ_POLL_INTERVAL for the retry interval - -Revision 1.312 2007/03/27 23:48:21 cheshire -Use mDNS_StopGetDomains(), not mDNS_StopQuery() - -Revision 1.311 2007/03/27 22:47:51 cheshire -Remove unnecessary "*(long*)0 = 0;" to generate crash and stack trace - -Revision 1.310 2007/03/24 01:24:13 cheshire -Add validator for uDNS data structures; fixed crash in RegisterSearchDomains() - -Revision 1.309 2007/03/24 00:47:53 cheshire -<rdar://problem/4983538> serviceRegistrationCallback: Locking Failure! mDNS_busy (1) != mDNS_reentrancy (2) -Locking in this file is all messed up. For now we'll just work around the issue. - -Revision 1.308 2007/03/24 00:41:33 cheshire -Minor code cleanup (move variable declarations to minimum enclosing scope) - -Revision 1.307 2007/03/21 23:06:00 cheshire -Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields - -Revision 1.306 2007/03/21 00:30:03 cheshire -<rdar://problem/4789455> Multiple errors in DNameList-related code - -Revision 1.305 2007/03/20 17:07:15 cheshire -Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket" - -Revision 1.304 2007/03/17 00:02:11 cheshire -<rdar://problem/5067013> NAT-PMP: Lease TTL is being ignored - -Revision 1.303 2007/03/10 03:26:44 cheshire -<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache - -Revision 1.302 2007/03/10 02:29:58 cheshire -Added comments about NAT-PMP response functions - -Revision 1.301 2007/03/10 02:02:58 cheshire -<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache -Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer - -Revision 1.300 2007/03/08 18:56:00 cheshire -Fixed typo: "&v4.ip.v4.b[0]" is always non-zero (ampersand should not be there) - -Revision 1.299 2007/02/28 01:45:47 cheshire -<rdar://problem/4683261> NAT-PMP: Port mapping refreshes should contain actual public port -<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c - -Revision 1.298 2007/02/14 03:16:39 cheshire -<rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code - -Revision 1.297 2007/02/08 21:12:28 cheshire -<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake - -Revision 1.296 2007/01/29 16:03:22 cheshire -Fix unused parameter warning - -Revision 1.295 2007/01/27 03:34:27 cheshire -Made GetZoneData use standard queries (and cached results); -eliminated GetZoneData_Callback() packet response handler - -Revision 1.294 2007/01/25 00:40:16 cheshire -Unified CNAME-following functionality into cache management code (which means CNAME-following -should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine. - -Revision 1.293 2007/01/23 02:56:11 cheshire -Store negative results in the cache, instead of generating them out of pktResponseHndlr() - -Revision 1.292 2007/01/20 01:32:40 cheshire -Update comments and debugging messages - -Revision 1.291 2007/01/20 00:07:02 cheshire -When we have credentials in the keychain for a domain, we attempt private queries, but -if the authoritative server is not set up for private queries (i.e. no _dns-query-tls -or _dns-llq-tls record) then we need to fall back to conventional non-private queries. - -Revision 1.290 2007/01/19 23:41:45 cheshire -Need to clear m->rec.r.resrec.RecordType after calling GetLLQOptData() - -Revision 1.289 2007/01/19 23:32:07 cheshire -Eliminate pointless timenow variable - -Revision 1.288 2007/01/19 23:26:08 cheshire -Right now tcpCallback does not run holding the lock, so no need to drop the lock before invoking callbacks - -Revision 1.287 2007/01/19 22:55:41 cheshire -Eliminate redundant identical parameters to GetZoneData_StartQuery() - -Revision 1.286 2007/01/19 21:17:33 cheshire -StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion - -Revision 1.285 2007/01/19 18:39:11 cheshire -Fix a bunch of parameters that should have been declared "const" - -Revision 1.284 2007/01/19 18:28:28 cheshire -Improved debugging messages - -Revision 1.283 2007/01/19 18:09:33 cheshire -Fixed getLLQAtIndex (now called GetLLQOptData): -1. It incorrectly assumed all EDNS0 OPT records are the same size (it ignored optlen) -2. It used inefficient memory copying instead of just returning a pointer - -Revision 1.282 2007/01/17 22:06:01 cheshire -Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort" - -Revision 1.281 2007/01/17 21:58:13 cheshire -For clarity, rename ntaContext field "isPrivate" to "ntaPrivate" - -Revision 1.280 2007/01/17 21:46:02 cheshire -Remove redundant duplicated "isPrivate" field from LLQ_Info - -Revision 1.279 2007/01/17 21:35:31 cheshire -For clarity, rename zoneData_t field "isPrivate" to "zonePrivate" - -Revision 1.278 2007/01/16 03:04:16 cheshire -<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries -Don't cache result of ntaContextSRV(context) in a local variable -- -the macro evaluates to a different result after we clear "context->isPrivate" - -Revision 1.277 2007/01/10 22:51:58 cheshire -<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries - -Revision 1.276 2007/01/10 02:09:30 cheshire -Better LogOperation record of keys read from System Keychain - -Revision 1.275 2007/01/09 22:37:18 cheshire -Provide ten-second grace period for deleted keys, to give mDNSResponder -time to delete host name before it gives up access to the required key. - -Revision 1.274 2007/01/09 01:16:32 cheshire -Improve "ERROR m->CurrentQuestion already set" debugging messages - -Revision 1.273 2007/01/08 23:58:00 cheshire -Don't request regDomain and browseDomains in uDNS_SetupDNSConfig() -- it just ignores those results - -Revision 1.272 2007/01/05 08:30:42 cheshire -Trim excessive "Log" checkin history from before 2006 -(checkin history still available via "cvs log ..." of course) - -Revision 1.271 2007/01/05 06:34:03 cheshire -Improve "ERROR m->CurrentQuestion already set" debugging messages - -Revision 1.270 2007/01/05 05:44:33 cheshire -Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c, -so that mDNSPosix embedded clients will compile again - -Revision 1.269 2007/01/04 23:11:13 cheshire -<rdar://problem/4720673> uDNS: Need to start caching unicast records -When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries - -Revision 1.268 2007/01/04 22:06:38 cheshire -Fixed crash in LLQNatMapComplete() - -Revision 1.267 2007/01/04 21:45:20 cheshire -Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros, -to do additional lock sanity checking around callback invocations - -Revision 1.266 2007/01/04 21:01:20 cheshire -<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support -Only return NXDOMAIN results to clients that request them using kDNSServiceFlagsReturnIntermediates - -Revision 1.265 2007/01/04 20:47:17 cheshire -Fixed crash in CheckForUnreferencedLLQMapping() - -Revision 1.264 2007/01/04 20:39:27 cheshire -Fix locking mismatch - -Revision 1.263 2007/01/04 02:39:53 cheshire -<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations - -Revision 1.262 2007/01/04 00:29:25 cheshire -Covert LogMsg() in GetAuthInfoForName to LogOperation() - -Revision 1.261 2006/12/22 20:59:49 cheshire -<rdar://problem/4742742> Read *all* DNS keys from keychain, - not just key for the system-wide default registration domain - -Revision 1.260 2006/12/21 00:06:07 cheshire -Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us - -Revision 1.259 2006/12/20 04:07:36 cheshire -Remove uDNS_info substructure from AuthRecord_struct - -Revision 1.258 2006/12/19 22:49:24 cheshire -Remove uDNS_info substructure from ServiceRecordSet_struct - -Revision 1.257 2006/12/19 02:38:20 cheshire -Get rid of unnecessary duplicate query ID field from DNSQuestion_struct - -Revision 1.256 2006/12/19 02:18:48 cheshire -Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct - -Revision 1.255 2006/12/16 01:58:31 cheshire -<rdar://problem/4720673> uDNS: Need to start caching unicast records - -Revision 1.254 2006/12/15 19:23:39 cheshire -Use new DomainNameLengthLimit() function, to be more defensive against malformed -data received from the network. - -Revision 1.253 2006/12/01 07:43:34 herscher -Fix byte ordering problem for one-shot TCP queries. -Iterate more intelligently over duplicates in uDNS_ReceiveMsg to avoid spin loops. - -Revision 1.252 2006/11/30 23:07:57 herscher -<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS - -Revision 1.251 2006/11/28 21:42:11 mkrochma -Work around a crashing bug that was introduced by uDNS and mDNS code unification - -Revision 1.250 2006/11/18 05:01:30 cheshire -Preliminary support for unifying the uDNS and mDNS code, -including caching of uDNS answers - -Revision 1.249 2006/11/10 07:44:04 herscher -<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM - -Revision 1.248 2006/11/08 04:26:53 cheshire -Fix typo in debugging message - -Revision 1.247 2006/10/20 05:35:04 herscher -<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list. - -Revision 1.246 2006/10/11 19:29:41 herscher -<rdar://problem/4744553> uDNS: mDNSResponder-111 using 100% CPU - -Revision 1.245 2006/10/04 22:21:15 herscher -Tidy up references to mDNS_struct introduced when the embedded uDNS_info struct was removed. - -Revision 1.244 2006/10/04 21:51:27 herscher -Replace calls to mDNSPlatformTimeNow(m) with m->timenow - -Revision 1.243 2006/10/04 21:38:59 herscher -Remove uDNS_info substructure from DNSQuestion_struct - -Revision 1.242 2006/09/27 00:51:46 herscher -Fix compile error when _LEGACY_NAT_TRAVERSAL_ is not defined - -Revision 1.241 2006/09/26 01:54:47 herscher -<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol) - -Revision 1.240 2006/09/15 21:20:15 cheshire -Remove uDNS_info substructure from mDNS_struct - -Revision 1.239 2006/08/16 02:52:56 mkrochma -<rdar://problem/4104154> Actually fix it this time - -Revision 1.238 2006/08/16 00:31:50 mkrochma -<rdar://problem/4386944> Get rid of NotAnInteger references - -Revision 1.237 2006/08/15 23:38:17 mkrochma -<rdar://problem/4104154> Requested Public Port field should be set to zero on mapping deletion - -Revision 1.236 2006/08/14 23:24:23 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.235 2006/07/30 05:45:36 cheshire -<rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC - -Revision 1.234 2006/07/22 02:58:36 cheshire -Code was clearing namehash twice instead of namehash and rdatahash - -Revision 1.233 2006/07/20 19:46:51 mkrochma -<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder -Fix Private DNS - -Revision 1.232 2006/07/15 02:01:29 cheshire -<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder -Fix broken "empty string" browsing - -Revision 1.231 2006/07/05 23:28:22 cheshire -<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder - -Revision 1.230 2006/06/29 03:02:44 cheshire -<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support - -Revision 1.229 2006/03/02 22:03:41 cheshire -<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use" -Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end - -Revision 1.228 2006/02/26 00:54:42 cheshire -Fixes to avoid code generation warning/error on FreeBSD 7 - -Revision 1.227 2006/01/09 20:47:05 cheshire -<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use" - -*/ + */ #include "uDNS.h" @@ -1338,103 +38,59 @@ Revision 1.227 2006/01/09 20:47:05 cheshire // default registration) and possibly one or more recommended automatic browsing domains. mDNSexport SearchListElem *SearchList = mDNSNULL; -// Temporary workaround to make ServiceRecordSet list management safe. -// Ideally a ServiceRecordSet shouldn't be a special entity that's given special treatment by the uDNS code -// -- it should just be a grouping of records that are treated the same as any other registered records. -// In that case it may no longer be necessary to keep an explicit list of ServiceRecordSets, which in turn -// would avoid the perils of modifying that list cleanly while some other piece of code is iterating through it. -ServiceRecordSet *CurrentServiceRecordSet = mDNSNULL; +// The value can be set to true by the Platform code e.g., MacOSX uses the plist mechanism +mDNSBool StrictUnicastOrdering = mDNSfalse; + +// We keep track of the number of unicast DNS servers and log a message when we exceed 64. +// Currently the unicast queries maintain a 64 bit map to track the valid DNS servers for that +// question. Bit position is the index into the DNS server list. This is done so to try all +// the servers exactly once before giving up. If we could allocate memory in the core, then +// arbitrary limitation of 64 DNSServers can be removed. +mDNSu8 NumUnicastDNSServers = 0; +#define MAX_UNICAST_DNS_SERVERS 64 // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - General Utility Functions #endif -// Unlink an AuthRecord from the m->ResourceRecords list. -// This seems risky. Probably some (or maybe all) of the places calling UnlinkAuthRecord to directly -// remove a record from the list should actually be using mDNS_Deregister/mDNS_Deregister_internal. -mDNSlocal mStatus UnlinkAuthRecord(mDNS *const m, AuthRecord *const rr) - { - AuthRecord **list = &m->ResourceRecords; - if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next; - if (m->CurrentRecord == rr) m->CurrentRecord = rr->next; - while (*list && *list != rr) list = &(*list)->next; - if (!*list) - { - list = &m->DuplicateRecords; - while (*list && *list != rr) list = &(*list)->next; - } - if (*list) { *list = rr->next; rr->next = mDNSNULL; return(mStatus_NoError); } - LogMsg("ERROR: UnlinkAuthRecord - no such active record %##s", rr->resrec.name->c); - return(mStatus_NoSuchRecord); - } - -// unlinkSRS is an internal routine (i.e. must be called with the lock already held) -mDNSlocal void unlinkSRS(mDNS *const m, ServiceRecordSet *srs) - { - ServiceRecordSet **p; - - if (srs->NATinfo.clientContext) - { - mDNS_StopNATOperation_internal(m, &srs->NATinfo); - srs->NATinfo.clientContext = mDNSNULL; - } - - for (p = &m->ServiceRegistrations; *p; p = &(*p)->uDNS_next) - if (*p == srs) - { - ExtraResourceRecord *e; - *p = srs->uDNS_next; - if (CurrentServiceRecordSet == srs) - CurrentServiceRecordSet = srs->uDNS_next; - srs->uDNS_next = mDNSNULL; - for (e=srs->Extras; e; e=e->next) - if (UnlinkAuthRecord(m, &e->r)) - LogMsg("unlinkSRS: extra record %##s not found", e->r.resrec.name->c); - return; - } - LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs->RR_SRV.resrec.name->c); - } - // set retry timestamp for record with exponential backoff -// (for service record sets, use RR_SRV as representative for time checks -mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr) +mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mDNSu32 random) { - mDNSs32 elapsed = m->timenow - rr->LastAPTime; rr->LastAPTime = m->timenow; -#if 0 - // Code for stress-testing registration renewal code - if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond * 120) - { - LogInfo("Adjusting expiry from %d to 120 seconds for %s", - (rr->expire - m->timenow) / mDNSPlatformOneSecond, ARDisplayString(m, rr)); - rr->expire = m->timenow + mDNSPlatformOneSecond * 120; - } -#endif - - if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond) + if (rr->expire && rr->refreshCount < MAX_UPDATE_REFRESH_COUNT) { mDNSs32 remaining = rr->expire - m->timenow; - rr->ThisAPInterval = remaining/2 + mDNSRandom(remaining/10); - debugf("SetRecordRetry refresh in %4d of %4d for %s", - rr->ThisAPInterval / mDNSPlatformOneSecond, (rr->expire - m->timenow) / mDNSPlatformOneSecond, ARDisplayString(m, rr)); + rr->refreshCount++; + if (remaining > MIN_UPDATE_REFRESH_TIME) + { + // Refresh at 70% + random (currently it is 0 to 10%) + rr->ThisAPInterval = 7 * (remaining/10) + (random ? random : mDNSRandom(remaining/10)); + // Don't update more often than 5 minutes + if (rr->ThisAPInterval < MIN_UPDATE_REFRESH_TIME) + rr->ThisAPInterval = MIN_UPDATE_REFRESH_TIME; + LogInfo("SetRecordRetry refresh in %d of %d for %s", + rr->ThisAPInterval/mDNSPlatformOneSecond, (rr->expire - m->timenow)/mDNSPlatformOneSecond, ARDisplayString(m, rr)); + } + else + { + rr->ThisAPInterval = MIN_UPDATE_REFRESH_TIME; + LogInfo("SetRecordRetry clamping to min refresh in %d of %d for %s", + rr->ThisAPInterval/mDNSPlatformOneSecond, (rr->expire - m->timenow)/mDNSPlatformOneSecond, ARDisplayString(m, rr)); + } return; } rr->expire = 0; - // If at least half our our time interval has elapsed, it's time to double rr->ThisAPInterval - // If resulting interval is too small, set to at least INIT_UCAST_POLL_INTERVAL (3 seconds) - // If resulting interval is too large, set to at most 30 minutes - if (rr->ThisAPInterval / 2 <= elapsed) rr->ThisAPInterval *= 2; - if (rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL || SendErr == mStatus_TransientErr) - rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL; - rr->ThisAPInterval += mDNSRandom(rr->ThisAPInterval/20); - if (rr->ThisAPInterval > 30 * 60 * mDNSPlatformOneSecond) - rr->ThisAPInterval = 30 * 60 * mDNSPlatformOneSecond; - - LogInfo("SetRecordRetry retry in %4d for %s", rr->ThisAPInterval / mDNSPlatformOneSecond, ARDisplayString(m, rr)); + rr->ThisAPInterval = rr->ThisAPInterval * QuestionIntervalStep; // Same Retry logic as Unicast Queries + if (rr->ThisAPInterval < INIT_RECORD_REG_INTERVAL) + rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; + if (rr->ThisAPInterval > MAX_RECORD_REG_INTERVAL) + rr->ThisAPInterval = MAX_RECORD_REG_INTERVAL; + + LogInfo("SetRecordRetry retry in %d ms for %s", rr->ThisAPInterval, ARDisplayString(m, rr)); } // *************************************************************************** @@ -1442,20 +98,26 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr) #pragma mark - Name Server List Management #endif -mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port) +mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped) { DNSServer **p = &m->DNSServers; DNSServer *tmp = mDNSNULL; + if ((NumUnicastDNSServers + 1) > MAX_UNICAST_DNS_SERVERS) + { + LogMsg("mDNS_AddDNSServer: DNS server limit of %d reached, not adding this server", MAX_UNICAST_DNS_SERVERS); + return mDNSNULL; + } + if (!d) d = (const domainname *)""; - LogInfo("mDNS_AddDNSServer: Adding %#a for %##s", addr, d->c); + LogInfo("mDNS_AddDNSServer: Adding %#a for %##s, InterfaceID %p, scoped %d", addr, d->c, interface, scoped); if (m->mDNS_busy != m->mDNS_reentrancy+1) LogMsg("mDNS_AddDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); while (*p) // Check if we already have this {interface,address,port,domain} tuple registered { - if ((*p)->interface == interface && (*p)->teststate != DNSServer_Disabled && + if ((*p)->scoped == scoped && (*p)->interface == interface && (*p)->teststate != DNSServer_Disabled && mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d)) { if (!((*p)->flags & DNSServer_FlagDelete)) debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr, mDNSVal16(port), d->c, interface); @@ -1476,6 +138,8 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons if (!*p) LogMsg("Error: mDNS_AddDNSServer - malloc"); else { + NumUnicastDNSServers++; + (*p)->scoped = scoped; (*p)->interface = interface; (*p)->addr = *addr; (*p)->port = port; @@ -1486,43 +150,126 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons (*p)->next = mDNSNULL; } } + (*p)->penaltyTime = 0; return(*p); } -mDNSexport void PushDNSServerToEnd(mDNS *const m, DNSQuestion *q) +// PenalizeDNSServer is called when the number of queries to the unicast +// DNS server exceeds MAX_UCAST_UNANSWERED_QUERIES or when we receive an +// error e.g., SERV_FAIL from DNS server. +mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q) { + DNSServer *new; DNSServer *orig = q->qDNSServer; - DNSServer **p = &m->DNSServers; if (m->mDNS_busy != m->mDNS_reentrancy+1) - LogMsg("PushDNSServerToEnd: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + LogMsg("PenalizeDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + // This should never happen. Whenever we change DNS server, we change the ID on the question and hence + // we should never accept a response after we penalize a DNS server e.g., send two queries, no response, + // penalize DNS server and no new servers to pick for the question and hence qDNSServer is NULL. If we + // receive a response now, the DNS server can be NULL. But we won't because the ID already has been + // changed. if (!q->qDNSServer) { - LogMsg("PushDNSServerToEnd: Null DNS server for %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), q->unansweredQueries); + LogMsg("PenalizeDNSServer: ERROR!! Null DNS server for %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), q->unansweredQueries); goto end; } - LogInfo("PushDNSServerToEnd: Pushing DNS server %#a:%d (%##s) due to %d unanswered queries for %##s (%s)", - &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype)); + LogInfo("PenalizeDNSServer: Penalizing DNS server %#a:%d question (%##s) for question %p %##s (%s) SuppressUnusable %d", + &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q, q->qname.c, DNSTypeName(q->qtype), + q->SuppressUnusable); - while (*p) + // If strict ordering of unicast servers needs to be preserved, we just lookup + // the next best match server below + // + // If strict ordering is not required which is the default behavior, we penalize the server + // for DNSSERVER_PENALTY_TIME. We may also use additional logic e.g., don't penalize for PTR + // in the future. + + if (!StrictUnicastOrdering) + { + LogInfo("PenalizeDNSServer: Strict Unicast Ordering is FALSE"); + // We penalize the server so that new queries don't pick this server for DNSSERVER_PENALTY_TIME + // XXX Include other logic here to see if this server should really be penalized + // + if (q->qtype == kDNSType_PTR) + { + LogInfo("PenalizeDNSServer: Not Penalizing PTR question"); + } + else + { + LogInfo("PenalizeDNSServer: Penalizing question type %d", q->qtype); + q->qDNSServer->penaltyTime = NonZeroTime(m->timenow + DNSSERVER_PENALTY_TIME); + } + } + else { - if (*p == q->qDNSServer) *p = q->qDNSServer->next; - else p=&(*p)->next; + LogInfo("PenalizeDNSServer: Strict Unicast Ordering is TRUE"); } - *p = q->qDNSServer; - q->qDNSServer->next = mDNSNULL; - end: - q->qDNSServer = GetServerForName(m, &q->qname); + new = GetServerForQuestion(m, q); - if (q->qDNSServer != orig) + + if (new == orig) + { + if (new) + LogMsg("PenalizeDNSServer: ERROR!! GetServerForQuestion returned the same server %#a:%d", &new->addr, + mDNSVal16(new->port)); + else + LogMsg("PenalizeDNSServer: ERROR!! GetServerForQuestion returned the same server NULL"); + q->ThisQInterval = 0; // Inactivate this question so that we dont bombard the network + } + else { - if (q->qDNSServer) LogInfo("PushDNSServerToEnd: Server for %##s (%s) changed to %#a:%d (%##s)", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c); - else LogInfo("PushDNSServerToEnd: Server for %##s (%s) changed to <null>", q->qname.c, DNSTypeName(q->qtype)); - q->ThisQInterval = q->ThisQInterval / QuestionIntervalStep; // Decrease interval one step so we don't quickly bounce between servers for queries that will not be answered. + // The new DNSServer is set in DNSServerChangeForQuestion + DNSServerChangeForQuestion(m, q, new); + + if (new) + { + LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to %#a:%d (%##s)", + q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c); + // We want to try the next server immediately. As the question may already have backed off, reset + // the interval. We do this only the first time when we try all the DNS servers. Once we reached the end of + // list and retrying all the servers again e.g., at least one server failed to respond in the previous try, we + // use the normal backoff which is done in uDNS_CheckCurrentQuestion when we send the packet out. + if (!q->triedAllServersOnce) + { + q->ThisQInterval = InitialQuestionInterval; + q->LastQTime = m->timenow - q->ThisQInterval; + SetNextQueryTime(m, q); + } + } + else + { + // We don't have any more DNS servers for this question. If some server in the list did not return + // any response, we need to keep retrying till we get a response. uDNS_CheckCurrentQuestion handles + // this case. + // + // If all servers responded with a negative response, We need to do two things. First, generate a + // negative response so that applications get a reply. We also need to reinitialize the DNS servers + // so that when the cache expires, we can restart the query. + // + // Negative response may be generated in two ways. + // + // 1. AnswerQuestionForDNSServerChanges (called from DNSServerChangedForQuestion) might find some + // cache entries and answer this question. + // 2. uDNS_CheckCurrentQuestion will create a new cache entry and answer this question + // + // For (1), it might be okay to reinitialize the DNS servers here. But for (2), we can't do it here + // because uDNS_CheckCurrentQuestion will try resending the queries. Hence, to be consistent, we + // defer reintializing the DNS servers up until generating a negative cache response. + // + // Be careful not to touch the ThisQInterval here. For a normal question, when we answer the question + // in AnswerCurrentQuestionWithResourceRecord will set ThisQInterval to MaxQuestionInterval and hence + // the next query will not happen until cache expiry. If it is a long lived question, + // AnswerCurrentQuestionWithResourceRecord will not set it to MaxQuestionInterval. In that case, + // we want the normal backoff to work. + LogInfo("PenalizeDNSServer: Server for %p, %##s (%s) changed to NULL, Interval %d", q, q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval); + } + q->unansweredQueries = 0; + } } @@ -1621,7 +368,7 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, info->deltime = 0; while (*p && (*p) != info) p=&(*p)->next; - if (*p) return(mStatus_AlreadyRegistered); + if (*p) {LogInfo("mDNS_SetSecretForDomain: Domain %##s Already in list", (*p)->domain.c); return(mStatus_AlreadyRegistered);} // Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo // being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use. @@ -1630,6 +377,7 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, info->AutoTunnelTarget .resrec.RecordType = kDNSRecordTypeUnregistered; info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered; info->AutoTunnelService .resrec.RecordType = kDNSRecordTypeUnregistered; + info->AutoTunnel6Record .resrec.RecordType = kDNSRecordTypeUnregistered; info->AutoTunnelNAT.clientContext = mDNSNULL; info->next = mDNSNULL; *p = info; @@ -1795,7 +543,7 @@ mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalIn { NATTraversalInfo **n; - LogInfo("mDNS_StartNATOperation_internal Protocol %d IntPort %d RequestedPort %d NATLease %d", + LogInfo("mDNS_StartNATOperation_internal %p Protocol %d IntPort %d RequestedPort %d NATLease %d", traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease); // Note: It important that new traversal requests are appended at the *end* of the list, not prepended at the start @@ -1857,11 +605,11 @@ mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *tra if (*ptr) *ptr = (*ptr)->next; // If we found it, cut this NATTraversalInfo struct from our list else { - LogMsg("mDNS_StopNATOperation: NATTraversalInfo %p not found in list", traversal); + LogMsg("mDNS_StopNATOperation_internal: NATTraversalInfo %p not found in list", traversal); return(mStatus_BadReferenceErr); } - LogInfo("mDNS_StopNATOperation_internal %d %d %d %d", + LogInfo("mDNS_StopNATOperation_internal %p %d %d %d %d", traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease); if (m->CurrentNATTraversal == traversal) @@ -1897,7 +645,7 @@ mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *tra return(mStatus_NoError); } -mDNSexport mStatus mDNS_StartNATOperation(mDNS *m, NATTraversalInfo *traversal) +mDNSexport mStatus mDNS_StartNATOperation(mDNS *const m, NATTraversalInfo *traversal) { mStatus status; mDNS_Lock(m); @@ -1906,7 +654,7 @@ mDNSexport mStatus mDNS_StartNATOperation(mDNS *m, NATTraversalInfo *traversal) return(status); } -mDNSexport mStatus mDNS_StopNATOperation(mDNS *m, NATTraversalInfo *traversal) +mDNSexport mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traversal) { mStatus status; mDNS_Lock(m); @@ -1987,6 +735,10 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const mDNSu8 *responsePtr = m->omsg.data; LLQOptData llqBuf; + if (q->tcp) { LogMsg("sendChallengeResponse: ERROR!!: question %##s (%s) tcp non-NULL", q->qname.c, DNSTypeName(q->qtype)); return; } + + if (PrivateQuery(q)) { LogMsg("sendChallengeResponse: ERROR!!: Private Query %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; } + if (q->ntries++ == kLLQ_MAX_TRIES) { LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s", kLLQ_MAX_TRIES, q->qname.c); @@ -2015,12 +767,8 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const responsePtr = putLLQ(&m->omsg, responsePtr, q, llq); if (responsePtr) { - mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo); - if (err) - { - LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err); - if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; } - } + mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL); + if (err) { LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err); } } else StartLLQPolling(m,q); } @@ -2074,7 +822,7 @@ mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const // an issue for private LLQs, because we skip parts 2 and 3 of the handshake. This is related to a bigger // problem of the current implementation of TCP LLQ setup: we're not handling state transitions correctly // if the server sends back SERVFULL or STATIC. - if (q->AuthInfo) + if (PrivateQuery(q)) { LogInfo("Private LLQ_SecondaryRequest; copying id %08X%08X", llq->id.l[0], llq->id.l[1]); q->id = llq->id; @@ -2092,7 +840,8 @@ mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const } } -mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport) +mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, + const mDNSAddr *const srcaddr, const mDNSIPPort srcport, DNSQuestion **matchQuestion) { DNSQuestion pktQ, *q; if (msg->h.numQuestions && getQuestion(msg, msg->data, end, 0, &pktQ)) @@ -2110,12 +859,30 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co if (q->state == LLQ_Poll && mDNSSameOpaque16(msg->h.id, q->TargetQID)) { m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it - debugf("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); - q->state = LLQ_InitialRequest; + + // Don't reset the state to IntialRequest as we may write that to the dynamic store + // and PrefPane might wrongly think that we are "Starting" instead of "Polling". If + // we are in polling state because of NAT-PMP disabled or DoubleNAT, next LLQNATCallback + // would kick us back to LLQInitialRequest. So, resetting the state here may not be useful. + // + // If we have a good NAT (neither NAT-PMP disabled nor Double-NAT), then we should not be + // possibly in polling state. To be safe, we want to retry from the start in that case + // as there may not be another LLQNATCallback + // + // NOTE: We can be in polling state if we cannot resolve the SOA record i.e, servAddr is set to + // all ones. In that case, we would set it in LLQ_InitialRequest as it overrides the NAT-PMP or + // Double-NAT state. + if (!mDNSAddressIsOnes(&q->servAddr) && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort) && + !m->LLQNAT.Result) + { + debugf("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + q->state = LLQ_InitialRequest; + } q->servPort = zeroIPPort; // Clear servPort so that startLLQHandshake will retry the GetZoneData processing q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry LLQ setup in approx 15 minutes q->LastQTime = m->timenow; SetNextQueryTime(m, q); + *matchQuestion = q; return uDNS_LLQ_Entire; // uDNS_LLQ_Entire means flush stale records; assume a large effective TTL } // Note: In LLQ Event packets, the msg->h.id does not match our q->TargetQID, because in that case the msg->h.id nonce is selected by the server @@ -2128,6 +895,7 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, q->LocalSocket, srcaddr, srcport, mDNSNULL, mDNSNULL); m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it debugf("uDNS_LLQ_Events: q->state == LLQ_Established msg->h.id %d q->TargetQID %d", mDNSVal16(msg->h.id), mDNSVal16(q->TargetQID)); + *matchQuestion = q; return uDNS_LLQ_Events; } if (opt && mDNSSameOpaque16(msg->h.id, q->TargetQID)) @@ -2146,6 +914,7 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co q->ntries = 0; } m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + *matchQuestion = q; return uDNS_LLQ_Ignore; } if (q->state < LLQ_Established && mDNSSameAddress(srcaddr, &q->servAddr)) @@ -2160,6 +929,7 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co // are still valid, so this packet should not cause us to do anything that messes with our cache. // The ack+answers packet gives us the whole truth, so we should handle it by updating our cache // to match the answers in the packet, and only the answers in the packet. + *matchQuestion = q; return (oldstate == LLQ_SecondaryRequest ? uDNS_LLQ_Entire : uDNS_LLQ_Ignore); } } @@ -2167,6 +937,7 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co } m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it } + *matchQuestion = mDNSNULL; return uDNS_LLQ_Not; } @@ -2183,11 +954,10 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs DNSQuestion *const q = tcpInfo->question; tcpInfo_t **backpointer = q ? &q ->tcp : - tcpInfo->srs ? &tcpInfo->srs->tcp : tcpInfo->rr ? &tcpInfo->rr ->tcp : mDNSNULL; if (backpointer && *backpointer != tcpInfo) - LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p srs %p rr %p", - mDNSPlatformTCPGetFD(tcpInfo->sock), *backpointer, tcpInfo, q, tcpInfo->srs, tcpInfo->rr); + LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p rr %p", + mDNSPlatformTCPGetFD(tcpInfo->sock), *backpointer, tcpInfo, q, tcpInfo->rr); if (err) goto exit; @@ -2198,21 +968,17 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs // Defensive coding for <rdar://problem/5546824> Crash in mDNSResponder at GetAuthInfoForName_internal + 366 // Don't know yet what's causing this, but at least we can be cautious and try to avoid crashing if we find our pointers in an unexpected state - if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage) - LogMsg("tcpCallback: ERROR: tcpInfo->srs->RR_SRV.resrec.name %p != &tcpInfo->srs->RR_SRV.namestorage %p", - tcpInfo->srs->RR_SRV.resrec.name, &tcpInfo->srs->RR_SRV.namestorage); if (tcpInfo->rr && tcpInfo->rr->resrec.name != &tcpInfo->rr->namestorage) LogMsg("tcpCallback: ERROR: tcpInfo->rr->resrec.name %p != &tcpInfo->rr->namestorage %p", tcpInfo->rr->resrec.name, &tcpInfo->rr->namestorage); - if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage) return; if (tcpInfo->rr && tcpInfo->rr-> resrec.name != &tcpInfo->rr-> namestorage) return; - AuthInfo = tcpInfo->srs ? GetAuthInfoForName(m, tcpInfo->srs->RR_SRV.resrec.name) : - tcpInfo->rr ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name) : mDNSNULL; + AuthInfo = tcpInfo->rr ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name) : mDNSNULL; // connection is established - send the message if (q && q->LongLived && q->state == LLQ_Established) { + // Lease renewal over TCP, resulting from opening a TCP connection in sendLLQRefresh end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen; } else if (q && q->LongLived && q->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort) && !mDNSIPPortIsZero(q->servPort)) @@ -2232,9 +998,11 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs end = putLLQ(&tcpInfo->request, tcpInfo->request.data, q, &llqData); if (!end) { LogMsg("ERROR: tcpCallback - putLLQ"); err = mStatus_UnknownErr; goto exit; } AuthInfo = q->AuthInfo; // Need to add TSIG to this message + q->ntries = 0; // Reset ntries so that tcp/tls connection failures don't affect sendChallengeResponse failures } else if (q) { + // LLQ Polling mode or non-LLQ uDNS over TCP InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, uQueryFlags); end = putQuestion(&tcpInfo->request, tcpInfo->request.data, tcpInfo->request.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass); AuthInfo = q->AuthInfo; // Need to add TSIG to this message @@ -2261,16 +1029,33 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs { mDNSu8 *lenptr = (mDNSu8 *)&tcpInfo->replylen; n = mDNSPlatformReadTCP(sock, lenptr + tcpInfo->nread, 2 - tcpInfo->nread, &closed); - if (n < 0) { LogMsg("ERROR: tcpCallback - attempt to read message length failed (%d)", n); err = mStatus_ConnFailed; goto exit; } + if (n < 0) + { + LogMsg("ERROR: tcpCallback - attempt to read message length failed (%d)", n); + err = mStatus_ConnFailed; + goto exit; + } else if (closed) { // It's perfectly fine for this socket to close after the first reply. The server might // be sending gratuitous replies using UDP and doesn't have a need to leave the TCP socket open. // We'll only log this event if we've never received a reply before. // BIND 9 appears to close an idle connection after 30 seconds. - if (tcpInfo->numReplies == 0) LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo->nread); - err = mStatus_ConnFailed; - goto exit; + if (tcpInfo->numReplies == 0) + { + LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo->nread); + err = mStatus_ConnFailed; + goto exit; + } + else + { + // Note that we may not be doing the best thing if an error occurs after we've sent a second request + // over this tcp connection. That is, we only track whether we've received at least one response + // which may have been to a previous request sent over this tcp connection. + if (backpointer) *backpointer = mDNSNULL; // Clear client backpointer FIRST so we don't risk double-disposing our tcpInfo_t + DisposeTCPConn(tcpInfo); + return; + } } tcpInfo->nread += n; @@ -2286,39 +1071,63 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs n = mDNSPlatformReadTCP(sock, ((char *)tcpInfo->reply) + (tcpInfo->nread - 2), tcpInfo->replylen - (tcpInfo->nread - 2), &closed); - if (n < 0) { LogMsg("ERROR: tcpCallback - read returned %d", n); err = mStatus_ConnFailed; goto exit; } - else if (closed) { LogMsg("ERROR: socket closed prematurely %d", tcpInfo->nread); err = mStatus_ConnFailed; goto exit; } + if (n < 0) + { + LogMsg("ERROR: tcpCallback - read returned %d", n); + err = mStatus_ConnFailed; + goto exit; + } + else if (closed) + { + if (tcpInfo->numReplies == 0) + { + LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo->nread); + err = mStatus_ConnFailed; + goto exit; + } + else + { + // Note that we may not be doing the best thing if an error occurs after we've sent a second request + // over this tcp connection. That is, we only track whether we've received at least one response + // which may have been to a previous request sent over this tcp connection. + if (backpointer) *backpointer = mDNSNULL; // Clear client backpointer FIRST so we don't risk double-disposing our tcpInfo_t + DisposeTCPConn(tcpInfo); + return; + } + } tcpInfo->nread += n; if ((tcpInfo->nread - 2) == tcpInfo->replylen) { - AuthRecord *rr = tcpInfo->rr; + mDNSBool tls; DNSMessage *reply = tcpInfo->reply; mDNSu8 *end = (mDNSu8 *)tcpInfo->reply + tcpInfo->replylen; mDNSAddr Addr = tcpInfo->Addr; mDNSIPPort Port = tcpInfo->Port; + mDNSIPPort srcPort = zeroIPPort; tcpInfo->numReplies++; tcpInfo->reply = mDNSNULL; // Detach reply buffer from tcpInfo_t, to make sure client callback can't cause it to be disposed tcpInfo->nread = 0; tcpInfo->replylen = 0; // If we're going to dispose this connection, do it FIRST, before calling client callback - // Note: Sleep code depends on us clearing *backpointer here -- it uses the clearing of rr->tcp and srs->tcp + // Note: Sleep code depends on us clearing *backpointer here -- it uses the clearing of rr->tcp // as the signal that the DNS deregistration operation with the server has completed, and the machine may now sleep + // If we clear the tcp pointer in the question, mDNSCoreReceiveResponse cannot find a matching question. Hence + // we store the minimal information i.e., the source port of the connection in the question itself. + // Dereference sock before it is disposed in DisposeTCPConn below. + + if (sock->flags & kTCPSocketFlags_UseTLS) tls = mDNStrue; + else tls = mDNSfalse; + + if (q && q->tcp) {srcPort = q->tcp->SrcPort; q->tcpSrcPort = srcPort;} + if (backpointer) if (!q || !q->LongLived || m->SleepState) { *backpointer = mDNSNULL; DisposeTCPConn(tcpInfo); } - if (rr && rr->resrec.RecordType == kDNSRecordTypeDeregistering) - { - mDNS_Lock(m); - LogInfo("tcpCallback: CompleteDeregistration %s", ARDisplayString(m, rr)); - CompleteDeregistration(m, rr); // Don't touch rr after this - mDNS_Unlock(m); - } - else - mDNSCoreReceive(m, reply, end, &Addr, Port, (sock->flags & kTCPSocketFlags_UseTLS) ? (mDNSAddr *)1 : mDNSNULL, zeroIPPort, 0); + mDNSCoreReceive(m, reply, end, &Addr, Port, tls ? (mDNSAddr *)1 : mDNSNULL, srcPort, 0); // USE CAUTION HERE: Invoking mDNSCoreReceive may have caused the environment to change, including canceling this operation itself mDNSPlatformMemFree(reply); @@ -2338,24 +1147,64 @@ exit: if (q) { - if (q->ThisQInterval == 0 || q->LastQTime + q->ThisQInterval - m->timenow > MAX_UCAST_POLL_INTERVAL) + if (q->ThisQInterval == 0) { + // We get here when we fail to establish a new TCP/TLS connection that would have been used for a new LLQ request or an LLQ renewal. + // Note that ThisQInterval is also zero when sendChallengeResponse resends the LLQ request on an extant TCP/TLS connection. + q->LastQTime = m->timenow; + if (q->LongLived) + { + // We didn't get the chance to send our request packet before the TCP/TLS connection failed. + // We want to retry quickly, but want to back off exponentially in case the server is having issues. + // Since ThisQInterval was 0, we can't just multiply by QuestionIntervalStep, we must track the number + // of TCP/TLS connection failures using ntries. + mDNSu32 count = q->ntries + 1; // want to wait at least 1 second before retrying + + q->ThisQInterval = InitialQuestionInterval; + + for (;count;count--) + q->ThisQInterval *= QuestionIntervalStep; + + if (q->ThisQInterval > LLQ_POLL_INTERVAL) + q->ThisQInterval = LLQ_POLL_INTERVAL; + else + q->ntries++; + + LogMsg("tcpCallback: stream connection for LLQ %##s (%s) failed %d times, retrying in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ntries, q->ThisQInterval); + } + else + { + q->ThisQInterval = MAX_UCAST_POLL_INTERVAL; + LogMsg("tcpCallback: stream connection for %##s (%s) failed, retrying in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval); + } + SetNextQueryTime(m, q); + } + else if (NextQSendTime(q) - m->timenow > (q->LongLived ? LLQ_POLL_INTERVAL : MAX_UCAST_POLL_INTERVAL)) + { + // If we get an error and our next scheduled query for this question is more than the max interval from now, + // reset the next query to ensure we wait no longer the maximum interval from now before trying again. q->LastQTime = m->timenow; - q->ThisQInterval = MAX_UCAST_POLL_INTERVAL; + q->ThisQInterval = q->LongLived ? LLQ_POLL_INTERVAL : MAX_UCAST_POLL_INTERVAL; SetNextQueryTime(m, q); + LogMsg("tcpCallback: stream connection for %##s (%s) failed, retrying in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval); } - // ConnFailed may be actually okay. It just means that the server closed the connection but the LLQ may still be okay. - // If the error isn't ConnFailed, then the LLQ is in bad shape. + + // We're about to dispose of the TCP connection, so we must reset the state to retry over TCP/TLS + // because sendChallengeResponse will send the query via UDP if we don't have a tcp pointer. + // Resetting to LLQ_InitialRequest will cause uDNS_CheckCurrentQuestion to call startLLQHandshake, which + // will attempt to establish a new tcp connection. + if (q->LongLived && q->state == LLQ_SecondaryRequest) + q->state = LLQ_InitialRequest; + + // ConnFailed may happen if the server sends a TCP reset or TLS fails, in which case we want to retry establishing the LLQ + // quickly rather than switching to polling mode. This case is handled by the above code to set q->ThisQInterval just above. + // If the error isn't ConnFailed, then the LLQ is in bad shape, so we switch to polling mode. if (err != mStatus_ConnFailed) { if (q->LongLived && q->state != LLQ_Poll) StartLLQPolling(m, q); } } - if (tcpInfo->rr) SetRecordRetry(m, tcpInfo->rr, mStatus_NoError); - - if (tcpInfo->srs) SetRecordRetry(m, &tcpInfo->srs->RR_SRV, mStatus_NoError); - mDNS_Unlock(m); DisposeTCPConn(tcpInfo); @@ -2363,12 +1212,17 @@ exit: } mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, - TCPSocketFlags flags, const mDNSAddr *const Addr, const mDNSIPPort Port, - DNSQuestion *const question, ServiceRecordSet *const srs, AuthRecord *const rr) + TCPSocketFlags flags, const mDNSAddr *const Addr, const mDNSIPPort Port, domainname *hostname, + DNSQuestion *const question, AuthRecord *const rr) { mStatus err; mDNSIPPort srcport = zeroIPPort; - tcpInfo_t *info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t)); + tcpInfo_t *info; + + if ((flags & kTCPSocketFlags_UseTLS) && (!hostname || !hostname->c[0])) + { LogMsg("MakeTCPConn: TLS connection being setup with NULL hostname"); return mDNSNULL; } + + info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t)); if (!info) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL); } mDNSPlatformMemZero(info, sizeof(tcpInfo_t)); @@ -2376,7 +1230,6 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con info->sock = mDNSPlatformTCPSocket(m, flags, &srcport); info->requestLen = 0; info->question = question; - info->srs = srs; info->rr = rr; info->Addr = *Addr; info->Port = Port; @@ -2384,6 +1237,7 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con info->replylen = 0; info->nread = 0; info->numReplies = 0; + info->SrcPort = srcport; if (msg) { @@ -2391,8 +1245,8 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con mDNSPlatformMemCopy(&info->request, msg, info->requestLen); } - if (!info->sock) { LogMsg("SendServiceRegistration: unable to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); } - err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpCallback, info); + if (!info->sock) { LogMsg("MakeTCPConn: unable to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); } + err = mDNSPlatformTCPConnect(info->sock, Addr, Port, hostname, (question ? question->InterfaceID : mDNSNULL), tcpCallback, info); // Probably suboptimal here. // Instead of returning mDNSNULL here on failure, we should probably invoke the callback with an error code. @@ -2402,7 +1256,7 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con // Don't need to log "connection failed" in customer builds -- it happens quite often during sleep, wake, configuration changes, etc. if (err == mStatus_ConnEstablished) { tcpCallback(info->sock, info, mDNStrue, mStatus_NoError); } - else if (err != mStatus_ConnPending ) { LogInfo("MakeTCPConnection: connection failed"); DisposeTCPConn(info); return(mDNSNULL); } + else if (err != mStatus_ConnPending ) { LogInfo("MakeTCPConn: connection failed"); DisposeTCPConn(info); return(mDNSNULL); } return(info); } @@ -2425,9 +1279,12 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q) return; } - if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort)) + // Either we don't have NAT-PMP support (ExternalPort is zero) or behind a Double NAT that may or + // may not have NAT-PMP support (NATResult is non-zero) + if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort) || m->LLQNAT.Result) { - LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s) External Port %d, NAT Result %d", + q->qname.c, DNSTypeName(q->qtype), mDNSVal16(m->LLQNAT.ExternalPort), m->LLQNAT.Result); StartLLQPolling(m, q); return; } @@ -2445,11 +1302,29 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q) return; } - if (q->AuthInfo) + if (PrivateQuery(q)) { if (q->tcp) LogInfo("startLLQHandshake: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); - if (q->tcp) DisposeTCPConn(q->tcp); - q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL); + if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; } + if (!q->nta) + { + // Normally we lookup the zone data and then call this function. And we never free the zone data + // for "PrivateQuery". But sometimes this can happen due to some race conditions. When we + // switch networks, we might end up "Polling" the network e.g., we are behind a Double NAT. + // When we poll, we free the zone information as we send the query to the server (See + // PrivateQueryGotZoneData). The NAT callback (LLQNATCallback) may happen soon after that. If we + // are still behind Double NAT, we would have returned early in this function. But we could + // have switched to a network with no NATs and we should get the zone data again. + LogInfo("startLLQHandshake: nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, LLQGotZoneData, q); + return; + } + else if (!q->nta->Host.c[0]) + { + // This should not happen. If it happens, we print a log and MakeTCPConn will fail if it can't find a hostname + LogMsg("startLLQHandshake: ERROR!!: nta non NULL for %##s (%s) but HostName %d NULL, LongLived %d", q->qname.c, DNSTypeName(q->qtype), q->nta->Host.c[0], q->LongLived); + } + q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, &q->nta->Host, q, mDNSNULL); if (!q->tcp) q->ThisQInterval = mDNSPlatformOneSecond * 5; // If TCP failed (transient networking glitch) try again in five seconds else @@ -2519,8 +1394,12 @@ mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr) // If this AutoTunnel is not yet active, start it now (which entails activating its NAT Traversal request, // which will subsequently advertise the appropriate records when the NAT Traversal returns a result) if (!AuthInfo->AutoTunnelNAT.clientContext && m->AutoTunnelHostAddr.b[0]) - SetupLocalAutoTunnelInterface_internal(m); + { + LogInfo("GetServiceTarget: Calling SetupLocalAutoTunnelInterface_internal"); + SetupLocalAutoTunnelInterface_internal(m, mDNStrue); + } if (AuthInfo->AutoTunnelHostRecord.namestorage.c[0] == 0) return(mDNSNULL); + debugf("GetServiceTarget: Returning %##s", AuthInfo->AutoTunnelHostRecord.namestorage.c); return(&AuthInfo->AutoTunnelHostRecord.namestorage); } else @@ -2543,144 +1422,11 @@ mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr) } if (m->StaticHostname.c[0]) return(&m->StaticHostname); else GetStaticHostname(m); // asynchronously do reverse lookup for primary IPv4 address + LogInfo("GetServiceTarget: Returning NULL for %s", ARDisplayString(m, rr)); return(mDNSNULL); } } -// Called with lock held -mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs) - { - mDNSu8 *ptr = m->omsg.data; - mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage); - mDNSOpaque16 id; - mStatus err = mStatus_NoError; - const domainname *target; - mDNSu32 i; - - if (m->mDNS_busy != m->mDNS_reentrancy+1) - LogMsg("SendServiceRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); - - if (mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4)) // Don't know our UpdateServer yet - { - srs->RR_SRV.LastAPTime = m->timenow; - if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 5) - srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; - return; - } - - if (srs->state == regState_Registered) srs->state = regState_Refresh; - - id = mDNS_NewMessageID(m); - InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags); - - // setup resource records - SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash - SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash - - // replace port w/ NAT mapping if necessary - if (srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(srs->NATinfo.ExternalPort)) - srs->RR_SRV.resrec.rdata->u.srv.port = srs->NATinfo.ExternalPort; - - // construct update packet - // set zone - ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass)); - if (!ptr) { err = mStatus_UnknownErr; goto exit; } - - if (srs->TestForSelfConflict) - { - // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records - if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) { err = mStatus_UnknownErr; goto exit; } - if (!(ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype))) { err = mStatus_UnknownErr; goto exit; } - } - - else if (srs->state != regState_Refresh && srs->state != regState_UpdatePending) - { - // use SRV name for prereq - //ptr = putPrereqNameNotInUse(srs->RR_SRV.resrec.name, &m->omsg, ptr, end); - - // For now, until we implement RFC 4701 (DHCID RR) to detect whether an existing record is someone else using the name, or just a - // stale echo of our own previous registration before we changed our host name, we just overwrite whatever may have already been there - ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_SRV.resrec.name, kDNSQType_ANY); - if (!ptr) { err = mStatus_UnknownErr; goto exit; } - } - - //!!!KRS Need to do bounds checking and use TCP if it won't fit!!! - if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; } - - for (i = 0; i < srs->NumSubTypes; i++) - if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; } - - if (srs->state == regState_UpdatePending) // we're updating the txt record - { - AuthRecord *txt = &srs->RR_TXT; - // delete old RData - SetNewRData(&txt->resrec, txt->OrigRData, txt->OrigRDLen); - if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_TXT.resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata - - // add new RData - SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen); - if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; } - } - else - if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; } - - target = GetServiceTarget(m, &srs->RR_SRV); - if (!target || target->c[0] == 0) - { - debugf("SendServiceRegistration - no target for %##s", srs->RR_SRV.resrec.name->c); - srs->state = regState_NoTarget; - return; - } - - if (!SameDomainName(target, &srs->RR_SRV.resrec.rdata->u.srv.target)) - { - AssignDomainName(&srs->RR_SRV.resrec.rdata->u.srv.target, target); - SetNewRData(&srs->RR_SRV.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash - } - - ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_SRV.resrec, srs->RR_SRV.resrec.rroriginalttl); - if (!ptr) { err = mStatus_UnknownErr; goto exit; } - - if (srs->srs_uselease) - { ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; } } - - if (srs->state != regState_Refresh && srs->state != regState_DeregDeferred && srs->state != regState_UpdatePending) - srs->state = regState_Pending; - - srs->id = id; - - if (srs->Private) - { - if (srs->tcp) LogInfo("SendServiceRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV)); - if (srs->tcp) DisposeTCPConn(srs->tcp); - srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL); - if (!srs->tcp) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2) - else if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 30) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 30; - } - else - { - err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name)); - if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %d", err); - } - - SetRecordRetry(m, &srs->RR_SRV, err); - return; - -exit: - if (err) - { - LogMsg("SendServiceRegistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c); - unlinkSRS(m, srs); - srs->state = regState_Unregistered; - - mDNS_DropLockBeforeCallback(); - srs->ServiceCallback(m, srs, err); - mDNS_ReclaimLockAfterCallback(); - // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function - // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. - } - } - mDNSlocal const domainname *PUBLIC_UPDATE_SERVICE_TYPE = (const domainname*)"\x0B_dns-update" "\x04_udp"; mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE = (const domainname*)"\x08_dns-llq" "\x04_udp"; @@ -2712,6 +1458,8 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question { debugf("GetZoneData GOT SOA %s", RRDisplayString(m, answer)); mDNS_StopQuery(m, question); + if (question->ThisQInterval != -1) + LogMsg("GetZoneData_QuestionCallback: Question %##s (%s) ThisQInterval %d not -1", question->qname.c, DNSTypeName(question->qtype), question->ThisQInterval); if (answer->rdlength) { AssignDomainName(&zd->ZoneName, answer->name); @@ -2721,21 +1469,33 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question } else if (zd->CurrentSOA->c[0]) { - zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1); - AssignDomainName(&zd->question.qname, zd->CurrentSOA); - GetZoneData_StartQuery(m, zd, kDNSType_SOA); + DomainAuthInfo *AuthInfo = GetAuthInfoForName(m, zd->CurrentSOA); + if (AuthInfo && AuthInfo->AutoTunnel) + { + // To keep the load on the server down, we don't chop down on + // SOA lookups for AutoTunnels + LogInfo("GetZoneData_QuestionCallback: not chopping labels for %##s", zd->CurrentSOA->c); + zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd); + } + else + { + zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1); + AssignDomainName(&zd->question.qname, zd->CurrentSOA); + GetZoneData_StartQuery(m, zd, kDNSType_SOA); + } } else { LogInfo("GetZoneData recursed to root label of %##s without finding SOA", zd->ChildName.c); zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd); - mDNSPlatformMemFree(zd); } } else if (answer->rrtype == kDNSType_SRV) { debugf("GetZoneData GOT SRV %s", RRDisplayString(m, answer)); mDNS_StopQuery(m, question); + if (question->ThisQInterval != -1) + LogMsg("GetZoneData_QuestionCallback: Question %##s (%s) ThisQInterval %d not -1", question->qname.c, DNSTypeName(question->qtype), question->ThisQInterval); // Right now we don't want to fail back to non-encrypted operations // If the AuthInfo has the AutoTunnel field set, then we want private or nothing // <rdar://problem/5687667> BTMM: Don't fallback to unencrypted operations when SRV lookup fails @@ -2762,7 +1522,6 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question zd->Port = zeroIPPort; zd->Addr = zeroAddr; zd->ZoneDataCallback(m, mStatus_NoError, zd); - mDNSPlatformMemFree(zd); } } } @@ -2770,6 +1529,8 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question { debugf("GetZoneData GOT A %s", RRDisplayString(m, answer)); mDNS_StopQuery(m, question); + if (question->ThisQInterval != -1) + LogMsg("GetZoneData_QuestionCallback: Question %##s (%s) ThisQInterval %d not -1", question->qname.c, DNSTypeName(question->qtype), question->ThisQInterval); zd->Addr.type = mDNSAddrType_IPv4; zd->Addr.ip.v4 = (answer->rdlength == 4) ? answer->rdata->u.ipv4 : zerov4Addr; // In order to simulate firewalls blocking our outgoing TCP connections, returning immediate ICMP errors or TCP resets, @@ -2782,8 +1543,8 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question zd->Addr.ip.v4.b[2] = 0; zd->Addr.ip.v4.b[3] = 1; #endif + // The caller needs to free the memory when done with zone data zd->ZoneDataCallback(m, mStatus_NoError, zd); - mDNSPlatformMemFree(zd); } } @@ -2797,7 +1558,10 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt debugf("lookupDNSPort %##s", zd->question.qname.c); } - zd->question.ThisQInterval = -1; // So that GetZoneData_QuestionCallback() knows whether to cancel this question (Is this necessary?) + // CancelGetZoneData can get called at any time. We should stop the question if it has not been + // stopped already. A value of -1 for ThisQInterval indicates that the question is not active + // yet. + zd->question.ThisQInterval = -1; zd->question.InterfaceID = mDNSInterface_Any; zd->question.Target = zeroAddr; //zd->question.qname.c[0] = 0; // Already set @@ -2807,6 +1571,7 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt zd->question.ExpectUnique = mDNStrue; zd->question.ForceMCast = mDNSfalse; zd->question.ReturnIntermed = mDNStrue; + zd->question.SuppressUnusable = mDNSfalse; zd->question.QuestionCallback = GetZoneData_QuestionCallback; zd->question.QuestionContext = zd; @@ -2861,216 +1626,288 @@ mDNSexport DomainAuthInfo *GetAuthInfoForQuestion(mDNS *m, const DNSQuestion *co #pragma mark - host name and interface management #endif -// Called in normal client context (lock not held) -mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n) +mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr); +mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr); +mDNSlocal mDNSBool IsRecordMergeable(mDNS *const m, AuthRecord *rr, mDNSs32 time); + +// When this function is called, service record is already deregistered. We just +// have to deregister the PTR and TXT records. +mDNSlocal void UpdateAllServiceRecords(mDNS *const m, AuthRecord *rr, mDNSBool reg) { - ServiceRecordSet *srs = (ServiceRecordSet *)n->clientContext; - debugf("SRVNatMap complete %.4a IntPort %u ExternalPort %u NATLease %u", &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), n->NATLease); + AuthRecord *r, *srvRR; - if (!srs) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; } - if (!n->NATLease) return; + if (rr->resrec.rrtype != kDNSType_SRV) { LogMsg("UpdateAllServiceRecords:ERROR!! ResourceRecord not a service record %s", ARDisplayString(m, rr)); return; } - mDNS_Lock(m); - if (!mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4)) - SendServiceRegistration(m, srs); // non-zero server address means we already have necessary zone data to send update - else + if (reg && rr->state == regState_NoTarget) { LogMsg("UpdateAllServiceRecords:ERROR!! SRV record %s in noTarget state during registration", ARDisplayString(m, rr)); return; } + + LogInfo("UpdateAllServiceRecords: ResourceRecord %s", ARDisplayString(m, rr)); + + for (r = m->ResourceRecords; r; r=r->next) { - // SHOULD NEVER HAPPEN! - LogInfo("ERROR: CompleteSRVNatMap called but srs->SRSUpdateServer.ip.v4 is zero!"); - srs->state = regState_FetchingZoneData; - if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta); // Make sure we cancel old one before we start a new one - srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs); + if (!AuthRecord_uDNS(r)) continue; + srvRR = mDNSNULL; + if (r->resrec.rrtype == kDNSType_PTR) + srvRR = r->Additional1; + else if (r->resrec.rrtype == kDNSType_TXT) + srvRR = r->DependentOn; + if (srvRR && srvRR->resrec.rrtype != kDNSType_SRV) + LogMsg("UpdateAllServiceRecords: ERROR!! Resource record %s wrong, expecting SRV type", ARDisplayString(m, srvRR)); + if (srvRR == rr) + { + if (!reg) + { + LogInfo("UpdateAllServiceRecords: deregistering %s", ARDisplayString(m, r)); + r->SRVChanged = mDNStrue; + r->ThisAPInterval = INIT_RECORD_REG_INTERVAL; + r->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL; + r->state = regState_DeregPending; + } + else + { + // Clearing SRVchanged is a safety measure. If our pewvious dereg never + // came back and we had a target change, we are starting fresh + r->SRVChanged = mDNSfalse; + // if it is already registered or in the process of registering, then don't + // bother re-registering. This happens today for non-BTMM domains where the + // TXT and PTR get registered before SRV records because of the delay in + // getting the port mapping. There is no point in re-registering the TXT + // and PTR records. + if ((r->state == regState_Registered) || + (r->state == regState_Pending && r->nta && !mDNSIPv4AddressIsZero(r->nta->Addr.ip.v4))) + LogInfo("UpdateAllServiceRecords: not registering %s, state %d", ARDisplayString(m, r), r->state); + else + { + LogInfo("UpdateAllServiceRecords: registering %s, state %d", ARDisplayString(m, r), r->state); + ActivateUnicastRegistration(m, r); + } + } + } } - mDNS_Unlock(m); } -mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs) - { - const mDNSu8 *p = srs->RR_PTR.resrec.name->c; - if (p[0]) p += 1 + p[0]; - if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) srs->NATinfo.Protocol = NATOp_MapTCP; - else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) srs->NATinfo.Protocol = NATOp_MapUDP; - else { LogMsg("StartSRVNatMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); return; } - - if (srs->NATinfo.clientContext) mDNS_StopNATOperation_internal(m, &srs->NATinfo); - // Don't try to set IntPort here -- - // SendServiceRegistration overwrites srs->RR_SRV.resrec.rdata->u.srv.port with external (mapped) port number - //srs->NATinfo.IntPort = srs->RR_SRV.resrec.rdata->u.srv.port; - srs->NATinfo.RequestedPort = srs->RR_SRV.resrec.rdata->u.srv.port; - srs->NATinfo.NATLease = 0; // Request default lease - srs->NATinfo.clientCallback = CompleteSRVNatMap; - srs->NATinfo.clientContext = srs; - mDNS_StartNATOperation_internal(m, &srs->NATinfo); - } - -// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1) -mDNSexport void ServiceRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData) +// Called in normal client context (lock not held) +// Currently only supports SRV records for nat mapping +mDNSlocal void CompleteRecordNatMap(mDNS *m, NATTraversalInfo *n) { - ServiceRecordSet *srs = (ServiceRecordSet *)zoneData->ZoneDataContext; - - if (m->mDNS_busy != m->mDNS_reentrancy) - LogMsg("ServiceRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); - - if (!srs->RR_SRV.resrec.rdata) - { LogMsg("ServiceRegistrationGotZoneData: ERROR: srs->RR_SRV.resrec.rdata is NULL"); return; } - - srs->srs_nta = mDNSNULL; - - // Start off assuming we're going to use a lease - // If we get an error from the server, and the update port as given in the SRV record is 53, then we'll retry without the lease option - srs->srs_uselease = mDNStrue; - - if (err || !zoneData) return; + const domainname *target; + domainname *srvt; + AuthRecord *rr = (AuthRecord *)n->clientContext; + debugf("SRVNatMap complete %.4a IntPort %u ExternalPort %u NATLease %u", &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), n->NATLease); - if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr)) return; + if (!rr) { LogMsg("CompleteRecordNatMap called with unknown AuthRecord object"); return; } + if (!n->NATLease) { LogMsg("CompleteRecordNatMap No NATLease for %s", ARDisplayString(m, rr)); return; } - // cache zone data - AssignDomainName(&srs->zone, &zoneData->ZoneName); - srs->SRSUpdateServer.type = mDNSAddrType_IPv4; - srs->SRSUpdateServer = zoneData->Addr; - srs->SRSUpdatePort = zoneData->Port; - srs->Private = zoneData->ZonePrivate; + if (rr->resrec.rrtype != kDNSType_SRV) {LogMsg("CompleteRecordNatMap: Not a service record %s", ARDisplayString(m, rr)); return; } - srs->RR_SRV.LastAPTime = m->timenow; - srs->RR_SRV.ThisAPInterval = 0; + if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) { LogInfo("CompleteRecordNatMap called for %s, Service deregistering", ARDisplayString(m, rr)); return; } - debugf("ServiceRegistrationGotZoneData My IPv4 %#a%s Server %#a:%d%s for %##s", - &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC1918)" : "", - &srs->SRSUpdateServer, mDNSVal16(srs->SRSUpdatePort), mDNSAddrIsRFC1918(&srs->SRSUpdateServer) ? " (RFC1918)" : "", - srs->RR_SRV.resrec.name->c); + if (rr->state == regState_DeregPending) { LogInfo("CompleteRecordNatMap called for %s, record in DeregPending", ARDisplayString(m, rr)); return; } - // If we have non-zero service port (always?) - // and a private address, and update server is non-private - // and this service is AutoTarget - // then initiate a NAT mapping request. On completion it will do SendServiceRegistration() for us - if (!mDNSIPPortIsZero(srs->RR_SRV.resrec.rdata->u.srv.port) && - mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->SRSUpdateServer) && - srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP) + // As we free the zone info after registering/deregistering with the server (See hndlRecordUpdateReply), + // we need to restart the get zone data and nat mapping request to get the latest mapping result as we can't handle it + // at this moment. Restart from the beginning. + if (!rr->nta || mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4)) { - srs->state = regState_NATMap; - debugf("ServiceRegistrationGotZoneData StartSRVNatMap"); - StartSRVNatMap(m, srs); + LogInfo("CompleteRecordNatMap called for %s but no zone information!", ARDisplayString(m, rr)); + // We need to clear out the NATinfo state so that it will result in re-acuqiring the mapping + // and hence this callback called again. + if (rr->NATinfo.clientContext) + { + mDNS_StopNATOperation_internal(m, &rr->NATinfo); + rr->NATinfo.clientContext = mDNSNULL; + } + rr->state = regState_Pending; + rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; + rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL; + return; } - else - { - mDNS_Lock(m); - SendServiceRegistration(m, srs); + + mDNS_Lock(m); + // Reevaluate the target always as Target could have changed while + // we were getting the port mapping (See UpdateOneSRVRecord) + target = GetServiceTarget(m, rr); + srvt = GetRRDomainNameTarget(&rr->resrec); + if (!target || target->c[0] == 0 || mDNSIPPortIsZero(n->ExternalPort)) + { + if (target && target->c[0]) + LogInfo("CompleteRecordNatMap - Target %##s for ResourceRecord %##s, ExternalPort %d", target->c, rr->resrec.name->c, mDNSVal16(n->ExternalPort)); + else + LogInfo("CompleteRecordNatMap - no target for %##s, ExternalPort %d", rr->resrec.name->c, mDNSVal16(n->ExternalPort)); + if (srvt) srvt->c[0] = 0; + rr->state = regState_NoTarget; + rr->resrec.rdlength = rr->resrec.rdestimate = 0; mDNS_Unlock(m); + UpdateAllServiceRecords(m, rr, mDNSfalse); + return; } + LogInfo("CompleteRecordNatMap - Target %##s for ResourceRecord %##s, ExternalPort %d", target->c, rr->resrec.name->c, mDNSVal16(n->ExternalPort)); + // This function might get called multiple times during a network transition event. Previosuly, we could + // have put the SRV record in NoTarget state above and deregistered all the other records. When this + // function gets called again with a non-zero ExternalPort, we need to set the target and register the + // other records again. + if (srvt && !SameDomainName(srvt, target)) + { + AssignDomainName(srvt, target); + SetNewRData(&rr->resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash + } + + // SRVChanged is set when when the target of the SRV record changes (See UpdateOneSRVRecord). + // As a result of the target change, we might register just that SRV Record if it was + // previously registered and we have a new target OR deregister SRV (and the associated + // PTR/TXT records) if we don't have a target anymore. When we get a response from the server, + // SRVChanged state tells that we registered/deregistered because of a target change + // and hence handle accordingly e.g., if we deregistered, put the records in NoTarget state OR + // if we registered then put it in Registered state. + // + // Here, we are registering all the records again from the beginning. Treat this as first time + // registration rather than a temporary target change. + rr->SRVChanged = mDNSfalse; + + // We want IsRecordMergeable to check whether it is a record whose update can be + // sent with others. We set the time before we call IsRecordMergeable, so that + // it does not fail this record based on time. We are interested in other checks + // at this time + rr->state = regState_Pending; + rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; + rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL; + if (IsRecordMergeable(m, rr, m->timenow + MERGE_DELAY_TIME)) + // Delay the record registration by MERGE_DELAY_TIME so that we can merge them + // into one update + rr->LastAPTime += MERGE_DELAY_TIME; + mDNS_Unlock(m); + // We call this always even though it may not be necessary always e.g., normal registration + // process where TXT and PTR gets registered followed by the SRV record after it gets + // the port mapping. In that case, UpdateAllServiceRecords handles the optimization. The + // update of TXT and PTR record is required if we entered noTargetState before as explained + // above. + UpdateAllServiceRecords(m, rr, mDNStrue); } -mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs) +mDNSlocal void StartRecordNatMap(mDNS *m, AuthRecord *rr) { - mDNSOpaque16 id; - mDNSu8 *ptr = m->omsg.data; - mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage); - mStatus err = mStatus_UnknownErr; - mDNSu32 i; + const mDNSu8 *p; + mDNSu8 protocol; - if (mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4)) // Don't know our UpdateServer yet + if (rr->resrec.rrtype != kDNSType_SRV) { - srs->RR_SRV.LastAPTime = m->timenow; - if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 5) - srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; + LogInfo("StartRecordNatMap: Resource Record %##s type %d, not supported", rr->resrec.name->c, rr->resrec.rrtype); return; } + p = rr->resrec.name->c; + //Assume <Service Instance>.<App Protocol>.<Transport protocol>.<Name> + // Skip the first two labels to get to the transport protocol + if (p[0]) p += 1 + p[0]; + if (p[0]) p += 1 + p[0]; + if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) protocol = NATOp_MapTCP; + else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) protocol = NATOp_MapUDP; + else { LogMsg("StartRecordNatMap: could not determine transport protocol of service %##s", rr->resrec.name->c); return; } + + if (rr->NATinfo.clientContext) mDNS_StopNATOperation_internal(m, &rr->NATinfo); + rr->NATinfo.Protocol = protocol; + rr->NATinfo.IntPort = rr->resrec.rdata->u.srv.port; + rr->NATinfo.RequestedPort = rr->resrec.rdata->u.srv.port; + rr->NATinfo.NATLease = 0; // Request default lease + rr->NATinfo.clientCallback = CompleteRecordNatMap; + rr->NATinfo.clientContext = rr; + mDNS_StartNATOperation_internal(m, &rr->NATinfo); + } - id = mDNS_NewMessageID(m); - InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags); - - // put zone - ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass)); - if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); err = mStatus_UnknownErr; goto exit; } - - if (!(ptr = putDeleteAllRRSets(&m->omsg, ptr, srs->RR_SRV.resrec.name))) { err = mStatus_UnknownErr; goto exit; } // this deletes SRV, TXT, and Extras - if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_PTR.resrec))) { err = mStatus_UnknownErr; goto exit; } - for (i = 0; i < srs->NumSubTypes; i++) - if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->SubTypes[i].resrec))) { err = mStatus_UnknownErr; goto exit; } - - srs->id = id; - srs->state = regState_DeregPending; - srs->RR_SRV.expire = 0; // Indicate that we have no active registration any more - - if (srs->Private) - { - LogInfo("SendServiceDeregistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV)); - if (srs->tcp) LogInfo("SendServiceDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV)); - if (srs->tcp) DisposeTCPConn(srs->tcp); - srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL); - if (!srs->tcp) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2) - else if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 30) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 30; - } - else +// Unlink an Auth Record from the m->ResourceRecords list. +// When a resource record enters regState_NoTarget initially, mDNS_Register_internal +// does not initialize completely e.g., it cannot check for duplicates etc. The resource +// record is temporarily left in the ResourceRecords list so that we can initialize later +// when the target is resolvable. Similarly, when host name changes, we enter regState_NoTarget +// and we do the same. +mDNSlocal mStatus UnlinkResourceRecord(mDNS *const m, AuthRecord *const rr) + { + AuthRecord **list = &m->ResourceRecords; + while (*list && *list != rr) list = &(*list)->next; + if (*list) { - err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name)); - if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %d", err); goto exit; } + *list = rr->next; + rr->next = mDNSNULL; + return(mStatus_NoError); } + LogMsg("UnlinkResourceRecord:ERROR!! - no such active record %##s", rr->resrec.name->c); + return(mStatus_NoSuchRecord); + } - SetRecordRetry(m, &srs->RR_SRV, err); - return; - -exit: - if (err) - { - LogMsg("SendServiceDeregistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c); - unlinkSRS(m, srs); - srs->state = regState_Unregistered; - } +// We need to go through mDNS_Register again as we did not complete the +// full initialization last time e.g., duplicate checks. +// After we register, we will be in regState_GetZoneData. +mDNSlocal void RegisterAllServiceRecords(mDNS *const m, AuthRecord *rr) + { + LogInfo("RegisterAllServiceRecords: Service Record %##s", rr->resrec.name->c); + // First Register the service record, we do this differently from other records because + // when it entered NoTarget state, it did not go through complete initialization + rr->SRVChanged = mDNSfalse; + UnlinkResourceRecord(m, rr); + mDNS_Register_internal(m, rr); + // Register the other records + UpdateAllServiceRecords(m, rr, mDNStrue); } // Called with lock held -mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs) +mDNSlocal void UpdateOneSRVRecord(mDNS *m, AuthRecord *rr) { - ExtraResourceRecord *e; - // Target change if: // We have a target and were previously waiting for one, or // We had a target and no longer do, or // The target has changed - domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target; - const domainname *const nt = GetServiceTarget(m, &srs->RR_SRV); + domainname *curtarget = &rr->resrec.rdata->u.srv.target; + const domainname *const nt = GetServiceTarget(m, rr); const domainname *const newtarget = nt ? nt : (domainname*)""; - mDNSBool TargetChanged = (newtarget->c[0] && srs->state == regState_NoTarget) || !SameDomainName(curtarget, newtarget); - mDNSBool HaveZoneData = !mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4); + mDNSBool TargetChanged = (newtarget->c[0] && rr->state == regState_NoTarget) || !SameDomainName(curtarget, newtarget); + mDNSBool HaveZoneData = rr->nta && !mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4); // Nat state change if: // We were behind a NAT, and now we are behind a new NAT, or // We're not behind a NAT but our port was previously mapped to a different external port // We were not behind a NAT and now we are - mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port; - mDNSBool NowNeedNATMAP = (srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(port) && mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->SRSUpdateServer)); - mDNSBool WereBehindNAT = (srs->NATinfo.clientContext != mDNSNULL); - mDNSBool PortWasMapped = (srs->NATinfo.clientContext && !mDNSSameIPPort(srs->NATinfo.RequestedPort, port)); // I think this is always false -- SC Sept 07 + mDNSIPPort port = rr->resrec.rdata->u.srv.port; + mDNSBool NowNeedNATMAP = (rr->AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(port) && mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && rr->nta && !mDNSAddrIsRFC1918(&rr->nta->Addr)); + mDNSBool WereBehindNAT = (rr->NATinfo.clientContext != mDNSNULL); + mDNSBool PortWasMapped = (rr->NATinfo.clientContext && !mDNSSameIPPort(rr->NATinfo.RequestedPort, port)); // I think this is always false -- SC Sept 07 mDNSBool NATChanged = (!WereBehindNAT && NowNeedNATMAP) || (!NowNeedNATMAP && PortWasMapped); - debugf("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowNeedNATMAP %d WereBehindNAT %d PortWasMapped %d NATChanged %d", - srs->RR_SRV.resrec.name->c, newtarget, + (void)HaveZoneData; //unused + + LogInfo("UpdateOneSRVRecord: Resource Record %s TargetChanged %d, NewTarget %##s", ARDisplayString(m, rr), TargetChanged, nt->c); + + debugf("UpdateOneSRVRecord: %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowNeedNATMAP %d WereBehindNAT %d PortWasMapped %d NATChanged %d", + rr->resrec.name->c, newtarget, TargetChanged, HaveZoneData, mDNSVal16(port), NowNeedNATMAP, WereBehindNAT, PortWasMapped, NATChanged); if (m->mDNS_busy != m->mDNS_reentrancy+1) - LogMsg("UpdateSRV: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + LogMsg("UpdateOneSRVRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); if (!TargetChanged && !NATChanged) return; - switch(srs->state) + // If we are deregistering the record, then ignore any NAT/Target change. + if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) + { + LogInfo("UpdateOneSRVRecord: Deregistering record, Ignoring TargetChanged %d, NATChanged %d for %##s, state %d", TargetChanged, NATChanged, + rr->resrec.name->c, rr->state); + return; + } + + if (newtarget) + LogInfo("UpdateOneSRVRecord: TargetChanged %d, NATChanged %d for %##s, state %d, newtarget %##s", TargetChanged, NATChanged, rr->resrec.name->c, rr->state, newtarget->c); + else + LogInfo("UpdateOneSRVRecord: TargetChanged %d, NATChanged %d for %##s, state %d, null newtarget", TargetChanged, NATChanged, rr->resrec.name->c, rr->state); + switch(rr->state) { - case regState_FetchingZoneData: - case regState_DeregPending: - case regState_DeregDeferred: - case regState_Unregistered: case regState_NATMap: - case regState_ExtraQueued: // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is) - // or is in the process of, or has already been, deregistered + // or is in the process of, or has already been, deregistered. This assumes that whenever we transition out + // of this state, we need to look at the target again. return; - case regState_Pending: - case regState_Refresh: case regState_UpdatePending: - // let the in-flight operation complete before updating - srs->SRVUpdateDeferred = mDNStrue; + // We are getting a Target change/NAT change while the SRV record is being updated ? + // let us not do anything for now. return; case regState_NATError: @@ -3078,61 +1915,75 @@ mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs) // if nat changed, register if we have a target (below) case regState_NoTarget: - if (newtarget->c[0]) + if (!newtarget->c[0]) { - debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowNeedNATMAP ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c); - if (!HaveZoneData) - { - srs->state = regState_FetchingZoneData; - if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta); // Make sure we cancel old one before we start a new one - srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs); - } - else - { - if (srs->NATinfo.clientContext && (NATChanged || !NowNeedNATMAP)) - { - mDNS_StopNATOperation_internal(m, &srs->NATinfo); - srs->NATinfo.clientContext = mDNSNULL; - } - if (NATChanged && NowNeedNATMAP && srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP) - { srs->state = regState_NATMap; StartSRVNatMap(m, srs); } - else SendServiceRegistration(m, srs); - } + LogInfo("UpdateOneSRVRecord: No target yet for Resource Record %s", ARDisplayString(m, rr)); + return; } + RegisterAllServiceRecords(m , rr); return; - + case regState_DeregPending: + // We are in DeregPending either because the service was deregistered from above or we handled + // a NAT/Target change before and sent the deregistration below. There are a few race conditions + // possible + // + // 1. We are handling a second NAT/Target change while the first dereg is in progress. It is possible + // that first dereg never made it through because there was no network connectivity e.g., disconnecting + // from network triggers this function due to a target change and later connecting to the network + // retriggers this function but the deregistration never made it through yet. Just fall through. + // If there is a target register otherwise deregister. + // + // 2. While we sent the dereg during a previous NAT/Target change, uDNS_DeregisterRecord gets + // called as part of service deregistration. When the response comes back, we call + // CompleteDeregistration rather than handle NAT/Target change because the record is in + // kDNSRecordTypeDeregistering state. + // + // 3. If the upper layer deregisters the service, we check for kDNSRecordTypeDeregistering both + // here in this function to avoid handling NAT/Target change and in hndlRecordUpdateReply to call + // CompleteDeregistration instead of handling NAT/Target change. Hence, we are not concerned + // about that case here. + // + // We just handle case (1) by falling through + case regState_Pending: + case regState_Refresh: case regState_Registered: // target or nat changed. deregister service. upon completion, we'll look for a new target - debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs->RR_SRV.resrec.name->c); - for (e = srs->Extras; e; e = e->next) e->r.state = regState_ExtraQueued; // extra will be re-registed if the service is re-registered - srs->SRVChanged = mDNStrue; - SendServiceDeregistration(m, srs); + rr->SRVChanged = mDNStrue; + rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; + rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL; + if (newtarget->c[0]) + { + LogInfo("UpdateOneSRVRecord: SRV record changed for service %##s, registering with new target %##s", + rr->resrec.name->c, newtarget->c); + rr->state = regState_Pending; + } + else + { + LogInfo("UpdateOneSRVRecord: SRV record changed for service %##s de-registering", rr->resrec.name->c); + rr->state = regState_DeregPending; + UpdateAllServiceRecords(m, rr, mDNSfalse); + } return; - - default: LogMsg("UpdateSRV: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c); + case regState_Unregistered: + default: LogMsg("UpdateOneSRVRecord: Unknown state %d for %##s", rr->state, rr->resrec.name->c); } } -// Called with lock held -mDNSlocal void UpdateSRVRecords(mDNS *m) +mDNSexport void UpdateAllSRVRecords(mDNS *m) { - debugf("UpdateSRVRecords%s", m->SleepState ? " (ignored due to SleepState)" : ""); - if (m->SleepState) return; + m->NextSRVUpdate = 0; + LogInfo("UpdateAllSRVRecords %d", m->SleepState); - if (CurrentServiceRecordSet) - LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set"); - CurrentServiceRecordSet = m->ServiceRegistrations; - - while (CurrentServiceRecordSet) + if (m->CurrentRecord) + LogMsg("UpdateAllSRVRecords ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); + m->CurrentRecord = m->ResourceRecords; + while (m->CurrentRecord) { - ServiceRecordSet *s = CurrentServiceRecordSet; - CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next; - UpdateSRV(m, s); + AuthRecord *rptr = m->CurrentRecord; + m->CurrentRecord = m->CurrentRecord->next; + if (AuthRecord_uDNS(rptr) && rptr->resrec.rrtype == kDNSType_SRV) + UpdateOneSRVRecord(m, rptr); } - - mDNS_DropLockBeforeCallback(); // mDNS_SetFQDN expects to be called without the lock held, so we emulate that here - mDNS_SetFQDN(m); - mDNS_ReclaimLockAfterCallback(); } // Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname @@ -3152,7 +2003,7 @@ mDNSlocal void hostnameGetPublicAddressCallback(mDNS *m, NATTraversalInfo *n) if (h->arv4.resrec.RecordType) { if (mDNSSameIPv4Address(h->arv4.resrec.rdata->u.ipv4, n->ExternalAddress)) return; // If address unchanged, do nothing - LogInfo("Updating hostname %##s IPv4 from %.4a to %.4a (NAT gateway's external address)", + LogInfo("Updating hostname %p %##s IPv4 from %.4a to %.4a (NAT gateway's external address)",n, h->arv4.resrec.name->c, &h->arv4.resrec.rdata->u.ipv4, &n->ExternalAddress); mDNS_Deregister(m, &h->arv4); // mStatus_MemFree callback will re-register with new address } @@ -3257,7 +2108,7 @@ mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus res // register any pending services that require a target mDNS_Lock(m); - UpdateSRVRecords(m); + m->NextSRVUpdate = NonZeroTime(m->timenow); mDNS_Unlock(m); // Deliver success to client @@ -3281,30 +2132,34 @@ mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const R (void)question; - debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed"); - if (AddRecord && !SameDomainName(pktname, storedname)) + if (answer->rdlength != 0) + LogInfo("FoundStaticHostname: question %##s -> answer %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "ADD" : "RMV"); + else + LogInfo("FoundStaticHostname: question %##s -> answer NULL (%s)", question->qname.c, AddRecord ? "ADD" : "RMV"); + + if (AddRecord && answer->rdlength != 0 && !SameDomainName(pktname, storedname)) { AssignDomainName(storedname, pktname); while (h) { - if (h->arv4.state == regState_FetchingZoneData || h->arv4.state == regState_Pending || h->arv4.state == regState_NATMap || - h->arv6.state == regState_FetchingZoneData || h->arv6.state == regState_Pending) + if (h->arv4.state == regState_Pending || h->arv4.state == regState_NATMap || h->arv6.state == regState_Pending) { // if we're in the process of registering a dynamic hostname, delay SRV update so we don't have to reregister services if the dynamic name succeeds m->NextSRVUpdate = NonZeroTime(m->timenow + 5 * mDNSPlatformOneSecond); + debugf("FoundStaticHostname: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow); return; } h = h->next; } mDNS_Lock(m); - UpdateSRVRecords(m); + m->NextSRVUpdate = NonZeroTime(m->timenow); mDNS_Unlock(m); } else if (!AddRecord && SameDomainName(pktname, storedname)) { mDNS_Lock(m); storedname->c[0] = 0; - UpdateSRVRecords(m); + m->NextSRVUpdate = NonZeroTime(m->timenow); mDNS_Unlock(m); } } @@ -3333,6 +2188,7 @@ mDNSlocal void GetStaticHostname(mDNS *m) q->ExpectUnique = mDNSfalse; q->ForceMCast = mDNSfalse; q->ReturnIntermed = mDNStrue; + q->SuppressUnusable = mDNSfalse; q->QuestionCallback = FoundStaticHostname; q->QuestionContext = mDNSNULL; @@ -3386,7 +2242,8 @@ mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) if (f6) mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal); // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback } - UpdateSRVRecords(m); + if (!m->mDNS_busy) LogMsg("mDNS_RemoveDynDNSHostName: ERROR: Lock not held"); + m->NextSRVUpdate = NonZeroTime(m->timenow); } // Currently called without holding the lock @@ -3404,8 +2261,6 @@ mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, co mDNS_Lock(m); - if (v4addr && !mDNSv4AddressIsLinkLocal(&v4addr->ip.v4)) v6addr = mDNSNULL; - v4Changed = !mDNSSameIPv4Address(m->AdvertisedV4.ip.v4, v4addr ? v4addr->ip.v4 : zerov4Addr); v6Changed = !mDNSSameIPv6Address(m->AdvertisedV6.ip.v6, v6addr ? v6addr->ip.v6 : zerov6Addr); RouterChanged = !mDNSSameIPv4Address(m->Router.ip.v4, router ? router->ip.v4 : zerov4Addr); @@ -3451,20 +2306,27 @@ mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, co if (v4Changed || RouterChanged) { + // If we have a non-zero IPv4 address, we should try immediately to see if we have a NAT gateway + // If we have no IPv4 address, we don't want to be in quite such a hurry to report failures to our clients + // <rdar://problem/6935929> Sleeping server sometimes briefly disappears over Back to My Mac after it wakes up m->ExternalAddress = zerov4Addr; m->retryIntervalGetAddr = NATMAP_INIT_RETRY; - m->retryGetAddr = m->timenow; + m->retryGetAddr = m->timenow + (v4addr ? 0 : mDNSPlatformOneSecond * 5); m->NextScheduledNATOp = m->timenow; m->LastNATMapResultCode = NATErr_None; #ifdef _LEGACY_NAT_TRAVERSAL_ LNT_ClearState(m); #endif // _LEGACY_NAT_TRAVERSAL_ + LogInfo("mDNS_SetPrimaryInterfaceInfo:%s%s: retryGetAddr in %d %d", + v4Changed ? " v4Changed" : "", + RouterChanged ? " RouterChanged" : "", + m->retryGetAddr - m->timenow, m->timenow); } if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, &m->ReverseMap); m->StaticHostname.c[0] = 0; - UpdateSRVRecords(m); // Will call GetStaticHostname if needed + m->NextSRVUpdate = NonZeroTime(m->timenow); #if APPLE_OSX_mDNSResponder if (RouterChanged) uuid_generate(m->asl_uuid); @@ -3493,7 +2355,7 @@ mDNSlocal mStatus ParseTSIGError(mDNS *const m, const DNSMessage *const msg, con { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); if (!ptr) goto finish; - if (m->rec.r.resrec.rrtype == kDNSType_TSIG) + if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_TSIG) { mDNSu32 macsize; mDNSu8 *rd = m->rec.r.resrec.rdata->u.data; @@ -3576,337 +2438,718 @@ mDNSlocal mStatus checkUpdateResult(mDNS *const m, const domainname *const displ } } -// Called with lock held -mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr) +// We add three Additional Records for unicast resource record registrations +// which is a function of AuthInfo and AutoTunnel properties +mDNSlocal mDNSu32 RRAdditionalSize(mDNS *const m, DomainAuthInfo *AuthInfo) { - mDNSu8 *ptr = m->omsg.data; - mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage); - mStatus err = mStatus_UnknownErr; - - if (m->mDNS_busy != m->mDNS_reentrancy+1) - LogMsg("SendRecordRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + mDNSu32 leaseSize, hinfoSize, tsigSize; + mDNSu32 rr_base_size = 10; // type (2) class (2) TTL (4) rdlength (2) + + // OPT RR : Emptyname(.) + base size + rdataOPT + leaseSize = 1 + rr_base_size + sizeof(rdataOPT); + + // HINFO: Resource Record Name + base size + RDATA + // HINFO is added only for autotunnels + hinfoSize = 0; + if (AuthInfo && AuthInfo->AutoTunnel) + hinfoSize = (m->hostlabel.c[0] + 1) + DomainNameLength(&AuthInfo->domain) + + rr_base_size + (2 + m->HIHardware.c[0] + m->HISoftware.c[0]); + + //TSIG: Resource Record Name + base size + RDATA + // RDATA: + // Algorithm name: hmac-md5.sig-alg.reg.int (8+7+3+3 + 5 bytes for length = 26 bytes) + // Time: 6 bytes + // Fudge: 2 bytes + // Mac Size: 2 bytes + // Mac: 16 bytes + // ID: 2 bytes + // Error: 2 bytes + // Len: 2 bytes + // Total: 58 bytes + tsigSize = 0; + if (AuthInfo) tsigSize = DomainNameLength(&AuthInfo->keyname) + rr_base_size + 58; + + return (leaseSize + hinfoSize + tsigSize); + } - if (mDNSIPv4AddressIsZero(rr->UpdateServer.ip.v4)) // Don't know our UpdateServer yet +//Note: Make sure that RREstimatedSize is updated accordingly if anything that is done here +//would modify rdlength/rdestimate +mDNSlocal mDNSu8* BuildUpdateMessage(mDNS *const m, mDNSu8 *ptr, AuthRecord *rr, mDNSu8 *limit) + { + //If this record is deregistering, then just send the deletion record + if (rr->state == regState_DeregPending) { - rr->LastAPTime = m->timenow; - if (rr->ThisAPInterval < mDNSPlatformOneSecond * 5) - rr->ThisAPInterval = mDNSPlatformOneSecond * 5; - return; + rr->expire = 0; // Indicate that we have no active registration any more + ptr = putDeletionRecordWithLimit(&m->omsg, ptr, &rr->resrec, limit); + if (!ptr) goto exit; + return ptr; } - rr->RequireGoodbye = mDNStrue; - rr->updateid = mDNS_NewMessageID(m); - InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags); + // This is a common function to both sending an update in a group or individual + // records separately. Hence, we change the state here. + if (rr->state == regState_Registered) rr->state = regState_Refresh; + if (rr->state != regState_Refresh && rr->state != regState_UpdatePending) + rr->state = regState_Pending; - // set zone - ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); - if (!ptr) { err = mStatus_UnknownErr; goto exit; } + // For Advisory records like e.g., _services._dns-sd, which is shared, don't send goodbyes as multiple + // host might be registering records and deregistering from one does not make sense + if (rr->resrec.RecordType != kDNSRecordTypeAdvisory) rr->RequireGoodbye = mDNStrue; + + if ((rr->resrec.rrtype == kDNSType_SRV) && (rr->AutoTarget == Target_AutoHostAndNATMAP) && + !mDNSIPPortIsZero(rr->NATinfo.ExternalPort)) + { + rr->resrec.rdata->u.srv.port = rr->NATinfo.ExternalPort; + } if (rr->state == regState_UpdatePending) { // delete old RData SetNewRData(&rr->resrec, rr->OrigRData, rr->OrigRDLen); - if (!(ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata + if (!(ptr = putDeletionRecordWithLimit(&m->omsg, ptr, &rr->resrec, limit))) goto exit; // delete old rdata // add new RData SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen); - if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; } + if (!(ptr = PutResourceRecordTTLWithLimit(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit))) goto exit; } - else { - if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique) + if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique || rr->resrec.RecordType == kDNSRecordTypeVerified) { - // KnownUnique: Delete any previous value - ptr = putDeleteRRSet(&m->omsg, ptr, rr->resrec.name, rr->resrec.rrtype); - if (!ptr) { err = mStatus_UnknownErr; goto exit; } + // KnownUnique : Delete any previous value + // For Unicast registrations, we don't verify that it is unique, but set to verified and hence we want to + // delete any previous value + ptr = putDeleteRRSetWithLimit(&m->omsg, ptr, rr->resrec.name, rr->resrec.rrtype, limit); + if (!ptr) goto exit; } - else if (rr->resrec.RecordType != kDNSRecordTypeShared) { - // For now don't do this, until we have the logic for intelligent grouping of individual recors into logical service record sets + // For now don't do this, until we have the logic for intelligent grouping of individual records into logical service record sets //ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end); - if (!ptr) { err = mStatus_UnknownErr; goto exit; } + if (!ptr) goto exit; } - ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl); - if (!ptr) { err = mStatus_UnknownErr; goto exit; } + ptr = PutResourceRecordTTLWithLimit(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit); + if (!ptr) goto exit; } - if (rr->uselease) + return ptr; +exit: + LogMsg("BuildUpdateMessage: Error formatting message for %s", ARDisplayString(m, rr)); + return mDNSNULL; + } + +// Called with lock held +mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr) + { + mDNSu8 *ptr = m->omsg.data; + mStatus err = mStatus_UnknownErr; + mDNSu8 *limit; + DomainAuthInfo *AuthInfo; + + // For the ability to register large TXT records, we limit the single record registrations + // to AbsoluteMaxDNSMessageData + limit = ptr + AbsoluteMaxDNSMessageData; + + AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name); + limit -= RRAdditionalSize(m, AuthInfo); + + if (m->mDNS_busy != m->mDNS_reentrancy+1) + LogMsg("SendRecordRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + + if (!rr->nta || mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4)) { - ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; } + // We never call this function when there is no zone information . Log a message if it ever happens. + LogMsg("SendRecordRegistration: No Zone information, should not happen %s", ARDisplayString(m, rr)); + return; } + rr->updateid = mDNS_NewMessageID(m); + InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags); + + // set zone + ptr = putZone(&m->omsg, ptr, limit, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); + if (!ptr) goto exit; + + if (!(ptr = BuildUpdateMessage(m, ptr, rr, limit))) goto exit; + + if (rr->uselease) + { + ptr = putUpdateLeaseWithLimit(&m->omsg, ptr, DEFAULT_UPDATE_LEASE, limit); + if (!ptr) goto exit; + } if (rr->Private) { LogInfo("SendRecordRegistration TCP %p %s", rr->tcp, ARDisplayString(m, rr)); if (rr->tcp) LogInfo("SendRecordRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr)); - if (rr->tcp) DisposeTCPConn(rr->tcp); - rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr); - if (!rr->tcp) rr->ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2) - else if (rr->ThisAPInterval < mDNSPlatformOneSecond * 30) rr->ThisAPInterval = mDNSPlatformOneSecond * 30; + if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } + if (!rr->nta) { LogMsg("SendRecordRegistration:Private:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; } + rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->nta->Addr, rr->nta->Port, &rr->nta->Host, mDNSNULL, rr); } else { - err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name)); + LogInfo("SendRecordRegistration UDP %s", ARDisplayString(m, rr)); + if (!rr->nta) { LogMsg("SendRecordRegistration:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; } + err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->nta->Addr, rr->nta->Port, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name)); if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %d", err); } - SetRecordRetry(m, rr, err); + SetRecordRetry(m, rr, 0); + return; +exit: + LogMsg("SendRecordRegistration: Error formatting message for %s, disabling further updates", ARDisplayString(m, rr)); + // Disable this record from future updates + rr->state = regState_NoTarget; + } - if (rr->state != regState_Refresh && rr->state != regState_DeregDeferred && rr->state != regState_UpdatePending) - rr->state = regState_Pending; +// Is the given record "rr" eligible for merging ? +mDNSlocal mDNSBool IsRecordMergeable(mDNS *const m, AuthRecord *rr, mDNSs32 time) + { + DomainAuthInfo *info; + (void) m; //unused + // A record is eligible for merge, if the following properties are met. + // + // 1. uDNS Resource Record + // 2. It is time to send them now + // 3. It is in proper state + // 4. Update zone has been resolved + // 5. if DomainAuthInfo exists for the zone, it should not be soon deleted + // 6. Zone information is present + // 7. Update server is not zero + // 8. It has a non-null zone + // 9. It uses a lease option + // 10. DontMerge is not set + // + // Following code is implemented as separate "if" statements instead of one "if" statement + // is for better debugging purposes e.g., we know exactly what failed if debugging turned on. - return; + if (!AuthRecord_uDNS(rr)) return mDNSfalse; -exit: - LogMsg("SendRecordRegistration: Error formatting message for %s", ARDisplayString(m, rr)); + if (rr->LastAPTime + rr->ThisAPInterval - time > 0) + { debugf("IsRecordMergeable: Time %d not reached for %s", rr->LastAPTime + rr->ThisAPInterval - m->timenow, ARDisplayString(m, rr)); return mDNSfalse; } + + if (!rr->zone) return mDNSfalse; + + info = GetAuthInfoForName_internal(m, rr->zone); + + if (info && info->deltime && m->timenow - info->deltime >= 0) {debugf("IsRecordMergeable: Domain %##s will be deleted soon", info->domain.c); return mDNSfalse;} + + if (rr->state != regState_DeregPending && rr->state != regState_Pending && rr->state != regState_Registered && rr->state != regState_Refresh && rr->state != regState_UpdatePending) + { debugf("IsRecordMergeable: state %d not right %s", rr->state, ARDisplayString(m, rr)); return mDNSfalse; } + + if (!rr->nta || mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4)) return mDNSfalse; + + if (!rr->uselease) return mDNSfalse; + + if (rr->mState == mergeState_DontMerge) {debugf("IsRecordMergeable Dontmerge true %s", ARDisplayString(m, rr));return mDNSfalse;} + debugf("IsRecordMergeable: Returning true for %s", ARDisplayString(m, rr)); + return mDNStrue; } -// Called with lock held -mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mStatus err) +// Is the resource record "rr" eligible to merge to with "currentRR" ? +mDNSlocal mDNSBool AreRecordsMergeable(mDNS *const m, AuthRecord *currentRR, AuthRecord *rr, mDNSs32 time) { - mDNSBool InvokeCallback = mDNSfalse; - ExtraResourceRecord **e = &srs->Extras; - AuthRecord *txt = &srs->RR_TXT; + // A record is eligible to merge with another record as long it is eligible for merge in itself + // and it has the same zone information as the other record + if (!IsRecordMergeable(m, rr, time)) return mDNSfalse; - if (m->mDNS_busy != m->mDNS_reentrancy+1) - LogMsg("hndlServiceUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + if (!SameDomainName(currentRR->zone, rr->zone)) + { debugf("AreRecordMergeable zone mismatch current rr Zone %##s, rr zone %##s", currentRR->zone->c, rr->zone->c); return mDNSfalse; } + + if (!mDNSSameIPv4Address(currentRR->nta->Addr.ip.v4, rr->nta->Addr.ip.v4)) return mDNSfalse; - debugf("hndlServiceUpdateReply: err %d state %d %##s", err, srs->state, srs->RR_SRV.resrec.name->c); + if (!mDNSSameIPPort(currentRR->nta->Port, rr->nta->Port)) return mDNSfalse; - SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError); + debugf("AreRecordsMergeable: Returning true for %s", ARDisplayString(m, rr)); + return mDNStrue; + } - switch (srs->state) +// If we can't build the message successfully because of problems in pre-computing +// the space, we disable merging for all the current records +mDNSlocal void RRMergeFailure(mDNS *const m) + { + AuthRecord *rr; + for (rr = m->ResourceRecords; rr; rr = rr->next) { - case regState_Pending: - if (err == mStatus_NameConflict && !srs->TestForSelfConflict) - { - srs->TestForSelfConflict = mDNStrue; - debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c); - SendServiceRegistration(m, srs); - return; - } - else if (srs->TestForSelfConflict) - { - srs->TestForSelfConflict = mDNSfalse; - if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict - if (!err) srs->state = regState_Registered; - InvokeCallback = mDNStrue; - break; - } - else if (srs->srs_uselease && err == mStatus_UnknownErr && mDNSSameIPPort(srs->SRSUpdatePort, UnicastDNSPort)) - { - LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c); - srs->srs_uselease = mDNSfalse; - SendServiceRegistration(m, srs); - return; - } - else - { - //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state - if (err) LogMsg("Error %d for registration of service %##s", err, srs->RR_SRV.resrec.name->c); - else srs->state = regState_Registered; - InvokeCallback = mDNStrue; - break; - } - case regState_Refresh: - if (err) - { - LogMsg("Error %d for refresh of service %##s", err, srs->RR_SRV.resrec.name->c); - InvokeCallback = mDNStrue; - } - else srs->state = regState_Registered; - break; - case regState_DeregPending: - if (err) LogMsg("Error %d for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c); - if (srs->SRVChanged) - { - srs->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state - break; - } - err = mStatus_MemFree; - InvokeCallback = mDNStrue; - if (srs->NATinfo.clientContext) - { - // deletion completed - mDNS_StopNATOperation_internal(m, &srs->NATinfo); - srs->NATinfo.clientContext = mDNSNULL; - } - srs->state = regState_Unregistered; - break; - case regState_DeregDeferred: - if (err) - { - debugf("Error %d received prior to deferred deregistration of %##s", err, srs->RR_SRV.resrec.name->c); - err = mStatus_MemFree; - InvokeCallback = mDNStrue; - srs->state = regState_Unregistered; - break; - } - else - { - debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c); - srs->state = regState_Registered; - SendServiceDeregistration(m, srs); - return; - } - case regState_UpdatePending: - if (err) - { - LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c); - InvokeCallback = mDNStrue; - } - else - { - srs->state = regState_Registered; - // deallocate old RData - if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData); - SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen); - txt->OrigRData = mDNSNULL; - txt->InFlightRData = mDNSNULL; - } - break; - case regState_NoTarget: - // This state is used when using SendServiceDeregistration() when going to sleep -- no further action required - return; - case regState_FetchingZoneData: - case regState_Registered: - case regState_Unregistered: - case regState_NATMap: - case regState_ExtraQueued: - case regState_NATError: - LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %d. Unlinking.", - srs->RR_SRV.resrec.name->c, srs->state, err); - err = mStatus_UnknownErr; - default: LogMsg("hndlServiceUpdateReply: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c); + rr->mState = mergeState_DontMerge; + rr->SendRNow = mDNSNULL; + // Restarting the registration is much simpler than saving and restoring + // the exact time + ActivateUnicastRegistration(m, rr); } + } - if ((srs->SRVChanged || srs->SRVUpdateDeferred) && (srs->state == regState_NoTarget || srs->state == regState_Registered)) +mDNSlocal void SendGroupRRMessage(mDNS *const m, AuthRecord *anchorRR, mDNSu8 *ptr, DomainAuthInfo *info) + { + mDNSu8 *limit; + if (!anchorRR) {debugf("SendGroupRRMessage: Could not merge records"); return;} + + if (info && info->AutoTunnel) limit = m->omsg.data + AbsoluteMaxDNSMessageData; + else limit = m->omsg.data + NormalMaxDNSMessageData; + + // This has to go in the additional section and hence need to be done last + ptr = putUpdateLeaseWithLimit(&m->omsg, ptr, DEFAULT_UPDATE_LEASE, limit); + if (!ptr) { - debugf("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs->SRVChanged, srs->SRVUpdateDeferred, srs->state); - if (InvokeCallback) - { - srs->ClientCallbackDeferred = mDNStrue; - srs->DeferredStatus = err; - } - srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse; - UpdateSRV(m, srs); + LogMsg("SendGroupRRMessage: ERROR: Could not put lease option, failing the group registration"); + // if we can't put the lease, we need to undo the merge + RRMergeFailure(m); return; } + if (anchorRR->Private) + { + if (anchorRR->tcp) debugf("SendGroupRRMessage: Disposing existing TCP connection for %s", ARDisplayString(m, anchorRR)); + if (anchorRR->tcp) { DisposeTCPConn(anchorRR->tcp); anchorRR->tcp = mDNSNULL; } + if (!anchorRR->nta) { LogMsg("SendGroupRRMessage:ERROR!! nta is NULL for %s", ARDisplayString(m, anchorRR)); return; } + anchorRR->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &anchorRR->nta->Addr, anchorRR->nta->Port, &anchorRR->nta->Host, mDNSNULL, anchorRR); + if (!anchorRR->tcp) LogInfo("SendGroupRRMessage: Cannot establish TCP connection for %s", ARDisplayString(m, anchorRR)); + else LogInfo("SendGroupRRMessage: Sent a group update ID: %d start %p, end %p, limit %p", mDNSVal16(m->omsg.h.id), m->omsg.data, ptr, limit); + } + else + { + mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &anchorRR->nta->Addr, anchorRR->nta->Port, mDNSNULL, info); + if (err) LogInfo("SendGroupRRMessage: Cannot send UDP message for %s", ARDisplayString(m, anchorRR)); + else LogInfo("SendGroupRRMessage: Sent a group UDP update ID: %d start %p, end %p, limit %p", mDNSVal16(m->omsg.h.id), m->omsg.data, ptr, limit); + } + return; + } + +// As we always include the zone information and the resource records contain zone name +// at the end, it will get compressed. Hence, we subtract zoneSize and add two bytes for +// the compression pointer +mDNSlocal mDNSu32 RREstimatedSize(AuthRecord *rr, int zoneSize) + { + int rdlength; - while (*e) + // Note: Estimation of the record size has to mirror the logic in BuildUpdateMessage, otherwise estimation + // would be wrong. Currently BuildUpdateMessage calls SetNewRData in UpdatePending case. Hence, we need + // to account for that here. Otherwise, we might under estimate the size. + if (rr->state == regState_UpdatePending) + // old RData that will be deleted + // new RData that will be added + rdlength = rr->OrigRDLen + rr->InFlightRDLen; + else + rdlength = rr->resrec.rdestimate; + + if (rr->state == regState_DeregPending) { - if ((*e)->r.state == regState_ExtraQueued) + debugf("RREstimatedSize: ResourceRecord %##s (%s), DomainNameLength %d, zoneSize %d, rdestimate %d", + rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), DomainNameLength(rr->resrec.name), zoneSize, rdlength); + return DomainNameLength(rr->resrec.name) - zoneSize + 2 + 10 + rdlength; + } + + // For SRV, TXT, AAAA etc. that are Unique/Verified, we also send a Deletion Record + if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique || rr->resrec.RecordType == kDNSRecordTypeVerified) + { + // Deletion Record: Resource Record Name + Base size (10) + 0 + // Record: Resource Record Name (Compressed = 2) + Base size (10) + rdestimate + + debugf("RREstimatedSize: ResourceRecord %##s (%s), DomainNameLength %d, zoneSize %d, rdestimate %d", + rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), DomainNameLength(rr->resrec.name), zoneSize, rdlength); + return DomainNameLength(rr->resrec.name) - zoneSize + 2 + 10 + 2 + 10 + rdlength; + } + else + { + return DomainNameLength(rr->resrec.name) - zoneSize + 2 + 10 + rdlength; + } + } + +mDNSlocal AuthRecord *MarkRRForSending(mDNS *const m) + { + AuthRecord *rr; + AuthRecord *firstRR = mDNSNULL; + + // Look for records that needs to be sent in the next two seconds (MERGE_DELAY_TIME is set to 1 second). + // The logic is as follows. + // + // 1. Record 1 finishes getting zone data and its registration gets delayed by 1 second + // 2. Record 2 comes 0.1 second later, finishes getting its zone data and its registration is also delayed by + // 1 second which is now scheduled at 1.1 second + // + // By looking for 1 second into the future (m->timenow + MERGE_DELAY_TIME below does that) we have merged both + // of the above records. Note that we can't look for records too much into the future as this will affect the + // retry logic. The first retry is scheduled at 3 seconds. Hence, we should always look smaller than that. + // Anything more than one second will affect the first retry to happen sooner. + // + // Note: As a side effect of looking one second into the future to facilitate merging, the retries happen + // one second sooner. + for (rr = m->ResourceRecords; rr; rr = rr->next) + { + if (!firstRR) + { + if (!IsRecordMergeable(m, rr, m->timenow + MERGE_DELAY_TIME)) continue; + firstRR = rr; + } + else if (!AreRecordsMergeable(m, firstRR, rr, m->timenow + MERGE_DELAY_TIME)) continue; + + if (rr->SendRNow) LogMsg("MarkRRForSending: Resourcerecord %s already marked for sending", ARDisplayString(m, rr)); + rr->SendRNow = mDNSInterfaceMark; + } + + // We parsed through all records and found something to send. The services/records might + // get registered at different times but we want the refreshes to be all merged and sent + // as one update. Hence, we accelerate some of the records so that they will sync up in + // the future. Look at the records excluding the ones that we have already sent in the + // previous pass. If it half way through its scheduled refresh/retransmit, merge them + // into this packet. + // + // Note that we only look at Registered/Refresh state to keep it simple. As we don't know + // whether the current update will fit into one or more packets, merging a resource record + // (which is in a different state) that has been scheduled for retransmit would trigger + // sending more packets. + if (firstRR) + { + int acc = 0; + for (rr = m->ResourceRecords; rr; rr = rr->next) + { + if ((rr->state != regState_Registered && rr->state != regState_Refresh) || + (rr->SendRNow == mDNSInterfaceMark) || + (!AreRecordsMergeable(m, firstRR, rr, m->timenow + rr->ThisAPInterval/2))) + continue; + rr->SendRNow = mDNSInterfaceMark; + acc++; + } + if (acc) LogInfo("MarkRRForSending: Accelereated %d records", acc); + } + return firstRR; + } + +mDNSlocal mDNSBool SendGroupUpdates(mDNS *const m) + { + mDNSOpaque16 msgid; + mDNSs32 spaceleft = 0; + mDNSs32 zoneSize, rrSize; + mDNSu8 *oldnext; // for debugging + mDNSu8 *next = m->omsg.data; + AuthRecord *rr; + AuthRecord *anchorRR = mDNSNULL; + int nrecords = 0; + AuthRecord *startRR = m->ResourceRecords; + mDNSu8 *limit = mDNSNULL; + DomainAuthInfo *AuthInfo = mDNSNULL; + mDNSBool sentallRecords = mDNStrue; + + + // We try to fit as many ResourceRecords as possible in AbsoluteNormal/MaxDNSMessageData. Before we start + // putting in resource records, we need to reserve space for a few things. Every group/packet should + // have the following. + // + // 1) Needs space for the Zone information (which needs to be at the beginning) + // 2) Additional section MUST have space for lease option, HINFO and TSIG option (which needs to + // to be at the end) + // + // In future we need to reserve space for the pre-requisites which also goes at the beginning. + // To accomodate pre-requisites in the future, first we walk the whole list marking records + // that can be sent in this packet and computing the space needed for these records. + // For TXT and SRV records, we delete the previous record if any by sending the same + // resource record with ANY RDATA and zero rdlen. Hence, we need to have space for both of them. + + while (startRR) + { + AuthInfo = mDNSNULL; + anchorRR = mDNSNULL; + nrecords = 0; + zoneSize = 0; + for (rr = startRR; rr; rr = rr->next) { - if (srs->state == regState_Registered && !err) + if (rr->SendRNow != mDNSInterfaceMark) continue; + + rr->SendRNow = mDNSNULL; + + if (!anchorRR) { - // extra resource record queued for this service - copy zone srs and register - (*e)->r.zone = &srs->zone; - (*e)->r.UpdateServer = srs->SRSUpdateServer; - (*e)->r.UpdatePort = srs->SRSUpdatePort; - (*e)->r.uselease = srs->srs_uselease; - SendRecordRegistration(m, &(*e)->r); - e = &(*e)->next; + AuthInfo = GetAuthInfoForName_internal(m, rr->zone); + + // Though we allow single record registrations for UDP to be AbsoluteMaxDNSMessageData (See + // SendRecordRegistration) to handle large TXT records, to avoid fragmentation we limit UDP + // message to NormalMaxDNSMessageData + if (AuthInfo && AuthInfo->AutoTunnel) spaceleft = AbsoluteMaxDNSMessageData; + else spaceleft = NormalMaxDNSMessageData; + + next = m->omsg.data; + spaceleft -= RRAdditionalSize(m, AuthInfo); + if (spaceleft <= 0) + { + LogMsg("SendGroupUpdates: ERROR!!: spaceleft is zero at the beginning"); + RRMergeFailure(m); + return mDNSfalse; + } + limit = next + spaceleft; + + // Build the initial part of message before putting in the other records + msgid = mDNS_NewMessageID(m); + InitializeDNSMessage(&m->omsg.h, msgid, UpdateReqFlags); + + // We need zone information at the beginning of the packet. Length: ZNAME, ZTYPE(2), ZCLASS(2) + // zone has to be non-NULL for a record to be mergeable, hence it is safe to set/ examine zone + //without checking for NULL. + zoneSize = DomainNameLength(rr->zone) + 4; + spaceleft -= zoneSize; + if (spaceleft <= 0) + { + LogMsg("SendGroupUpdates: ERROR no space for zone information, disabling merge"); + RRMergeFailure(m); + return mDNSfalse; + } + next = putZone(&m->omsg, next, limit, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); + if (!next) + { + LogMsg("SendGroupUpdates: ERROR! Cannot put zone, disabling merge"); + RRMergeFailure(m); + return mDNSfalse; + } + anchorRR = rr; + } + + rrSize = RREstimatedSize(rr, zoneSize - 4); + + if ((spaceleft - rrSize) < 0) + { + // If we can't fit even a single message, skip it, it will be sent separately + // in CheckRecordUpdates + if (!nrecords) + { + LogInfo("SendGroupUpdates: Skipping message %s, spaceleft %d, rrSize %d", ARDisplayString(m, rr), spaceleft, rrSize); + // Mark this as not sent so that the caller knows about it + rr->SendRNow = mDNSInterfaceMark; + // We need to remove the merge delay so that we can send it immediately + rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; + rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL; + rr = rr->next; + anchorRR = mDNSNULL; + sentallRecords = mDNSfalse; + } + else + { + LogInfo("SendGroupUpdates:1: Parsed %d records and sending using %s, spaceleft %d, rrSize %d", nrecords, ARDisplayString(m, anchorRR), spaceleft, rrSize); + SendGroupRRMessage(m, anchorRR, next, AuthInfo); + } + break; // breaks out of for loop } - else if (err && (*e)->r.state != regState_Unregistered) + spaceleft -= rrSize; + oldnext = next; + LogInfo("SendGroupUpdates: Building a message with resource record %s, next %p, state %d", ARDisplayString(m, rr), next, rr->state); + if (!(next = BuildUpdateMessage(m, next, rr, limit))) { - // unlink extra from list - (*e)->r.state = regState_Unregistered; - *e = (*e)->next; + // We calculated the space and if we can't fit in, we had some bug in the calculation, + // disable merge completely. + LogMsg("SendGroupUpdates: ptr NULL while building message with %s", ARDisplayString(m, rr)); + RRMergeFailure(m); + return mDNSfalse; } - else e = &(*e)->next; + // If our estimate was higher, adjust to the actual size + if ((next - oldnext) > rrSize) + LogMsg("SendGroupUpdates: ERROR!! Record size estimation is wrong for %s, Estimate %d, Actual %d, state %d", ARDisplayString(m, rr), rrSize, next - oldnext, rr->state); + else { spaceleft += rrSize; spaceleft -= (next - oldnext); } + + nrecords++; + // We could have sent an update earlier with this "rr" as anchorRR for which we never got a response. + // To preserve ordering, we blow away the previous connection before sending this. + if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL;} + rr->updateid = msgid; + + // By setting the retry time interval here, we will not be looking at these records + // again when we return to CheckGroupRecordUpdates. + SetRecordRetry(m, rr, 0); } - else e = &(*e)->next; + // Either we have parsed all the records or stopped at "rr" above due to lack of space + startRR = rr; } - if (srs->state == regState_Unregistered) + if (anchorRR) { - if (err != mStatus_MemFree) - LogMsg("hndlServiceUpdateReply ERROR! state == regState_Unregistered but err != mStatus_MemFree. Permanently abandoning service registration %##s", - srs->RR_SRV.resrec.name->c); - unlinkSRS(m, srs); + LogInfo("SendGroupUpdates: Parsed %d records and sending using %s", nrecords, ARDisplayString(m, anchorRR)); + SendGroupRRMessage(m, anchorRR, next, AuthInfo); } - else if (txt->QueuedRData && srs->state == regState_Registered) + return sentallRecords; + } + +// Merge the record registrations and send them as a group only if they +// have same DomainAuthInfo and hence the same key to put the TSIG +mDNSlocal void CheckGroupRecordUpdates(mDNS *const m) + { + AuthRecord *rr, *nextRR; + // Keep sending as long as there is at least one record to be sent + while (MarkRRForSending(m)) { - if (InvokeCallback) + if (!SendGroupUpdates(m)) { - // if we were supposed to give a client callback, we'll do it after we update the primary txt record - srs->ClientCallbackDeferred = mDNStrue; - srs->DeferredStatus = err; + // if everything that was marked was not sent, send them out individually + for (rr = m->ResourceRecords; rr; rr = nextRR) + { + // SendRecordRegistrtion might delete the rr from list, hence + // dereference nextRR before calling the function + nextRR = rr->next; + if (rr->SendRNow == mDNSInterfaceMark) + { + // Any records marked for sending should be eligible to be sent out + // immediately. Just being cautious + if (rr->LastAPTime + rr->ThisAPInterval - m->timenow > 0) + { LogMsg("CheckGroupRecordUpdates: ERROR!! Resourcerecord %s not ready", ARDisplayString(m, rr)); continue; } + rr->SendRNow = mDNSNULL; + SendRecordRegistration(m, rr); + } + } } - srs->state = regState_UpdatePending; - txt->InFlightRData = txt->QueuedRData; - txt->InFlightRDLen = txt->QueuedRDLen; - txt->OrigRData = txt->resrec.rdata; - txt->OrigRDLen = txt->resrec.rdlength; - txt->QueuedRData = mDNSNULL; - SendServiceRegistration(m, srs); - return; } + + debugf("CheckGroupRecordUpdates: No work, returning"); + return; + } - mDNS_DropLockBeforeCallback(); - if (InvokeCallback) - srs->ServiceCallback(m, srs, err); - else if (srs->ClientCallbackDeferred) +mDNSlocal void hndlSRVChanged(mDNS *const m, AuthRecord *rr) + { + // Reevaluate the target always as NAT/Target could have changed while + // we were registering/deeregistering + domainname *dt; + const domainname *target = GetServiceTarget(m, rr); + if (!target || target->c[0] == 0) + { + // we don't have a target, if we just derregistered, then we don't have to do anything + if (rr->state == regState_DeregPending) + { + LogInfo("hndlSRVChanged: SRVChanged, No Target, SRV Deregistered for %##s, state %d", rr->resrec.name->c, + rr->state); + rr->SRVChanged = mDNSfalse; + dt = GetRRDomainNameTarget(&rr->resrec); + if (dt) dt->c[0] = 0; + rr->state = regState_NoTarget; // Wait for the next target change + rr->resrec.rdlength = rr->resrec.rdestimate = 0; + return; + } + + // we don't have a target, if we just registered, we need to deregister + if (rr->state == regState_Pending) + { + LogInfo("hndlSRVChanged: SRVChanged, No Target, Deregistering again %##s, state %d", rr->resrec.name->c, rr->state); + rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; + rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL; + rr->state = regState_DeregPending; + return; + } + LogInfo("hndlSRVChanged: Not in DeregPending or RegPending state %##s, state %d", rr->resrec.name->c, rr->state); + } + else { - srs->ClientCallbackDeferred = mDNSfalse; - srs->ServiceCallback(m, srs, srs->DeferredStatus); + // If we were in registered state and SRV changed to NULL, we deregister and come back here + // if we have a target, we need to register again. + // + // if we just registered check to see if it is same. If it is different just re-register the + // SRV and its assoicated records + // + // UpdateOneSRVRecord takes care of re-registering all service records + if ((rr->state == regState_DeregPending) || + (rr->state == regState_Pending && !SameDomainName(target, &rr->resrec.rdata->u.srv.target))) + { + dt = GetRRDomainNameTarget(&rr->resrec); + if (dt) dt->c[0] = 0; + rr->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state + rr->resrec.rdlength = rr->resrec.rdestimate = 0; + LogInfo("hndlSRVChanged: SRVChanged, Valid Target %##s, Registering all records for %##s, state %d", + target->c, rr->resrec.name->c, rr->state); + rr->SRVChanged = mDNSfalse; + UpdateOneSRVRecord(m, rr); + return; + } + // Target did not change while this record was registering. Hence, we go to + // Registered state - the state we started from. + if (rr->state == regState_Pending) rr->state = regState_Registered; } - mDNS_ReclaimLockAfterCallback(); - // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function - // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. + + rr->SRVChanged = mDNSfalse; } // Called with lock held -mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err) +mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err, mDNSu32 random) { mDNSBool InvokeCallback = mDNStrue; + mDNSIPPort UpdatePort = zeroIPPort; if (m->mDNS_busy != m->mDNS_reentrancy+1) LogMsg("hndlRecordUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); - LogInfo("hndlRecordUpdateReply: err %d state %d %s", err, rr->state, ARDisplayString(m, rr)); + LogInfo("hndlRecordUpdateReply: err %d ID %d state %d %s(%p)", err, mDNSVal16(rr->updateid), rr->state, ARDisplayString(m, rr), rr); - if (m->SleepState) return; // If we just sent a deregister on going to sleep, no further action required + rr->updateError = err; +#if APPLE_OSX_mDNSResponder + if (err == mStatus_BadSig) UpdateAutoTunnelDomainStatuses(m); +#endif - SetRecordRetry(m, rr, mStatus_NoError); + SetRecordRetry(m, rr, random); + + rr->updateid = zeroID; // Make sure that this is not considered as part of a group anymore + // Later when need to send an update, we will get the zone data again. Thus we avoid + // using stale information. + // + // Note: By clearing out the zone info here, it also helps better merging of records + // in some cases. For example, when we get out regState_NoTarget state e.g., move out + // of Double NAT, we want all the records to be in one update. Some BTMM records like + // _autotunnel6 and host records are registered/deregistered when NAT state changes. + // As they are re-registered the zone information is cleared out. To merge with other + // records that might be possibly going out, clearing out the information here helps + // as all of them try to get the zone data. + if (rr->nta) + { + // We always expect the question to be stopped when we get a valid response from the server. + // If the zone info tries to change during this time, updateid would be different and hence + // this response should not have been accepted. + if (rr->nta->question.ThisQInterval != -1) + LogMsg("hndlRecordUpdateReply: ResourceRecord %s, zone info question %##s (%s) interval %d not -1", + ARDisplayString(m, rr), rr->nta->question.qname.c, DNSTypeName(rr->nta->question.qtype), rr->nta->question.ThisQInterval); + UpdatePort = rr->nta->Port; + CancelGetZoneData(m, rr->nta); + rr->nta = mDNSNULL; + } + + // If we are deregistering the record, then complete the deregistration. Ignore any NAT/SRV change + // that could have happened during that time. + if (rr->resrec.RecordType == kDNSRecordTypeDeregistering && rr->state == regState_DeregPending) + { + debugf("hndlRecordUpdateReply: Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype); + if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %d", + rr->resrec.name->c, rr->resrec.rrtype, err); + rr->state = regState_Unregistered; + CompleteDeregistration(m, rr); + return; + } + + // We are returning early without updating the state. When we come back from sleep we will re-register after + // re-initializing all the state as though it is a first registration. If the record can't be registered e.g., + // no target, it will be deregistered. Hence, the updating to the right state should not matter when going + // to sleep. + if (m->SleepState) + { + // Need to set it to NoTarget state so that RecordReadyForSleep knows that + // we are done + if (rr->resrec.rrtype == kDNSType_SRV && rr->state == regState_DeregPending) + rr->state = regState_NoTarget; + return; + } if (rr->state == regState_UpdatePending) { if (err) LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err); rr->state = regState_Registered; // deallocate old RData - if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->OrigRData); + if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->OrigRData, rr->OrigRDLen); SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen); rr->OrigRData = mDNSNULL; rr->InFlightRData = mDNSNULL; } - if (rr->state == regState_DeregPending) - { - debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype); - if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %d", - rr->resrec.name->c, rr->resrec.rrtype, err); - err = mStatus_MemFree; - rr->state = regState_Unregistered; - } - - if (rr->state == regState_DeregDeferred) + if (rr->SRVChanged) { - if (err) + if (rr->resrec.rrtype == kDNSType_SRV) + hndlSRVChanged(m, rr); + else { - LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %d", - rr->resrec.name->c, rr->resrec.rrtype, err); - rr->state = regState_Unregistered; + LogInfo("hndlRecordUpdateReply: Deregistered %##s (%s), state %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->state); + rr->SRVChanged = mDNSfalse; + if (rr->state != regState_DeregPending) LogMsg("hndlRecordUpdateReply: ResourceRecord %s not in DeregPending state %d", ARDisplayString(m, rr), rr->state); + rr->state = regState_NoTarget; // Wait for the next target change } - debugf("Calling deferred deregistration of record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype); - rr->state = regState_Registered; - mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); return; } - + if (rr->state == regState_Pending || rr->state == regState_Refresh) { if (!err) @@ -3916,24 +3159,20 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err) } else { - if (rr->uselease && err == mStatus_UnknownErr && mDNSSameIPPort(rr->UpdatePort, UnicastDNSPort)) + // Retry without lease only for non-Private domains + LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %d", rr->resrec.name->c, rr->resrec.rrtype, err); + if (!rr->Private && rr->uselease && err == mStatus_UnknownErr && mDNSSameIPPort(UpdatePort, UnicastDNSPort)) { - LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c); + LogMsg("hndlRecordUpdateReply: Will retry update of record %##s without lease option", rr->resrec.name->c); rr->uselease = mDNSfalse; - SendRecordRegistration(m, rr); + rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; + rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL; return; } - LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %d", rr->resrec.name->c, rr->resrec.rrtype, err); - return; + // Communicate the error to the application in the callback below } } - if (rr->state == regState_Unregistered) // Should never happen - { - LogMsg("hndlRecordUpdateReply rr->state == regState_Unregistered %s", ARDisplayString(m, rr)); - return; - } - if (rr->QueuedRData && rr->state == regState_Registered) { rr->state = regState_UpdatePending; @@ -3942,12 +3181,17 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err) rr->OrigRData = rr->resrec.rdata; rr->OrigRDLen = rr->resrec.rdlength; rr->QueuedRData = mDNSNULL; - SendRecordRegistration(m, rr); + rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; + rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL; return; } - if (InvokeCallback && rr->RecordCallback) + // Don't invoke the callback on error as this may not be useful to the client. + // The client may potentially delete the resource record on error which we normally + // delete during deregistration + if (!err && InvokeCallback && rr->RecordCallback) { + LogInfo("hndlRecordUpdateReply: Calling record callback on %##s", rr->resrec.name->c); mDNS_DropLockBeforeCallback(); rr->RecordCallback(m, rr, err); mDNS_ReclaimLockAfterCallback(); @@ -3977,11 +3221,14 @@ mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interfac // We compute a conservative estimate of how much the NAT gateways's clock should have advanced // 1. We subtract 12.5% from our own measured elapsed time, to allow for NAT gateways that have an inacurate clock that runs slowly - // 2. We add a two-second safety margin to allow for rounding errors: - // -- e.g. if NAT gateway sends a packet at t=2.00 seconds, then one at t=7.99, that's virtually 6 seconds, - // but based on the values in the packet (2,7) the apparent difference is only 5 seconds - // -- similarly, if we're slow handling packets and/or we have coarse clock granularity, we could over-estimate the true interval - // (e.g. t=1.99 seconds rounded to 1, and t=8.01 rounded to 8, gives an apparent difference of 7 seconds) + // 2. We add a two-second safety margin to allow for rounding errors: e.g. + // -- if NAT gateway sends a packet at t=2.000 seconds, then one at t=7.999, that's approximately 6 real seconds, + // but based on the values in the packet (2,7) the apparent difference according to the packet is only 5 seconds + // -- if we're slow handling packets and/or we have coarse clock granularity, + // we could receive the t=2 packet at our t=1.999 seconds, which we round down to 1 + // and the t=7.999 packet at our t=8.000 seconds, which we record as 8, + // giving an apparent local time difference of 7 seconds + // The two-second safety margin coves this possible calculation discrepancy if (AddrReply->upseconds < m->LastNATupseconds || nat_elapsed + 2 < our_elapsed - our_elapsed/8) { LogMsg("NAT gateway %#a rebooted", &m->Router); RecreateNATMappings(m); } @@ -4173,12 +3420,12 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS (void)srcport; // Unused debugf("uDNS_ReceiveMsg from %#-15a with " - "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s", + "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes", srcaddr, - msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", - msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", + msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", + msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,", - msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s"); + msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s", end - msg->data); if (QR_OP == StdR) { @@ -4188,17 +3435,14 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW) { if (!srcaddr) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring"); - else if (qptr->tcp) + else { - // There may be a race condition here, if the server decides to drop the connection just as we decide to reuse it - // For now it should not be serious because our normal retry logic (as used to handle UDP packet loss) - // should take care of it but later we may want to look at handling this case explicitly - LogInfo("uDNS_ReceiveMsg: Using existing TCP connection for %##s (%s)", qptr->qname.c, DNSTypeName(qptr->qtype)); - mDNS_DropLockBeforeCallback(); - tcpCallback(qptr->tcp->sock, qptr->tcp, mDNStrue, mStatus_NoError); - mDNS_ReclaimLockAfterCallback(); + // Don't reuse TCP connections. We might have failed over to a different DNS server + // while the first TCP connection is in progress. We need a new TCP connection to the + // new DNS server. So, always try to establish a new connection. + if (qptr->tcp) { DisposeTCPConn(qptr->tcp); qptr->tcp = mDNSNULL; } + qptr->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, mDNSNULL, qptr, mDNSNULL); } - else qptr->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, qptr, mDNSNULL, mDNSNULL); } } @@ -4206,30 +3450,12 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS { mDNSu32 lease = GetPktLease(m, msg, end); mDNSs32 expire = m->timenow + (mDNSs32)lease * mDNSPlatformOneSecond; + mDNSu32 random = mDNSRandom((mDNSs32)lease * mDNSPlatformOneSecond/10); //rcode = kDNSFlag1_RC_ServFail; // Simulate server failure (rcode 2) - if (CurrentServiceRecordSet) - LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set"); - CurrentServiceRecordSet = m->ServiceRegistrations; - - while (CurrentServiceRecordSet) - { - ServiceRecordSet *sptr = CurrentServiceRecordSet; - CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next; - - if (mDNSSameOpaque16(sptr->id, msg->h.id)) - { - err = checkUpdateResult(m, sptr->RR_SRV.resrec.name, rcode, msg, end); - if (!err && sptr->srs_uselease && lease) - if (sptr->RR_SRV.expire - expire >= 0 || sptr->state != regState_UpdatePending) - sptr->RR_SRV.expire = expire; - hndlServiceUpdateReply(m, sptr, err); - CurrentServiceRecordSet = mDNSNULL; - return; - } - } - + // Walk through all the records that matches the messageID. There could be multiple + // records if we had sent them in a group if (m->CurrentRecord) LogMsg("uDNS_ReceiveMsg ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); m->CurrentRecord = m->ResourceRecords; @@ -4242,10 +3468,13 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS err = checkUpdateResult(m, rptr->resrec.name, rcode, msg, end); if (!err && rptr->uselease && lease) if (rptr->expire - expire >= 0 || rptr->state != regState_UpdatePending) + { rptr->expire = expire; - hndlRecordUpdateReply(m, rptr, err); - m->CurrentRecord = mDNSNULL; - return; + rptr->refreshCount = 0; + } + // We pass the random value to make sure that if we update multiple + // records, they all get the same random value + hndlRecordUpdateReply(m, rptr, err, random); } } } @@ -4261,6 +3490,7 @@ mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q) { mDNSu8 *end; LLQOptData llq; + mDNSu8 *limit = m->omsg.data + AbsoluteMaxDNSMessageData; if (q->ReqLease) if ((q->state == LLQ_Established && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0) @@ -4282,23 +3512,31 @@ mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q) // Note that we (conditionally) add HINFO and TSIG here, since the question might be going away, // so we may not be able to reference it (most importantly it's AuthInfo) when we actually send the message - end = putHINFO(m, &m->omsg, end, q->AuthInfo); + end = putHINFO(m, &m->omsg, end, q->AuthInfo, limit); if (!end) { LogMsg("sendLLQRefresh: putHINFO failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; } - if (q->AuthInfo) + if (PrivateQuery(q)) { DNSDigest_SignMessageHostByteOrder(&m->omsg, &end, q->AuthInfo); if (!end) { LogMsg("sendLLQRefresh: DNSDigest_SignMessage failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; } } - if (q->AuthInfo && !q->tcp) + if (PrivateQuery(q) && !q->tcp) { LogInfo("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); - q->tcp = MakeTCPConn(m, &m->omsg, end, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL); + if (!q->nta) { LogMsg("sendLLQRefresh:ERROR!! q->nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; } + q->tcp = MakeTCPConn(m, &m->omsg, end, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, &q->nta->Host, q, mDNSNULL); } else { - mStatus err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, mDNSNULL); + mStatus err; + + // if AuthInfo and AuthInfo->AutoTunnel is set, we use the TCP socket but don't need to pass the AuthInfo as + // we already protected the message above. + LogInfo("sendLLQRefresh: using existing %s session %##s (%s)", PrivateQuery(q) ? "TLS" : "UDP", + q->qname.c, DNSTypeName(q->qtype)); + + err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, mDNSNULL); if (err) { LogMsg("sendLLQRefresh: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err); @@ -4320,24 +3558,39 @@ mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneI mDNS_Lock(m); - // If we get here it means that the GetZoneData operation has completed, and is is about to cancel - // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which - // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes). - q->nta = mDNSNULL; + // If we get here it means that the GetZoneData operation has completed. + // We hold on to the zone data if it is AutoTunnel as we use the hostname + // in zoneInfo during the TLS connection setup. q->servAddr = zeroAddr; q->servPort = zeroIPPort; - if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr)) + if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr) && zoneInfo->Host.c[0]) { q->servAddr = zoneInfo->Addr; q->servPort = zoneInfo->Port; - q->AuthInfo = zoneInfo->ZonePrivate ? GetAuthInfoForName_internal(m, &q->qname) : mDNSNULL; + if (!PrivateQuery(q)) + { + // We don't need the zone data as we use it only for the Host information which we + // don't need if we are not going to use TLS connections. + if (q->nta) + { + if (q->nta != zoneInfo) LogMsg("LLQGotZoneData: nta (%p) != zoneInfo (%p) %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype)); + CancelGetZoneData(m, q->nta); + q->nta = mDNSNULL; + } + } q->ntries = 0; debugf("LLQGotZoneData %#a:%d", &q->servAddr, mDNSVal16(q->servPort)); startLLQHandshake(m, q); } else { + if (q->nta) + { + if (q->nta != zoneInfo) LogMsg("LLQGotZoneData: nta (%p) != zoneInfo (%p) %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype)); + CancelGetZoneData(m, q->nta); + q->nta = mDNSNULL; + } StartLLQPolling(m,q); if (err == mStatus_NoSuchNameErr) { @@ -4357,17 +3610,16 @@ mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneDat LogInfo("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q->qname.c, DNSTypeName(q->qtype), err, zoneInfo->ZoneName.c, zoneInfo->ZonePrivate); - // If we get here it means that the GetZoneData operation has completed, and is is about to cancel - // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which - // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes). - q->nta = mDNSNULL; + if (q->nta != zoneInfo) LogMsg("PrivateQueryGotZoneData:ERROR!!: nta (%p) != zoneInfo (%p) %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype)); - if (err || !zoneInfo || mDNSAddressIsZero(&zoneInfo->Addr) || mDNSIPPortIsZero(zoneInfo->Port)) + if (err || !zoneInfo || mDNSAddressIsZero(&zoneInfo->Addr) || mDNSIPPortIsZero(zoneInfo->Port) || !zoneInfo->Host.c[0]) { - LogInfo("ERROR: PrivateQueryGotZoneData %##s (%s) invoked with error code %d %p %#a:%d", + LogInfo("PrivateQueryGotZoneData: ERROR!! %##s (%s) invoked with error code %d %p %#a:%d", q->qname.c, DNSTypeName(q->qtype), err, zoneInfo, zoneInfo ? &zoneInfo->Addr : mDNSNULL, zoneInfo ? mDNSVal16(zoneInfo->Port) : 0); + CancelGetZoneData(m, q->nta); + q->nta = mDNSNULL; return; } @@ -4377,6 +3629,8 @@ mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneDat q->AuthInfo = mDNSNULL; // Clear AuthInfo so we try again non-private q->ThisQInterval = InitialQuestionInterval; q->LastQTime = m->timenow - q->ThisQInterval; + CancelGetZoneData(m, q->nta); + q->nta = mDNSNULL; mDNS_Lock(m); SetNextQueryTime(m, q); mDNS_Unlock(m); @@ -4384,15 +3638,19 @@ mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneDat // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query } - if (!q->AuthInfo) + if (!PrivateQuery(q)) { - LogMsg("ERROR: PrivateQueryGotZoneData: cannot find credentials for q %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + LogMsg("PrivateQueryGotZoneData: ERROR!! Not a private query %##s (%s) AuthInfo %p", q->qname.c, DNSTypeName(q->qtype), q->AuthInfo); + CancelGetZoneData(m, q->nta); + q->nta = mDNSNULL; return; } q->TargetQID = mDNS_NewMessageID(m); - if (q->tcp) DisposeTCPConn(q->tcp); - q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &zoneInfo->Addr, zoneInfo->Port, q, mDNSNULL, mDNSNULL); + if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; } + if (!q->nta) { LogMsg("PrivateQueryGotZoneData:ERROR!! nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; } + q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &zoneInfo->Addr, zoneInfo->Port, &q->nta->Host, q, mDNSNULL); + if (q->nta) { CancelGetZoneData(m, q->nta); q->nta = mDNSNULL; } } // *************************************************************************** @@ -4407,23 +3665,28 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const AuthRecord *ptr; int c1, c2; + if (newRR->nta != zoneData) + LogMsg("RecordRegistrationGotZoneData: nta (%p) != zoneData (%p) %##s (%s)", newRR->nta, zoneData, newRR->resrec.name->c, DNSTypeName(newRR->resrec.rrtype)); + if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("RecordRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); - newRR->nta = mDNSNULL; - - // Start off assuming we're going to use a lease - // If we get an error from the server, and the update port as given in the SRV record is 53, then we'll retry without the lease option - newRR->uselease = mDNStrue; - // make sure record is still in list (!!!) for (ptr = m->ResourceRecords; ptr; ptr = ptr->next) if (ptr == newRR) break; - if (!ptr) { LogMsg("RecordRegistrationGotZoneData - RR no longer in list. Discarding."); return; } + if (!ptr) + { + LogMsg("RecordRegistrationGotZoneData - RR no longer in list. Discarding."); + CancelGetZoneData(m, newRR->nta); + newRR->nta = mDNSNULL; + return; + } // check error/result if (err) { if (err != mStatus_NoSuchNameErr) LogMsg("RecordRegistrationGotZoneData: error %d", err); + CancelGetZoneData(m, newRR->nta); + newRR->nta = mDNSNULL; return; } @@ -4432,6 +3695,8 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const if (newRR->resrec.rrclass != zoneData->ZoneClass) { LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)", newRR->resrec.rrclass, zoneData->ZoneClass); + CancelGetZoneData(m, newRR->nta); + newRR->nta = mDNSNULL; return; } @@ -4441,6 +3706,8 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const if (zoneData->ZoneName.c[0] == 0) { LogInfo("RecordRegistrationGotZoneData: No name server found claiming responsibility for \"%##s\"!", newRR->resrec.name->c); + CancelGetZoneData(m, newRR->nta); + newRR->nta = mDNSNULL; return; } @@ -4450,188 +3717,267 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const if (c2 > c1) { LogMsg("RecordRegistrationGotZoneData: Zone \"%##s\" is longer than \"%##s\"", zoneData->ZoneName.c, newRR->resrec.name->c); + CancelGetZoneData(m, newRR->nta); + newRR->nta = mDNSNULL; return; } newRR->zone = SkipLeadingLabels(newRR->resrec.name, c1-c2); if (!SameDomainName(newRR->zone, &zoneData->ZoneName)) { LogMsg("RecordRegistrationGotZoneData: Zone \"%##s\" does not match \"%##s\" for \"%##s\"", newRR->zone->c, zoneData->ZoneName.c, newRR->resrec.name->c); + CancelGetZoneData(m, newRR->nta); + newRR->nta = mDNSNULL; return; } - newRR->UpdateServer = zoneData->Addr; - newRR->UpdatePort = zoneData->Port; - newRR->Private = zoneData->ZonePrivate; - debugf("RecordRegistrationGotZoneData: Set newRR->UpdateServer %##s %##s to %#a:%d", - newRR->resrec.name->c, zoneData->ZoneName.c, &newRR->UpdateServer, mDNSVal16(newRR->UpdatePort)); - if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr)) + if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr) || !zoneData->Host.c[0]) { LogInfo("RecordRegistrationGotZoneData: No _dns-update._udp service found for \"%##s\"!", newRR->resrec.name->c); + CancelGetZoneData(m, newRR->nta); + newRR->nta = mDNSNULL; return; } - newRR->ThisAPInterval = 5 * mDNSPlatformOneSecond; // After doubling, first retry will happen after ten seconds + newRR->Private = zoneData->ZonePrivate; + debugf("RecordRegistrationGotZoneData: Set zone information for %##s %##s to %#a:%d", + newRR->resrec.name->c, zoneData->ZoneName.c, &zoneData->Addr, mDNSVal16(zoneData->Port)); - mDNS_Lock(m); // SendRecordRegistration expects to be called with the lock held - SendRecordRegistration(m, newRR); + // If we are deregistering, uDNS_DeregisterRecord will do that as it has the zone data now. + if (newRR->state == regState_DeregPending) + { + mDNS_Lock(m); + uDNS_DeregisterRecord(m, newRR); + mDNS_Unlock(m); + return; + } + + if (newRR->resrec.rrtype == kDNSType_SRV) + { + const domainname *target; + // Reevaluate the target always as NAT/Target could have changed while + // we were fetching zone data. + mDNS_Lock(m); + target = GetServiceTarget(m, newRR); + mDNS_Unlock(m); + if (!target || target->c[0] == 0) + { + domainname *t = GetRRDomainNameTarget(&newRR->resrec); + LogInfo("RecordRegistrationGotZoneData - no target for %##s", newRR->resrec.name->c); + if (t) t->c[0] = 0; + newRR->resrec.rdlength = newRR->resrec.rdestimate = 0; + newRR->state = regState_NoTarget; + CancelGetZoneData(m, newRR->nta); + newRR->nta = mDNSNULL; + return; + } + } + // If we have non-zero service port (always?) + // and a private address, and update server is non-private + // and this service is AutoTarget + // then initiate a NAT mapping request. On completion it will do SendRecordRegistration() for us + if (newRR->resrec.rrtype == kDNSType_SRV && !mDNSIPPortIsZero(newRR->resrec.rdata->u.srv.port) && + mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && newRR->nta && !mDNSAddrIsRFC1918(&newRR->nta->Addr) && + newRR->AutoTarget == Target_AutoHostAndNATMAP) + { + DomainAuthInfo *AuthInfo; + AuthInfo = GetAuthInfoForName(m, newRR->resrec.name); + if (AuthInfo && AuthInfo->AutoTunnel) + { + domainname *t = GetRRDomainNameTarget(&newRR->resrec); + LogMsg("RecordRegistrationGotZoneData: ERROR!! AutoTunnel has Target_AutoHostAndNATMAP for %s", ARDisplayString(m, newRR)); + if (t) t->c[0] = 0; + newRR->resrec.rdlength = newRR->resrec.rdestimate = 0; + newRR->state = regState_NoTarget; + CancelGetZoneData(m, newRR->nta); + newRR->nta = mDNSNULL; + return; + } + // During network transitions, we are called multiple times in different states. Setup NAT + // state just once for this record. + if (!newRR->NATinfo.clientContext) + { + LogInfo("RecordRegistrationGotZoneData StartRecordNatMap %s", ARDisplayString(m, newRR)); + newRR->state = regState_NATMap; + StartRecordNatMap(m, newRR); + return; + } + else LogInfo("RecordRegistrationGotZoneData: StartRecordNatMap for %s, state %d, context %p", ARDisplayString(m, newRR), newRR->state, newRR->NATinfo.clientContext); + } + mDNS_Lock(m); + // We want IsRecordMergeable to check whether it is a record whose update can be + // sent with others. We set the time before we call IsRecordMergeable, so that + // it does not fail this record based on time. We are interested in other checks + // at this time. If a previous update resulted in error, then don't reset the + // interval. Preserve the back-off so that we don't keep retrying aggressively. + if (newRR->updateError == mStatus_NoError) + { + newRR->ThisAPInterval = INIT_RECORD_REG_INTERVAL; + newRR->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL; + } + if (IsRecordMergeable(m, newRR, m->timenow + MERGE_DELAY_TIME)) + { + // Delay the record registration by MERGE_DELAY_TIME so that we can merge them + // into one update + LogInfo("RecordRegistrationGotZoneData: Delayed registration for %s", ARDisplayString(m, newRR)); + newRR->LastAPTime += MERGE_DELAY_TIME; + } mDNS_Unlock(m); } mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr) { mDNSu8 *ptr = m->omsg.data; - mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage); + mDNSu8 *limit; + DomainAuthInfo *AuthInfo; - if (mDNSIPv4AddressIsZero(rr->UpdateServer.ip.v4)) // Don't know our UpdateServer yet + if (m->mDNS_busy != m->mDNS_reentrancy+1) + LogMsg("SendRecordDeRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + + if (!rr->nta || mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4)) { - rr->LastAPTime = m->timenow; - if (rr->ThisAPInterval < mDNSPlatformOneSecond * 5) - rr->ThisAPInterval = mDNSPlatformOneSecond * 5; + LogMsg("SendRecordDeRegistration: No zone info for Resource record %s RecordType %d", ARDisplayString(m, rr), rr->resrec.RecordType); return; } + limit = ptr + AbsoluteMaxDNSMessageData; + AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name); + limit -= RRAdditionalSize(m, AuthInfo); + + rr->updateid = mDNS_NewMessageID(m); InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags); - ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); - if (ptr) ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec); - if (!ptr) + // set zone + ptr = putZone(&m->omsg, ptr, limit, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); + if (!ptr) goto exit; + + ptr = BuildUpdateMessage(m, ptr, rr, limit); + + if (!ptr) goto exit; + + if (rr->Private) { - LogMsg("SendRecordDeregistration Error: could not contruct deregistration packet for %s", ARDisplayString(m, rr)); - if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); + LogInfo("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr)); + if (rr->tcp) LogInfo("SendRecordDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr)); + if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } + if (!rr->nta) { LogMsg("SendRecordDeregistration:Private:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; } + rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->nta->Addr, rr->nta->Port, &rr->nta->Host, mDNSNULL, rr); } else { - rr->expire = 0; // Indicate that we have no active registration any more - if (rr->Private) - { - LogInfo("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr)); - if (rr->tcp) LogInfo("SendRecordDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr)); - if (rr->tcp) DisposeTCPConn(rr->tcp); - rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr); - if (!rr->tcp) rr->ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2) - else if (rr->ThisAPInterval < mDNSPlatformOneSecond * 30) rr->ThisAPInterval = mDNSPlatformOneSecond * 30; - SetRecordRetry(m, rr, mStatus_NoError); - } - else - { - mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name)); - if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err); - if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); // Don't touch rr after this - } + mStatus err; + LogInfo("SendRecordDeregistration UDP %s", ARDisplayString(m, rr)); + if (!rr->nta) { LogMsg("SendRecordDeregistration:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; } + err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->nta->Addr, rr->nta->Port, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name)); + if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err); + //if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); // Don't touch rr after this } + SetRecordRetry(m, rr, 0); + return; +exit: + LogMsg("SendRecordDeregistration: Error formatting message for %s", ARDisplayString(m, rr)); } mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr) { + DomainAuthInfo *info; + + LogInfo("uDNS_DeregisterRecord: Resource Record %s, state %d", ARDisplayString(m, rr), rr->state); + switch (rr->state) { - case regState_NATMap: LogMsg("regState_NATMap %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError; - case regState_ExtraQueued: rr->state = regState_Unregistered; break; case regState_Refresh: case regState_Pending: case regState_UpdatePending: - case regState_FetchingZoneData: case regState_Registered: break; case regState_DeregPending: break; - case regState_DeregDeferred: LogMsg("regState_DeregDeferred %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError; - case regState_Unregistered: LogMsg("regState_Unregistered %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError; - case regState_NATError: LogMsg("regState_NATError %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError; - case regState_NoTarget: LogMsg("regState_NoTarget %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError; - default: LogMsg("uDNS_DeregisterRecord: State %d for %##s type %s", rr->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError; - } - - if (rr->state != regState_Unregistered) { rr->state = regState_DeregPending; SendRecordDeregistration(m, rr); } - return mStatus_NoError; - } - -// Called with lock held -mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs) - { - char *errmsg = "Unknown State"; - - if (m->mDNS_busy != m->mDNS_reentrancy+1) - LogMsg("uDNS_DeregisterService: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); - // don't re-register with a new target following deregistration - srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse; - - if (srs->srs_nta) { CancelGetZoneData(m, srs->srs_nta); srs->srs_nta = mDNSNULL; } + case regState_NATError: + case regState_NATMap: + // A record could be in NoTarget to start with if the corresponding SRV record could not find a target. + // It is also possible to reenter the NoTarget state when we move to a network with a NAT that has + // no NAT-PMP/UPnP support. In that case before we entered NoTarget, we already deregistered with + // the server. + case regState_NoTarget: + case regState_Unregistered: + case regState_Zero: + default: + LogInfo("uDNS_DeregisterRecord: State %d for %##s type %s", rr->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + // This function may be called during sleep when there are no sleep proxy servers + if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) CompleteDeregistration(m, rr); + return mStatus_NoError; + } - if (srs->NATinfo.clientContext) - { - mDNS_StopNATOperation_internal(m, &srs->NATinfo); - srs->NATinfo.clientContext = mDNSNULL; + // If a current group registration is pending, we can't send this deregisration till that registration + // has reached the server i.e., the ordering is important. Previously, if we did not send this + // registration in a group, then the previous connection will be torn down as part of sending the + // deregistration. If we send this in a group, we need to locate the resource record that was used + // to send this registration and terminate that connection. This means all the updates on that might + // be lost (assuming the response is not waiting for us at the socket) and the retry will send the + // update again sometime in the near future. + // + // NOTE: SSL handshake failures normally free the TCP connection immediately. Hence, you may not + // find the TCP below there. This case can happen only when tcp is trying to actively retransmit + // the request or SSL negotiation taking time i.e resource record is actively trying to get the + // message to the server. During that time a deregister has to happen. + + if (!mDNSOpaque16IsZero(rr->updateid)) + { + AuthRecord *anchorRR; + mDNSBool found = mDNSfalse; + for (anchorRR = m->ResourceRecords; anchorRR; anchorRR = anchorRR->next) + { + if (AuthRecord_uDNS(rr) && mDNSSameOpaque16(anchorRR->updateid, rr->updateid) && anchorRR->tcp) + { + LogInfo("uDNS_DeregisterRecord: Found Anchor RR %s terminated", ARDisplayString(m, anchorRR)); + if (found) + LogMsg("uDNS_DeregisterRecord: ERROR: Another anchorRR %s found", ARDisplayString(m, anchorRR)); + DisposeTCPConn(anchorRR->tcp); + anchorRR->tcp = mDNSNULL; + found = mDNStrue; + } + } + if (!found) LogInfo("uDNSDeregisterRecord: Cannot find the anchor Resource Record for %s, not an error", ARDisplayString(m, rr)); } - switch (srs->state) + // Retry logic for deregistration should be no different from sending registration the first time. + // Currently ThisAPInterval most likely is set to the refresh interval + rr->state = regState_DeregPending; + rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; + rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL; + info = GetAuthInfoForName_internal(m, rr->resrec.name); + if (IsRecordMergeable(m, rr, m->timenow + MERGE_DELAY_TIME)) { - case regState_Unregistered: - debugf("uDNS_DeregisterService - service %##s not registered", srs->RR_SRV.resrec.name->c); - return mStatus_BadReferenceErr; - case regState_DeregPending: - case regState_DeregDeferred: - debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name->c); - return mStatus_NoError; - case regState_NATError: // not registered - case regState_NATMap: // not registered - case regState_NoTarget: // not registered - unlinkSRS(m, srs); - srs->state = regState_Unregistered; - mDNS_DropLockBeforeCallback(); - srs->ServiceCallback(m, srs, mStatus_MemFree); - mDNS_ReclaimLockAfterCallback(); - return mStatus_NoError; - case regState_Pending: - case regState_Refresh: - case regState_UpdatePending: - case regState_FetchingZoneData: - case regState_Registered: - srs->state = regState_DeregPending; - SendServiceDeregistration(m, srs); - return mStatus_NoError; - case regState_ExtraQueued: // only for record registrations - errmsg = "bad state (regState_ExtraQueued)"; - goto error; - default: LogMsg("uDNS_DeregisterService: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c); + // Delay the record deregistration by MERGE_DELAY_TIME so that we can merge them + // into one update. If the domain is being deleted, delay by 2 * MERGE_DELAY_TIME + // so that we can merge all the AutoTunnel records and the service records in + // one update (they get deregistered a little apart) + if (info && info->deltime) rr->LastAPTime += (2 * MERGE_DELAY_TIME); + else rr->LastAPTime += MERGE_DELAY_TIME; } + // IsRecordMergeable could have returned false for several reasons e.g., DontMerge is set or + // no zone information. Most likely it is the latter, CheckRecordUpdates will fetch the zone + // data when it encounters this record. + + if (m->NextuDNSEvent - (rr->LastAPTime + rr->ThisAPInterval) >= 0) + m->NextuDNSEvent = (rr->LastAPTime + rr->ThisAPInterval); - error: - LogMsg("Error, uDNS_DeregisterService: %s", errmsg); - return mStatus_BadReferenceErr; + return mStatus_NoError; } mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr) { - ServiceRecordSet *parent = mDNSNULL; - AuthRecord *rptr; - regState_t *stateptr = mDNSNULL; - - // find the record in registered service list - for (parent = m->ServiceRegistrations; parent; parent = parent->uDNS_next) - if (&parent->RR_TXT == rr) { stateptr = &parent->state; break; } - - if (!parent) - { - // record not part of a service - check individual record registrations - for (rptr = m->ResourceRecords; rptr; rptr = rptr->next) - if (rptr == rr) { stateptr = &rr->state; break; } - if (!rptr) goto unreg_error; - } - - switch(*stateptr) + LogInfo("uDNS_UpdateRecord: Resource Record %##s, state %d", rr->resrec.name->c, rr->state); + switch(rr->state) { case regState_DeregPending: - case regState_DeregDeferred: case regState_Unregistered: // not actively registered goto unreg_error; - case regState_FetchingZoneData: case regState_NATMap: - case regState_ExtraQueued: case regState_NoTarget: // change rdata directly since it hasn't been sent yet - if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->resrec.rdata); + if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->resrec.rdata, rr->resrec.rdlength); SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); rr->NewRData = mDNSNULL; return mStatus_NoError; @@ -4642,7 +3988,7 @@ mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr) // registration in-flight. queue rdata and return if (rr->QueuedRData && rr->UpdateCallback) // if unsent rdata is already queued, free it before we replace it - rr->UpdateCallback(m, rr, rr->QueuedRData); + rr->UpdateCallback(m, rr, rr->QueuedRData, rr->QueuedRDLen); rr->QueuedRData = rr->NewRData; rr->QueuedRDLen = rr->newrdlength; rr->NewRData = mDNSNULL; @@ -4654,21 +4000,21 @@ mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr) rr->InFlightRData = rr->NewRData; rr->InFlightRDLen = rr->newrdlength; rr->NewRData = mDNSNULL; - *stateptr = regState_UpdatePending; - if (parent) SendServiceRegistration(m, parent); - else SendRecordRegistration(m, rr); + rr->state = regState_UpdatePending; + rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; + rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL; return mStatus_NoError; case regState_NATError: LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr->resrec.name->c); return mStatus_UnknownErr; // states for service records only - default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", *stateptr, rr->resrec.name->c); + default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", rr->state, rr->resrec.name->c); } unreg_error: - LogMsg("Requested update of record %##s type %d, part of service not currently registered", - rr->resrec.name->c, rr->resrec.rrtype); + LogMsg("uDNS_UpdateRecord: Requested update of record %##s type %d, in erroneous state %d", + rr->resrec.name->c, rr->resrec.rrtype, rr->state); return mStatus_Invalid; } @@ -4677,23 +4023,76 @@ mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr) #pragma mark - Periodic Execution Routines #endif +mDNSlocal const mDNSu8 *mDNS_WABLabels[] = + { + (const mDNSu8 *)"\001b", + (const mDNSu8 *)"\002db", + (const mDNSu8 *)"\002lb", + (const mDNSu8 *)"\001r", + (const mDNSu8 *)"\002dr", + (const mDNSu8 *)"\002cf", + (const mDNSu8 *)mDNSNULL, + }; + +// Returns true if it is a WAB question +mDNSlocal mDNSBool WABQuestion(const domainname *qname) + { + const mDNSu8 *sd = (const mDNSu8 *)"\007_dns-sd"; + const mDNSu8 *prot = (const mDNSu8 *)"\004_udp"; + const domainname *d = qname; + const mDNSu8 *label; + int i = 0; + + // We need at least 3 labels (WAB prefix) + one more label to make + // a meaningful WAB query + if (CountLabels(qname) < 4) { debugf("WABQuestion: question %##s, not enough labels", qname->c); return mDNSfalse; } + + label = (const mDNSu8 *)d; + while (mDNS_WABLabels[i] != (const mDNSu8 *)mDNSNULL) + { + if (SameDomainLabel(mDNS_WABLabels[i], label)) {debugf("WABquestion: WAB question %##s, label1 match", qname->c); break;} + i++; + } + if (mDNS_WABLabels[i] == (const mDNSu8 *)mDNSNULL) + { + debugf("WABquestion: Not a WAB question %##s, label1 mismatch", qname->c); + return mDNSfalse; + } + // CountLabels already verified the number of labels + d = (const domainname *)(d->c + 1 + d->c[0]); // Second Label + label = (const mDNSu8 *)d; + if (!SameDomainLabel(label, sd)){ debugf("WABquestion: Not a WAB question %##s, label2 mismatch", qname->c);return(mDNSfalse); } + debugf("WABquestion: WAB question %##s, label2 match", qname->c); + + d = (const domainname *)(d->c + 1 + d->c[0]); // Third Label + label = (const mDNSu8 *)d; + if (!SameDomainLabel(label, prot)){ debugf("WABquestion: Not a WAB question %##s, label3 mismatch", qname->c);return(mDNSfalse); } + debugf("WABquestion: WAB question %##s, label3 match", qname->c); + + LogInfo("WABquestion: Question %##s is a WAB question", qname->c); + + return mDNStrue; + } + // The question to be checked is not passed in as an explicit parameter; // instead it is implicit that the question to be checked is m->CurrentQuestion. mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) { DNSQuestion *q = m->CurrentQuestion; - mDNSs32 sendtime = q->LastQTime + q->ThisQInterval; - // Don't allow sendtime to be earlier than SuppressStdPort53Queries - if (!q->LongLived && m->SuppressStdPort53Queries && sendtime - m->SuppressStdPort53Queries < 0) - sendtime = m->SuppressStdPort53Queries; - if (m->timenow - sendtime < 0) return; + if (m->timenow - NextQSendTime(q) < 0) return; if (q->LongLived) { switch (q->state) { case LLQ_InitialRequest: startLLQHandshake(m, q); break; - case LLQ_SecondaryRequest: sendChallengeResponse(m, q, mDNSNULL); break; + case LLQ_SecondaryRequest: + // For PrivateQueries, we need to start the handshake again as we don't do the Challenge/Response step + if (PrivateQuery(q)) + startLLQHandshake(m, q); + else + sendChallengeResponse(m, q, mDNSNULL); + break; case LLQ_Established: sendLLQRefresh(m, q); break; case LLQ_Poll: break; // Do nothing (handled below) } @@ -4705,12 +4104,44 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) if (q->unansweredQueries >= MAX_UCAST_UNANSWERED_QUERIES) { DNSServer *orig = q->qDNSServer; - if (orig) LogInfo("Sent %d unanswered queries for %##s (%s) to %#a:%d (%##s)", q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype), &orig->addr, mDNSVal16(orig->port), orig->domain.c); + if (orig) + LogInfo("uDNS_CheckCurrentQuestion: Sent %d unanswered queries for %##s (%s) to %#a:%d (%##s)", + q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype), &orig->addr, mDNSVal16(orig->port), orig->domain.c); - PushDNSServerToEnd(m, q); - q->unansweredQueries = 0; + PenalizeDNSServer(m, q); + q->noServerResponse = 1; + } + // There are two cases here. + // + // 1. We have only one DNS server for this question. It is not responding even after we sent MAX_UCAST_UNANSWERED_QUERIES. + // In that case, we need to keep retrying till we get a response. But we need to backoff as we retry. We set + // noServerResponse in the block above and below we do not touch the question interval. When we come here, we + // already waited for the response. We need to send another query right at this moment. We do that below by + // reinitializing dns servers and reissuing the query. + // + // 2. We have more than one DNS server. If at least one server did not respond, we would have set noServerResponse + // either now (the last server in the list) or before (non-last server in the list). In either case, if we have + // reached the end of DNS server list, we need to try again from the beginning. Ideally we should try just the + // servers that did not respond, but for simplicity we try all the servers. Once we reached the end of list, we + // set triedAllServersOnce so that we don't try all the servers aggressively. See PenalizeDNSServer. + if (!q->qDNSServer && q->noServerResponse) + { + DNSServer *new; + DNSQuestion *qptr; + q->triedAllServersOnce = 1; + // Re-initialize all DNS servers for this question. If we have a DNSServer, DNSServerChangeForQuestion will + // handle all the work including setting the new DNS server. + SetValidDNSServers(m, q); + new = GetServerForQuestion(m, q); + if (new) + { + LogInfo("uDNS_checkCurrentQuestion: Retrying question %p %##s (%s) DNS Server %#a:%d ThisQInterval %d", + q, q->qname.c, DNSTypeName(q->qtype), new ? &new->addr : mDNSNULL, mDNSVal16(new ? new->port : zeroIPPort), q->ThisQInterval); + DNSServerChangeForQuestion(m, q, new); + } + for (qptr = q->next ; qptr; qptr = qptr->next) + if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; } } - if (q->qDNSServer && q->qDNSServer->teststate != DNSServer_Disabled) { mDNSu8 *end = m->omsg.data; @@ -4722,7 +4153,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) if (q->qDNSServer->teststate != DNSServer_Untested || NoTestQuery(q)) { end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass); - private = (q->AuthInfo && q->AuthInfo->AutoTunnel); + private = PrivateQuery(q); } else if (m->timenow - q->qDNSServer->lasttest >= INIT_UCAST_POLL_INTERVAL) // Make sure at least three seconds has elapsed since last test query { @@ -4735,19 +4166,21 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q))) { - //LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype)); + //LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, NextQSendTime(q) - m->timenow, private, q->qname.c, DNSTypeName(q->qtype)); if (private) { if (q->nta) CancelGetZoneData(m, q->nta); q->nta = StartGetZoneData(m, &q->qname, q->LongLived ? ZoneServiceLLQ : ZoneServiceQuery, PrivateQueryGotZoneData, q); - q->ThisQInterval = (LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10)) / QuestionIntervalStep; + if (q->state == LLQ_Poll) q->ThisQInterval = (LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10)) / QuestionIntervalStep; } else { + debugf("uDNS_CheckCurrentQuestion sending %p %##s (%s) %#a:%d UnansweredQueries %d", + q, q->qname.c, DNSTypeName(q->qtype), + q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->unansweredQueries); if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort); if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time else err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL); - m->SuppressStdPort53Queries = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+99)/100); } } @@ -4758,6 +4191,16 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) q->unansweredQueries++; if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = MAX_UCAST_POLL_INTERVAL; + if (private && q->state != LLQ_Poll) + { + // We don't want to retransmit too soon. Hence, we always schedule our first + // retransmisson at 3 seconds rather than one second + if (q->ThisQInterval < (3 * mDNSPlatformOneSecond)) + q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep; + if (q->ThisQInterval > LLQ_POLL_INTERVAL) + q->ThisQInterval = LLQ_POLL_INTERVAL; + LogInfo("uDNS_CheckCurrentQuestion: private non polling question for %##s (%s) will be retried in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval); + } debugf("Increased ThisQInterval to %d for %##s (%s)", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype)); } q->LastQTime = m->timenow; @@ -4781,21 +4224,63 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) for (rr = cg->members; rr; rr=rr->next) if (SameNameRecordAnswersQuestion(&rr->resrec, q)) mDNS_PurgeCacheResourceRecord(m, rr); - if (!q->qDNSServer) debugf("uDNS_CheckCurrentQuestion no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); - else LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qname.c); + if (!q->qDNSServer) + { + if (!mDNSOpaque64IsZero(&q->validDNSServers)) + LogMsg("uDNS_CheckCurrentQuestion: ERROR!!: valid DNSServer bits not zero 0x%x, 0x%x for question %##s (%s)", + q->validDNSServers.l[1], q->validDNSServers.l[0], q->qname.c, DNSTypeName(q->qtype)); + // If we reached the end of list while picking DNS servers, then we don't want to deactivate the + // question. Try after 60 seconds. We find this by looking for valid DNSServers for this question, + // if we find any, then we must have tried them before we came here. This avoids maintaining + // another state variable to see if we had valid DNS servers for this question. + SetValidDNSServers(m, q); + if (mDNSOpaque64IsZero(&q->validDNSServers)) + { + LogInfo("uDNS_CheckCurrentQuestion: no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + q->ThisQInterval = 0; + } + else + { + DNSQuestion *qptr; + // Pretend that we sent this question. As this is an ActiveQuestion, the NextScheduledQuery should + // be set properly. Also, we need to properly backoff in cases where we don't set the question to + // MaxQuestionInterval when we answer the question e.g., LongLived, we need to keep backing off + q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep; + q->LastQTime = m->timenow; + SetNextQueryTime(m, q); + // Pick a new DNS server now. Otherwise, when the cache is 80% of its expiry, we will try + // to send a query and come back to the same place here and log the above message. + q->qDNSServer = GetServerForQuestion(m, q); + for (qptr = q->next ; qptr; qptr = qptr->next) + if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; } + LogInfo("uDNS_checkCurrentQuestion: Tried all DNS servers, retry question %p SuppressUnusable %d %##s (%s) with DNS Server %#a:%d after 60 seconds, ThisQInterval %d", + q, q->SuppressUnusable, q->qname.c, DNSTypeName(q->qtype), + q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->ThisQInterval); + } + } + else + { + q->ThisQInterval = 0; + LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qname.c); + } - MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any); - // Inactivate this question until the next change of DNS servers (do this before AnswerCurrentQuestionWithResourceRecord) - q->ThisQInterval = 0; + // For some of the WAB queries that we generate form within the mDNSResponder, most of the home routers + // don't understand and return ServFail/NXDomain. In those cases, we don't want to try too often. We try + // every fifteen minutes in that case + MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, (WABQuestion(&q->qname) ? 60 * 15 : 60), mDNSInterface_Any, q->qDNSServer); q->unansweredQueries = 0; - CreateNewCacheEntry(m, slot, cg); + // We're already using the m->CurrentQuestion pointer, so CacheRecordAdd can't use it to walk the question list. + // To solve this problem we set rr->DelayDelivery to a nonzero value (which happens to be 'now') so that we + // momentarily defer generating answer callbacks until mDNS_Execute time. + CreateNewCacheEntry(m, slot, cg, NonZeroTime(m->timenow)); + ScheduleNextCacheCheckTime(m, slot, NonZeroTime(m->timenow)); m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it // MUST NOT touch m->CurrentQuestion (or q) after this -- client callback could have deleted it } } } -mDNSlocal void CheckNATMappings(mDNS *m) +mDNSexport void CheckNATMappings(mDNS *m) { mStatus err = mStatus_NoError; mDNSBool rfc1918 = mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4); @@ -4829,7 +4314,9 @@ mDNSlocal void CheckNATMappings(mDNS *m) if (m->SSDPSocket) { debugf("CheckNATMappings destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; } } - if (m->NATTraversals) + if (!m->NATTraversals) + m->retryGetAddr = m->timenow + 0x78000000; + else { if (m->timenow - m->retryGetAddr >= 0) { @@ -4840,6 +4327,8 @@ mDNSlocal void CheckNATMappings(mDNS *m) else if (m->retryIntervalGetAddr < NATMAP_MAX_RETRY_INTERVAL / 2) m->retryIntervalGetAddr *= 2; else m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL; } + LogInfo("CheckNATMappings retryGetAddr sent address request err %d interval %d", err, m->retryIntervalGetAddr); + // Always update m->retryGetAddr, even if we fail to send the packet. Otherwise in cases where we can't send the packet // (like when we have no active interfaces) we'll spin in an infinite loop repeatedly failing to send the packet m->retryGetAddr = m->timenow + m->retryIntervalGetAddr; @@ -4894,6 +4383,10 @@ mDNSlocal void CheckNATMappings(mDNS *m) // (1) we have an ExternalAddress, or we've tried and failed a couple of times to discover it // and (2) the client doesn't want a mapping, or the client won't need a mapping, or the client has a successful mapping, or we've tried and failed a couple of times // and (3) we have new data to give the client that's changed since the last callback + // Time line is: Send, Wait 500ms, Send, Wait 1sec, Send, Wait 2sec, Send + // At this point we've sent three requests without an answer, we've just sent our fourth request, + // retryIntervalGetAddr is now 4 seconds, which is greater than NATMAP_INIT_RETRY * 8 (2 seconds), + // so we return an error result to the caller. if (!mDNSIPv4AddressIsZero(m->ExternalAddress) || m->retryIntervalGetAddr > NATMAP_INIT_RETRY * 8) { const mStatus EffectiveResult = cur->NewResult ? cur->NewResult : mDNSv4AddrIsRFC1918(&m->ExternalAddress) ? mStatus_DoubleNAT : mStatus_NoError; @@ -4908,10 +4401,10 @@ mDNSlocal void CheckNATMappings(mDNS *m) if (cur->Protocol && mDNSIPPortIsZero(ExternalPort) && !mDNSIPv4AddressIsZero(m->Router.ip.v4)) { if (!EffectiveResult) - LogInfo("Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d", + LogInfo("CheckNATMapping: Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d", cur, &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort), cur->retryInterval, EffectiveResult); else - LogMsg("Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d", + LogMsg("CheckNATMapping: Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d", cur, &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort), cur->retryInterval, EffectiveResult); } @@ -4930,91 +4423,106 @@ mDNSlocal void CheckNATMappings(mDNS *m) } } -mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m) +mDNSlocal mDNSs32 CheckRecordUpdates(mDNS *m) { AuthRecord *rr; mDNSs32 nextevent = m->timenow + 0x3FFFFFFF; + CheckGroupRecordUpdates(m); + for (rr = m->ResourceRecords; rr; rr = rr->next) { - if (rr->state == regState_FetchingZoneData || - rr->state == regState_Pending || rr->state == regState_DeregPending || rr->state == regState_UpdatePending || - rr->state == regState_DeregDeferred || rr->state == regState_Refresh || rr->state == regState_Registered) + if (!AuthRecord_uDNS(rr)) continue; + if (rr->state == regState_NoTarget) {debugf("CheckRecordUpdates: Record %##s in NoTarget", rr->resrec.name->c); continue;} + // While we are waiting for the port mapping, we have nothing to do. The port mapping callback + // will take care of this + if (rr->state == regState_NATMap) {debugf("CheckRecordUpdates: Record %##s in NATMap", rr->resrec.name->c); continue;} + if (rr->state == regState_Pending || rr->state == regState_DeregPending || rr->state == regState_UpdatePending || + rr->state == regState_Refresh || rr->state == regState_Registered) { - if (rr->LastAPTime + rr->ThisAPInterval - m->timenow < 0) + if (rr->LastAPTime + rr->ThisAPInterval - m->timenow <= 0) { if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } - if (rr->state == regState_FetchingZoneData) + if (!rr->nta || mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4)) { - if (rr->nta) CancelGetZoneData(m, rr->nta); + // Zero out the updateid so that if we have a pending response from the server, it won't + // be accepted as a valid response. If we accept the response, we might free the new "nta" + if (rr->nta) { rr->updateid = zeroID; CancelGetZoneData(m, rr->nta); } rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr); - SetRecordRetry(m, rr, mStatus_NoError); + + // We have just started the GetZoneData. We need to wait for it to finish. SetRecordRetry here + // schedules the update timer to fire in the future. + // + // There are three cases. + // + // 1) When the updates are sent the first time, the first retry is intended to be at three seconds + // in the future. But by calling SetRecordRetry here we set it to nine seconds. But it does not + // matter because when the answer comes back, RecordRegistrationGotZoneData resets the interval + // back to INIT_RECORD_REG_INTERVAL. This also gives enough time for the query. + // + // 2) In the case of update errors (updateError), this causes further backoff as + // RecordRegistrationGotZoneData does not reset the timer. This is intentional as in the case of + // errors, we don't want to update aggressively. + // + // 3) We might be refreshing the update. This is very similar to case (1). RecordRegistrationGotZoneData + // resets it back to INIT_RECORD_REG_INTERVAL. + // + SetRecordRetry(m, rr, 0); } else if (rr->state == regState_DeregPending) SendRecordDeregistration(m, rr); else SendRecordRegistration(m, rr); } - if (nextevent - (rr->LastAPTime + rr->ThisAPInterval) > 0) - nextevent = (rr->LastAPTime + rr->ThisAPInterval); } + if (nextevent - (rr->LastAPTime + rr->ThisAPInterval) > 0) + nextevent = (rr->LastAPTime + rr->ThisAPInterval); } return nextevent; } -mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m) +mDNSexport void uDNS_Tasks(mDNS *const m) { - mDNSs32 nextevent = m->timenow + 0x3FFFFFFF; + mDNSs32 nexte; + DNSServer *d; + + m->NextuDNSEvent = m->timenow + 0x3FFFFFFF; - if (CurrentServiceRecordSet) - LogMsg("CheckServiceRegistrations ERROR CurrentServiceRecordSet already set"); - CurrentServiceRecordSet = m->ServiceRegistrations; + nexte = CheckRecordUpdates(m); + if (m->NextuDNSEvent - nexte > 0) + m->NextuDNSEvent = nexte; - // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery - while (CurrentServiceRecordSet) - { - ServiceRecordSet *srs = CurrentServiceRecordSet; - CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next; - if (srs->state == regState_FetchingZoneData || - srs->state == regState_Pending || srs->state == regState_DeregPending || srs->state == regState_DeregDeferred || - srs->state == regState_Refresh || srs->state == regState_UpdatePending || srs->state == regState_Registered) + for (d = m->DNSServers; d; d=d->next) + if (d->penaltyTime) { - if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - m->timenow <= 0) + if (m->timenow - d->penaltyTime >= 0) { - if (srs->tcp) { DisposeTCPConn(srs->tcp); srs->tcp = mDNSNULL; } - if (srs->state == regState_FetchingZoneData) - { - if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta); - srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs); - SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError); - } - else if (srs->state == regState_DeregPending) SendServiceDeregistration(m, srs); - else SendServiceRegistration(m, srs); + LogInfo("DNS server %#a:%d out of penalty box", &d->addr, mDNSVal16(d->port)); + d->penaltyTime = 0; } - if (nextevent - (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval) > 0) - nextevent = (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval); + else + if (m->NextuDNSEvent - d->penaltyTime > 0) + m->NextuDNSEvent = d->penaltyTime; } - } - return nextevent; - } - -mDNSexport void uDNS_Execute(mDNS *const m) - { - mDNSs32 nexte; - - m->NextuDNSEvent = m->timenow + 0x3FFFFFFF; - - if (m->NextSRVUpdate && m->NextSRVUpdate - m->timenow < 0) - { m->NextSRVUpdate = 0; UpdateSRVRecords(m); } - - CheckNATMappings(m); - if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0) - m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it - - nexte = CheckRecordRegistrations(m); - if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte; - - nexte = CheckServiceRegistrations(m); - if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte; + if (m->CurrentQuestion) + LogMsg("uDNS_Tasks ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); + m->CurrentQuestion = m->Questions; + while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) + { + DNSQuestion *const q = m->CurrentQuestion; + if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID)) + { + uDNS_CheckCurrentQuestion(m); + if (q == m->CurrentQuestion) + if (m->NextuDNSEvent - NextQSendTime(q) > 0) + m->NextuDNSEvent = NextQSendTime(q); + } + // If m->CurrentQuestion wasn't modified out from under us, advance it now + // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() + // depends on having m->CurrentQuestion point to the right question + if (m->CurrentQuestion == q) + m->CurrentQuestion = q->next; + } + m->CurrentQuestion = mDNSNULL; } // *************************************************************************** @@ -5022,61 +4530,42 @@ mDNSexport void uDNS_Execute(mDNS *const m) #pragma mark - Startup, Shutdown, and Sleep #endif -// simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of -// the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough -// in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake, -// we just move up the timers. - mDNSexport void SleepRecordRegistrations(mDNS *m) { AuthRecord *rr; for (rr = m->ResourceRecords; rr; rr=rr->next) + { if (AuthRecord_uDNS(rr)) - if (rr->state == regState_Registered || - rr->state == regState_Refresh) + { + // Zero out the updateid so that if we have a pending response from the server, it won't + // be accepted as a valid response. + if (rr->nta) { rr->updateid = zeroID; CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; } + + if (rr->NATinfo.clientContext) { - SendRecordDeregistration(m, rr); - rr->state = regState_Refresh; - rr->LastAPTime = m->timenow; - rr->ThisAPInterval = 300 * mDNSPlatformOneSecond; + mDNS_StopNATOperation_internal(m, &rr->NATinfo); + rr->NATinfo.clientContext = mDNSNULL; + } + // We are waiting to update the resource record. The original data of the record is + // in OrigRData and the updated value is in InFlightRData. Free the old and the new + // one will be registered when we come back. + if (rr->state == regState_UpdatePending) + { + // act as if the update succeeded, since we're about to delete the name anyway + rr->state = regState_Registered; + // deallocate old RData + if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->OrigRData, rr->OrigRDLen); + SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen); + rr->OrigRData = mDNSNULL; + rr->InFlightRData = mDNSNULL; } - } - -mDNSexport void SleepServiceRegistrations(mDNS *m) - { - ServiceRecordSet *srs = m->ServiceRegistrations; - while (srs) - { - LogInfo("SleepServiceRegistrations: state %d %s", srs->state, ARDisplayString(m, &srs->RR_SRV)); - if (srs->srs_nta) { CancelGetZoneData(m, srs->srs_nta); srs->srs_nta = mDNSNULL; } - - if (srs->NATinfo.clientContext) - { - mDNS_StopNATOperation_internal(m, &srs->NATinfo); - srs->NATinfo.clientContext = mDNSNULL; - } - if (srs->state == regState_UpdatePending) - { - // act as if the update succeeded, since we're about to delete the name anyway - AuthRecord *txt = &srs->RR_TXT; - srs->state = regState_Registered; - // deallocate old RData - if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData); - SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen); - txt->OrigRData = mDNSNULL; - txt->InFlightRData = mDNSNULL; + // If we have not begun the registration process i.e., never sent a registration packet, + // then uDNS_DeregisterRecord will not send a deregistration + uDNS_DeregisterRecord(m, rr); + + // When we wake, we call ActivateUnicastRegistration which starts at StartGetZoneData } - - if (srs->state == regState_Registered || srs->state == regState_Refresh) - SendServiceDeregistration(m, srs); - - srs->state = regState_NoTarget; // when we wake, we'll re-register (and optionally nat-map) once our address record completes - srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0; - srs->SRSUpdateServer = zeroAddr; // This will cause UpdateSRV to do a new StartGetZoneData - srs->RR_SRV.ThisAPInterval = 5 * mDNSPlatformOneSecond; // After doubling, first retry will happen after ten seconds - - srs = srs->uDNS_next; } } @@ -5110,6 +4599,95 @@ mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus r if (result == mStatus_MemFree) mDNSPlatformMemFree(rr->RecordContext); } +#if APPLE_OSX_mDNSResponder +mDNSlocal void CheckAutoTunnel6Registration(mDNS *const m, mDNSBool RegisterAutoTunnel6) + { + LogInfo("CheckAutoTunnel6Registration: Current value RegisterAutoTunnel6 %d, New value %d", m->RegisterAutoTunnel6, RegisterAutoTunnel6); + if (!RegisterAutoTunnel6) + { + // We are not supposed to register autotunnel6. If we had previously registered + // autotunnel6, deregister it now. + if (m->RegisterAutoTunnel6) + { + m->RegisterAutoTunnel6 = mDNSfalse; + LogInfo("CheckAutoTunnel6Registration: Removing AutoTunnel6"); + RemoveAutoTunnel6Record(m); + } + else LogInfo("CheckAutoTunnel6Registration: Already Removed AutoTunnel6"); + } + else + { + // We are supposed to register autotunnel6. If we had previously de-registered + // autotunnel6, re-register it now. + if (!m->RegisterAutoTunnel6) + { + m->RegisterAutoTunnel6 = mDNStrue; + LogInfo("CheckAutoTunnel6Registration: Adding AutoTunnel6"); + SetupConndConfigChanges(m); + } + else LogInfo("CheckAutoTunnel6Registration: already Added AutoTunnel6"); + } + } +#endif + +mDNSlocal void FoundDirDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) + { + SearchListElem *slElem = question->QuestionContext; + mDNSBool RegisterAutoTunnel6 = mDNStrue; + char *res = "DisableInboundRelay"; + + LogInfo("FoundDirDomain: InterfaceID %p %s Question %##s Answer %s", answer->InterfaceID, AddRecord ? "Add" : "Rmv", question->qname.c, RRDisplayString(m, answer)); + if (answer->rrtype != kDNSType_TXT) + { + LogMsg("FoundDirDomain: answer type is not TXT %s for question %##s", DNSTypeName(answer->rrtype), question->qname.c); + return; + } + if (answer->RecordType == kDNSRecordTypePacketNegative) + { + LogInfo("FoundDirDomain: Negative answer for %##s", question->qname.c); + return; + } + if (answer->InterfaceID == mDNSInterface_LocalOnly) + { + LogInfo("FoundDirDomain: LocalOnly interfaceID for %##s", question->qname.c); + return; + } + + // TXT record is encoded as <len><data> + if (answer->rdlength != mDNSPlatformStrLen(res) + 1) + { + LogInfo("FoundDirDomain: Invalid TXT record to disable %##s, length %d", question->qname.c, answer->rdlength); + return; + } + + // Compare the data (excluding the len byte) + if (!mDNSPlatformMemSame(&answer->rdata->u.txt.c[1], res, answer->rdlength - 1)) + { + LogInfo("FoundDirDomain: Invalid TXT record to disable %##s", question->qname.c); + return; + } + + // It is sufficient for one answer to disable registration of autotunnel6. But we should + // have zero answers across all domains to register autotunnel6. + if (AddRecord) + { + slElem->numDirAnswers++; + RegisterAutoTunnel6 = mDNSfalse; + } + else + { + const SearchListElem *s; + slElem->numDirAnswers--; + if (slElem->numDirAnswers < 0) LogMsg("FoundDirDomain: numDirAnswers less than zero %d", slElem->numDirAnswers); + // See if any domain (including the slElem) has any answers + for (s=SearchList; s; s=s->next) + if (s->numDirAnswers) { RegisterAutoTunnel6 = mDNSfalse; break; } + } +#if APPLE_OSX_mDNSResponder + CheckAutoTunnel6Registration(m, RegisterAutoTunnel6); +#endif + } + mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { SearchListElem *slElem = question->QuestionContext; @@ -5168,11 +4746,6 @@ mDNSexport void udns_validatelists(void *const v) { mDNS *const m = v; - ServiceRecordSet *s; - for (s = m->ServiceRegistrations; s; s=s->uDNS_next) - if (s->uDNS_next == (ServiceRecordSet*)~0) - LogMemCorruption("m->ServiceRegistrations: %p is garbage (%lX)", s, s->uDNS_next); - NATTraversalInfo *n; for (n = m->NATTraversals; n; n=n->next) if (n->next == (NATTraversalInfo *)~0 || n->clientCallback == (NATTraversalClientCallback)~0) @@ -5200,12 +4773,33 @@ mDNSexport void udns_validatelists(void *const v) } #endif +mDNSlocal void mDNS_StartDirQuestion(mDNS *const m, DNSQuestion *question, domainname *domain, void *context) + { + AssignDomainName (&question->qname, (const domainname*)"\002cf" "\007_dns-sd" "\x04_udp"); + AppendDomainName (&question->qname, domain); + question->InterfaceID = mDNSInterface_Any; + question->Target = zeroAddr; + question->qtype = kDNSType_TXT; + question->qclass = kDNSClass_IN; + question->LongLived = mDNSfalse; + question->ExpectUnique = mDNStrue; + question->ForceMCast = mDNSfalse; + question->ReturnIntermed = mDNSfalse; + question->SuppressUnusable = mDNSfalse; + question->QuestionCallback = FoundDirDomain; + question->QuestionContext = context; + LogInfo("mDNS_StartDirQuestion: Start DIR domain question %##s", question->qname.c); + if (mDNS_StartQuery(m, question)) + LogMsg("mDNS_StartDirQuestion: ERROR!! cannot start _dir._dns-sd query"); + } + // This should probably move to the UDS daemon -- the concept of legacy clients and automatic registration / automatic browsing // is really a UDS API issue, not something intrinsic to uDNS - mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m) { SearchListElem **p = &SearchList, *ptr; + const SearchListElem *s; + mDNSBool RegisterAutoTunnel6 = mDNStrue; mStatus err; // step 1: mark each element for removal (-1) @@ -5229,6 +4823,9 @@ mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m) *p = ptr->next; // If the user has "local" in their DNS searchlist, we ignore that for the purposes of domain enumeration queries + // Note: Stopping a question will not generate the RMV events for the question (handled in FoundDirDomain) + // and hence we need to recheck all the domains to see if we need to register/deregister _autotunnel6. + // This is done at the end. if (!SameDomainName(&ptr->domain, &localdomain)) { mDNS_StopGetDomains(m, &ptr->BrowseQ); @@ -5236,6 +4833,7 @@ mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m) mDNS_StopGetDomains(m, &ptr->DefBrowseQ); mDNS_StopGetDomains(m, &ptr->DefRegisterQ); mDNS_StopGetDomains(m, &ptr->AutomaticBrowseQ); + mDNS_StopGetDomains(m, &ptr->DirQ); } mDNSPlatformMemFree(ptr); @@ -5246,7 +4844,7 @@ mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m) arList = arList->next; debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c); err = mDNS_Deregister(m, &dereg->ar); - if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err); + if (err) LogMsg("uDNS_RegisterSearchDomains ERROR!! mDNS_Deregister returned %d", err); // Memory will be freed in the FreeARElemCallback } continue; @@ -5264,22 +4862,28 @@ mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m) err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ, mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr); err5 = mDNS_GetDomains(m, &ptr->AutomaticBrowseQ, mDNS_DomainTypeBrowseAutomatic, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr); if (err1 || err2 || err3 || err4 || err5) - LogMsg("GetDomains for domain %##s returned error(s):\n" + LogMsg("uDNS_RegisterSearchDomains: GetDomains for domain %##s returned error(s):\n" "%d (mDNS_DomainTypeBrowse)\n" "%d (mDNS_DomainTypeBrowseDefault)\n" "%d (mDNS_DomainTypeRegistration)\n" "%d (mDNS_DomainTypeRegistrationDefault)" "%d (mDNS_DomainTypeBrowseAutomatic)\n", ptr->domain.c, err1, err2, err3, err4, err5); + mDNS_StartDirQuestion(m, &ptr->DirQ, &ptr->domain, ptr); } ptr->flag = 0; } - if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); } + if (ptr->flag) { LogMsg("uDNS_RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); } p = &ptr->next; } - + // if there is any domain has answers, need to deregister autotunnel6 + for (s=SearchList; s; s=s->next) + if (s->numDirAnswers) { RegisterAutoTunnel6 = mDNSfalse; break; } +#if APPLE_OSX_mDNSResponder + CheckAutoTunnel6Registration(m, RegisterAutoTunnel6); +#endif return mStatus_NoError; } @@ -5299,5 +4903,5 @@ struct CompileTimeAssertionChecks_uDNS // other overly-large structures instead of having a pointer to them, can inadvertently // cause structure sizes (and therefore memory usage) to balloon unreasonably. char sizecheck_tcpInfo_t [(sizeof(tcpInfo_t) <= 9056) ? 1 : -1]; - char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 3920) ? 1 : -1]; + char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 4800) ? 1 : -1]; }; diff --git a/external/apache2/mDNSResponder/dist/mDNSCore/uDNS.h b/external/apache2/mDNSResponder/dist/mDNSCore/uDNS.h index 0d91ebcce75..0562dae17b7 100755 --- a/external/apache2/mDNSResponder/dist/mDNSCore/uDNS.h +++ b/external/apache2/mDNSResponder/dist/mDNSCore/uDNS.h @@ -13,210 +13,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - - Change History (most recent first): - -Log: uDNS.h,v $ -Revision 1.93 2008/09/24 23:48:05 cheshire -Don't need to pass whole ServiceRecordSet reference to GetServiceTarget; -it only needs to access the embedded SRV member of the set - -Revision 1.92 2008/06/19 23:42:03 mcguire -<rdar://problem/4206534> Use all configured DNS servers - -Revision 1.91 2008/06/19 01:20:50 mcguire -<rdar://problem/4206534> Use all configured DNS servers - -Revision 1.90 2007/12/22 02:25:30 cheshire -<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep - -Revision 1.89 2007/12/15 01:12:27 cheshire -<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown - -Revision 1.88 2007/10/25 20:06:13 cheshire -Don't try to do SOA queries using private DNS (TLS over TCP) queries - -Revision 1.87 2007/10/24 22:40:06 cheshire -Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData -Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData - -Revision 1.86 2007/10/18 23:06:42 cheshire -<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep -Additional fixes and refinements - -Revision 1.85 2007/10/18 20:23:17 cheshire -Moved SuspendLLQs into mDNS.c, since it's only called from one place - -Revision 1.84 2007/10/17 22:49:54 cheshire -<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep - -Revision 1.83 2007/10/17 22:37:23 cheshire -<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events - -Revision 1.82 2007/10/17 21:53:51 cheshire -Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData - -Revision 1.81 2007/10/16 21:16:50 cheshire -Get rid of unused uDNS_Sleep() routine - -Revision 1.80 2007/10/16 20:59:41 cheshire -Export SuspendLLQs/SleepServiceRegistrations/SleepRecordRegistrations so they're callable from other files - -Revision 1.79 2007/09/20 01:13:19 cheshire -Export CacheGroupForName so it's callable from other files - -Revision 1.78 2007/09/14 21:26:09 cheshire -<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways - -Revision 1.77 2007/09/12 23:03:08 cheshire -<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index - -Revision 1.76 2007/09/12 19:22:19 cheshire -Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport -Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers - -Revision 1.75 2007/08/28 23:53:21 cheshire -Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete - -Revision 1.74 2007/08/24 00:15:20 cheshire -Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held - -Revision 1.73 2007/08/01 03:09:22 cheshire -<rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port - -Revision 1.72 2007/08/01 00:04:13 cheshire -<rdar://problem/5261696> Crash in tcpKQSocketCallback -Half-open TCP connections were not being cancelled properly - -Revision 1.71 2007/07/30 23:31:26 cheshire -Code for respecting TTL received in uDNS responses should exclude LLQ-type responses - -Revision 1.70 2007/07/27 20:52:29 cheshire -Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events - -Revision 1.69 2007/07/27 19:30:40 cheshire -Changed mDNSQuestionCallback parameter from mDNSBool to QC_result, -to properly reflect tri-state nature of the possible responses - -Revision 1.68 2007/07/27 18:38:56 cheshire -Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion" - -Revision 1.67 2007/07/20 23:11:12 cheshire -Fix code layout - -Revision 1.66 2007/07/16 23:54:48 cheshire -<rdar://problem/5338850> Crash when removing or changing DNS keys - -Revision 1.65 2007/07/16 20:14:22 vazquez -<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite - -Revision 1.64 2007/07/11 02:53:36 cheshire -<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services -Add ServiceRecordSet parameter in GetServiceTarget - -Revision 1.63 2007/06/29 00:09:24 vazquez -<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes) - -Revision 1.62 2007/05/14 23:53:00 cheshire -Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c - -Revision 1.61 2007/05/07 20:43:45 cheshire -<rdar://problem/4241419> Reduce the number of queries and announcements - -Revision 1.60 2007/05/04 21:46:10 cheshire -Get rid of uDNS_Close (synonym for uDNS_Sleep) - -Revision 1.59 2007/05/03 22:40:38 cheshire -<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record - -Revision 1.58 2007/05/02 22:21:33 cheshire -<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData - -Revision 1.57 2007/04/27 19:28:02 cheshire -Any code that calls StartGetZoneData needs to keep a handle to the structure, so -it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop --- it would start a query and then quickly cancel it, and then when -StartGetZoneData completed, it had a dangling pointer and crashed.) - -Revision 1.56 2007/04/25 02:14:38 cheshire -<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query -Additional fixes to make LLQs work properly - -Revision 1.55 2007/04/22 06:02:03 cheshire -<rdar://problem/4615977> Query should immediately return failure when no server - -Revision 1.54 2007/04/04 21:48:53 cheshire -<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list - -Revision 1.53 2007/03/28 15:56:37 cheshire -<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output - -Revision 1.52 2007/02/28 01:44:26 cheshire -<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c - -Revision 1.51 2007/01/27 03:34:27 cheshire -Made GetZoneData use standard queries (and cached results); -eliminated GetZoneData_Callback() packet response handler - -Revision 1.50 2007/01/19 21:17:32 cheshire -StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion - -Revision 1.49 2007/01/17 21:35:31 cheshire -For clarity, rename zoneData_t field "isPrivate" to "zonePrivate" - -Revision 1.48 2007/01/10 22:51:57 cheshire -<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries - -Revision 1.47 2007/01/05 08:30:43 cheshire -Trim excessive "Log" checkin history from before 2006 -(checkin history still available via "cvs log ..." of course) - -Revision 1.46 2007/01/04 01:41:47 cheshire -Use _dns-update-tls/_dns-query-tls/_dns-llq-tls instead of creating a new "_tls" subdomain - -Revision 1.45 2006/12/22 20:59:49 cheshire -<rdar://problem/4742742> Read *all* DNS keys from keychain, - not just key for the system-wide default registration domain - -Revision 1.44 2006/12/20 04:07:35 cheshire -Remove uDNS_info substructure from AuthRecord_struct - -Revision 1.43 2006/12/16 01:58:32 cheshire -<rdar://problem/4720673> uDNS: Need to start caching unicast records - -Revision 1.42 2006/11/30 23:07:56 herscher -<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS - -Revision 1.41 2006/11/18 05:01:30 cheshire -Preliminary support for unifying the uDNS and mDNS code, -including caching of uDNS answers - -Revision 1.40 2006/11/10 07:44:04 herscher -<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM - -Revision 1.39 2006/10/20 05:35:05 herscher -<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list. - -Revision 1.38 2006/09/26 01:54:02 herscher -<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol) - -Revision 1.37 2006/09/15 21:20:15 cheshire -Remove uDNS_info substructure from mDNS_struct - -Revision 1.36 2006/08/14 23:24:23 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.35 2006/07/30 05:45:36 cheshire -<rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC - -Revision 1.34 2006/07/15 02:01:29 cheshire -<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder -Fix broken "empty string" browsing - -Revision 1.33 2006/07/05 22:53:28 cheshire -<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder - -*/ + */ #ifndef __UDNS_H_ #define __UDNS_H_ @@ -236,6 +33,7 @@ Revision 1.33 2006/07/05 22:53:28 cheshire #define LLQ_POLL_INTERVAL (15 * 60 * mDNSPlatformOneSecond) // Polling interval for zones w/ an advertised LLQ port (ie not static zones) if LLQ fails due to NAT, etc. #define RESPONSE_WINDOW (60 * mDNSPlatformOneSecond) // require server responses within one minute of request #define MAX_UCAST_UNANSWERED_QUERIES 2 // the number of unanswered queries from any one uDNS server before trying another server +#define DNSSERVER_PENALTY_TIME (60 * mDNSPlatformOneSecond) // number of seconds for which new questions don't pick this server #define DEFAULT_UPDATE_LEASE 7200 @@ -244,13 +42,23 @@ Revision 1.33 2006/07/05 22:53:28 cheshire #define QuestionIntervalStep3 (QuestionIntervalStep*QuestionIntervalStep*QuestionIntervalStep) #define InitialQuestionInterval ((mDNSPlatformOneSecond + QuestionIntervalStep-1) / QuestionIntervalStep) +// For Unicast record registrations, we initialize the interval to 1 second. When we send any query for +// the record registration e.g., GetZoneData, we always back off by QuestionIntervalStep +// so that the first retry does not happen until 3 seconds which should be enough for TCP/TLS to be done. +#define INIT_RECORD_REG_INTERVAL (1 * mDNSPlatformOneSecond) +#define MAX_RECORD_REG_INTERVAL (15 * 60 * mDNSPlatformOneSecond) +#define MERGE_DELAY_TIME (1 * mDNSPlatformOneSecond) + +// If we are refreshing, we do it at least 5 times with a min update frequency of +// 5 minutes +#define MAX_UPDATE_REFRESH_COUNT 5 +#define MIN_UPDATE_REFRESH_TIME (5 * 60 * mDNSPlatformOneSecond) // Entry points into unicast-specific routines extern void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo); extern void startLLQHandshake(mDNS *m, DNSQuestion *q); extern void sendLLQRefresh(mDNS *m, DNSQuestion *q); -extern void SleepServiceRegistrations(mDNS *m); extern void SleepRecordRegistrations(mDNS *m); // uDNS_UpdateRecord @@ -259,16 +67,11 @@ extern void SleepRecordRegistrations(mDNS *m); // rr->newrdlength // rr->UpdateCallback -extern mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra); extern mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr); extern void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q); extern CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name); extern mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr); -// mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal -// mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict -// mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered -typedef enum { mDNS_Dereg_normal, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type; extern mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt); extern mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question); extern mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question); @@ -276,19 +79,16 @@ extern mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalInfo * extern void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData); extern mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr); - -extern void ServiceRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *result); extern const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr); -extern mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs); - extern void uDNS_CheckCurrentQuestion(mDNS *const m); // integer fields of msg header must be in HOST byte order before calling this routine extern void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport); -// returns time of next scheduled event -extern void uDNS_Execute(mDNS *const m); +extern void uDNS_Tasks(mDNS *const m); +extern void UpdateAllSRVRecords(mDNS *m); +extern void CheckNATMappings(mDNS *m); extern mStatus uDNS_SetupDNSConfig(mDNS *const m); extern mStatus uDNS_RegisterSearchDomains(mDNS *const m); @@ -301,7 +101,7 @@ typedef enum uDNS_LLQ_Events // LLQ event packet: don't flush cache; assume TTL is 2 x LLQ refresh interval } uDNS_LLQType; -extern uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport); +extern uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, DNSQuestion **matchQuestion); extern DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name); extern DomainAuthInfo *GetAuthInfoForQuestion(mDNS *m, const DNSQuestion *const q); extern void DisposeTCPConn(struct tcpInfo_t *tcp); diff --git a/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSPosix.h b/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSPosix.h index 5eda2d16fef..dab4b11a4c5 100755 --- a/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSPosix.h +++ b/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSPosix.h @@ -13,70 +13,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - - Change History (most recent first): - -Log: mDNSPosix.h,v $ -Revision 1.19 2007/04/22 20:15:46 cheshire -Add missing parameters for mDNSPosixEventCallback - -Revision 1.18 2006/08/14 23:24:47 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.17 2005/02/04 00:39:59 cheshire -Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it - -Revision 1.16 2004/11/30 22:37:01 cheshire -Update copyright dates and add "Mode: C; tab-width: 4" headers - -Revision 1.15 2004/02/06 01:19:51 cheshire -Conditionally exclude IPv6 code unless HAVE_IPV6 is set - -Revision 1.14 2004/01/28 21:12:15 cheshire -Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6) - -Revision 1.13 2004/01/24 05:12:03 cheshire -<rdar://problem/3534352>: Need separate socket for issuing unicast queries - -Revision 1.12 2004/01/23 21:37:08 cheshire -For consistency, rename multicastSocket to multicastSocket4, and multicastSocketv6 to multicastSocket6 - -Revision 1.11 2003/12/11 03:03:51 rpantos -Clean up mDNSPosix so that it builds on OS X again. - -Revision 1.10 2003/12/08 20:47:02 rpantos -Add support for mDNSResponder on Linux. - -Revision 1.9 2003/10/30 19:25:19 cheshire -Fix warning on certain compilers - -Revision 1.8 2003/08/12 19:56:26 cheshire -Update to APSL 2.0 - -Revision 1.7 2003/07/02 21:19:59 cheshire -<rdar://problem/3313413> Update copyright notices, etc., in source code comments - -Revision 1.6 2003/03/13 03:46:21 cheshire -Fixes to make the code build on Linux - -Revision 1.5 2003/03/08 00:35:56 cheshire -Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt") - -Revision 1.4 2002/12/23 22:13:31 jgraessl - -Reviewed by: Stuart Cheshire -Initial IPv6 support for mDNSResponder. - -Revision 1.3 2002/09/21 20:44:53 zarzycki -Added APSL info - -Revision 1.2 2002/09/19 04:20:44 cheshire -Remove high-ascii characters that confuse some systems - -Revision 1.1 2002/09/17 06:24:34 cheshire -First checkin - -*/ + */ #ifndef __mDNSPlatformPosix_h #define __mDNSPlatformPosix_h diff --git a/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSUNP.h b/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSUNP.h index c91004f71fe..59b5501b37b 100755 --- a/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSUNP.h +++ b/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSUNP.h @@ -13,73 +13,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - - Change History (most recent first): - -Log: mDNSUNP.h,v $ -Revision 1.19 2006/08/14 23:24:47 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.18 2005/04/08 21:37:57 ksekar -<rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux - -Revision 1.17 2004/12/17 19:32:43 cheshire -Add missing semicolon - -Revision 1.16 2004/12/01 04:25:05 cheshire -<rdar://problem/3872803> Darwin patches for Solaris and Suse -Provide daemon() for platforms that don't have it - -Revision 1.15 2004/11/30 22:37:01 cheshire -Update copyright dates and add "Mode: C; tab-width: 4" headers - -Revision 1.14 2004/10/16 00:17:01 cheshire -<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check - -Revision 1.13 2004/03/20 05:37:09 cheshire -Fix contributed by Terry Lambert & Alfred Perlstein: -Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x - -Revision 1.12 2004/01/28 21:12:15 cheshire -Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6) - -Revision 1.11 2003/12/13 05:43:09 bradley -Fixed non-sa_len and non-IPv6 version of GET_SA_LEN macro to cast as sockaddr to access -sa_family so it works with any sockaddr-compatible address structure (e.g. sockaddr_storage). - -Revision 1.10 2003/12/11 03:03:51 rpantos -Clean up mDNSPosix so that it builds on OS X again. - -Revision 1.9 2003/12/08 20:47:02 rpantos -Add support for mDNSResponder on Linux. - -Revision 1.8 2003/08/12 19:56:26 cheshire -Update to APSL 2.0 - -Revision 1.7 2003/08/06 18:20:51 cheshire -Makefile cleanup - -Revision 1.6 2003/07/02 21:19:59 cheshire -<rdar://problem/3313413> Update copyright notices, etc., in source code comments - -Revision 1.5 2003/03/13 03:46:21 cheshire -Fixes to make the code build on Linux - -Revision 1.4 2002/12/23 22:13:32 jgraessl - -Reviewed by: Stuart Cheshire -Initial IPv6 support for mDNSResponder. - -Revision 1.3 2002/09/21 20:44:53 zarzycki -Added APSL info - -Revision 1.2 2002/09/19 04:20:44 cheshire -Remove high-ascii characters that confuse some systems - -Revision 1.1 2002/09/17 06:24:35 cheshire -First checkin - -*/ + */ #ifndef __mDNSUNP_h #define __mDNSUNP_h diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/CommonServices.h b/external/apache2/mDNSResponder/dist/mDNSShared/CommonServices.h index d3bcd462ec5..797e1a07370 100644 --- a/external/apache2/mDNSResponder/dist/mDNSShared/CommonServices.h +++ b/external/apache2/mDNSResponder/dist/mDNSShared/CommonServices.h @@ -13,45 +13,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - - Change History (most recent first): - -Log: CommonServices.h,v $ -Revision 1.11 2009/03/30 19:51:29 herscher -<rdar://problem/5925472> Current Bonjour code does not compile on Windows -<rdar://problem/5187308> Move build train to Visual Studio 2005 - -Revision 1.10 2009/01/11 03:20:06 mkrochma -<rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris - -Revision 1.9 2009/01/10 22:03:43 mkrochma -<rdar://problem/5797507> dnsextd fails to build on Linux - -Revision 1.8 2007/01/17 19:16:59 cheshire -Only define ssize_t if it's not already defined - -Revision 1.7 2007/01/16 23:00:45 cheshire -Don't need to include CoreServices.h - -Revision 1.6 2006/08/24 22:41:53 herscher -<rdar://problem/4580067> POSIX: dnsextd_parser doesn't compile on Linux - -Revision 1.5 2006/08/14 23:24:56 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.4 2006/07/05 22:43:21 cheshire -<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder - -Revision 1.3 2004/04/08 09:27:12 bradley -Added macro for portable specification of callback calling conventions. - -Revision 1.2 2004/03/07 05:53:39 bradley -Fixed NumVersion extraction macros. Updated error code mappings to match latest internal version. - -Revision 1.1 2004/01/30 02:25:59 bradley -Common Services and portability support for various platforms. - -*/ + */ //--------------------------------------------------------------------------------------------------------------------------- /*! @header CommonServices @@ -102,6 +64,16 @@ Common Services and portability support for various platforms. #endif #endif +// NetBSD + +#if( !defined( TARGET_OS_NETBSD ) ) + #if( defined( __NetBSD__ ) ) + #define TARGET_OS_NETBSD 1 + #else + #define TARGET_OS_NETBSD 0 + #endif +#endif + // Solaris #if( !defined( TARGET_OS_SOLARIS ) ) @@ -128,7 +100,7 @@ Common Services and portability support for various platforms. // No predefined macro for VxWorks so just assume VxWorks if nothing else is set. - #if( !macintosh && !__MACH__ && !defined( __linux__ ) && !defined ( __SVR4 ) && !defined ( __sun ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) ) + #if( !macintosh && !__MACH__ && !defined( __linux__ ) && !defined ( __SVR4 ) && !defined ( __sun ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) && !defined(__NetBSD__) && !defined(__DragonFly__) && !defined(__FreeBSD__)) #define TARGET_OS_VXWORKS 1 #else #define TARGET_OS_VXWORKS 0 @@ -224,6 +196,12 @@ Common Services and portability support for various platforms. #include <stdint.h> #include <arpa/inet.h> +#elif ( TARGET_OS_NETBSD ) + + // NetBSD + + #include <arpa/inet.h> + #elif( TARGET_OS_SOLARIS ) // Solaris @@ -493,7 +471,7 @@ Common Services and portability support for various platforms. // - Windows #if( TARGET_LANGUAGE_C_LIKE ) - #if( !defined(_SSIZE_T) && ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_LINUX && !TARGET_OS_VXWORKS && !TARGET_OS_MAC) + #if( !defined(_SSIZE_T) && ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_LINUX && !TARGET_OS_VXWORKS && !TARGET_OS_MAC && !TARGET_OS_NETBSD ) typedef int ssize_t; #endif #endif diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/GenLinkedList.c b/external/apache2/mDNSResponder/dist/mDNSShared/GenLinkedList.c index 970745ed3e2..6e371b9db52 100644 --- a/external/apache2/mDNSResponder/dist/mDNSShared/GenLinkedList.c +++ b/external/apache2/mDNSResponder/dist/mDNSShared/GenLinkedList.c @@ -20,20 +20,7 @@ Version: 1.0 Tabs: 4 spaces - - Change History (most recent first): - -Log: GenLinkedList.c,v $ -Revision 1.4 2006/08/14 23:24:56 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.3 2004/04/22 21:14:42 cheshire -Fix comment spelling mistake - -Revision 1.2 2004/02/05 07:41:08 cheshire -Add Log header - -*/ + */ #include "GenLinkedList.h" diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/GenLinkedList.h b/external/apache2/mDNSResponder/dist/mDNSShared/GenLinkedList.h index 033860c9952..4e177083c75 100644 --- a/external/apache2/mDNSResponder/dist/mDNSShared/GenLinkedList.h +++ b/external/apache2/mDNSResponder/dist/mDNSShared/GenLinkedList.h @@ -13,24 +13,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - - File: GenLinkedList.c - - Contains: interface to generic linked lists. - - Version: 1.0 - Tabs: 4 spaces - - Change History (most recent first): - -Log: GenLinkedList.h,v $ -Revision 1.3 2006/08/14 23:24:56 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.2 2004/02/05 07:41:08 cheshire -Add Log header - -*/ + */ #ifndef __GenLinkedList__ #define __GenLinkedList__ diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/PlatformCommon.c b/external/apache2/mDNSResponder/dist/mDNSShared/PlatformCommon.c index aa0a5ca4a20..a2c74091a3a 100644 --- a/external/apache2/mDNSResponder/dist/mDNSShared/PlatformCommon.c +++ b/external/apache2/mDNSResponder/dist/mDNSShared/PlatformCommon.c @@ -13,79 +13,6 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - - Change History (most recent first): - -Log: PlatformCommon.c,v $ -Revision 1.21 2009/04/11 00:20:24 jessic2 -<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically - -Revision 1.20 2008/10/09 22:26:05 cheshire -Save space by not showing high-resolution timestamp in LogMsgNoIdent() lines - -Revision 1.19 2008/07/14 17:43:36 mkrochma -Fix previous check in so connect still gets called - -Revision 1.18 2008/07/12 17:19:41 mkrochma -<rdar://problem/6068351> mDNSResponder PlatformCommon.c uses sin_len even on non-compliant platforms - -Revision 1.17 2008/03/05 00:19:09 cheshire -Conditionalize LogTimeStamps so it's specific to APPLE_OSX, for now - -Revision 1.16 2008/02/26 21:47:45 cheshire -Added cast to avoid compiler warning - -Revision 1.15 2008/02/26 21:42:26 cheshire -Added 'LogTimeStamps' option, to show ms-granularity timestamps on every log message - -Revision 1.14 2007/12/03 18:37:26 cheshire -Moved mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg -from mDNSMacOSX.c to PlatformCommon.c, so that Posix build can use them - -Revision 1.13 2007/10/22 20:07:07 cheshire -Moved mDNSPlatformSourceAddrForDest from mDNSMacOSX.c to PlatformCommon.c so -Posix build can share the code (better than just pasting it into mDNSPosix.c) - -Revision 1.12 2007/10/16 17:19:53 cheshire -<rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks -Cut ReadDDNSSettingsFromConfFile stack from 2112 to 1104 bytes - -Revision 1.11 2007/07/31 23:08:34 mcguire -<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming - -Revision 1.10 2007/07/11 02:59:58 cheshire -<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services -Add AutoTunnel parameter to mDNS_SetSecretForDomain - -Revision 1.9 2007/01/09 22:37:44 cheshire -Remove unused ClearDomainSecrets() function - -Revision 1.8 2006/12/22 20:59:51 cheshire -<rdar://problem/4742742> Read *all* DNS keys from keychain, - not just key for the system-wide default registration domain - -Revision 1.7 2006/08/14 23:24:56 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.6 2005/04/08 21:30:16 ksekar -<rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9 -Patch submitted by Bernd Kuhls - -Revision 1.5 2005/02/01 19:33:30 ksekar -<rdar://problem/3985239> Keychain format too restrictive - -Revision 1.4 2005/01/19 19:19:21 ksekar -<rdar://problem/3960191> Need a way to turn off domain discovery - -Revision 1.3 2004/12/13 17:46:52 cheshire -Use sizeof(buf) instead of fixed constant 1024 - -Revision 1.2 2004/12/01 03:30:29 cheshire -<rdar://problem/3889346> Add Unicast DNS support to mDNSPosix - -Revision 1.1 2004/12/01 01:51:35 cheshire -Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c - */ #include <stdio.h> // Needed for fopen() etc. diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/PlatformCommon.h b/external/apache2/mDNSResponder/dist/mDNSShared/PlatformCommon.h index dd7c4891e25..631e3d731a6 100644 --- a/external/apache2/mDNSResponder/dist/mDNSShared/PlatformCommon.h +++ b/external/apache2/mDNSResponder/dist/mDNSShared/PlatformCommon.h @@ -13,35 +13,6 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - - Change History (most recent first): - -Log: PlatformCommon.h,v $ -Revision 1.8 2007/10/22 20:07:52 cheshire -Deleted unused FindSourceAddrForIP() function - -Revision 1.7 2007/07/31 23:08:34 mcguire -<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming - -Revision 1.6 2007/01/09 22:37:43 cheshire -Remove unused ClearDomainSecrets() function - -Revision 1.5 2006/12/22 20:59:51 cheshire -<rdar://problem/4742742> Read *all* DNS keys from keychain, - not just key for the system-wide default registration domain - -Revision 1.4 2006/08/14 23:24:56 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.3 2005/01/19 19:19:21 ksekar -<rdar://problem/3960191> Need a way to turn off domain discovery - -Revision 1.2 2004/12/01 03:30:29 cheshire -<rdar://problem/3889346> Add Unicast DNS support to mDNSPosix - -Revision 1.1 2004/12/01 01:51:35 cheshire -Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c - */ extern void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled); diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_ipc.c b/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_ipc.c index 5c1ec4d0254..131510c80e4 100644 --- a/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_ipc.c +++ b/external/apache2/mDNSResponder/dist/mDNSShared/dnssd_ipc.c @@ -24,62 +24,6 @@ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Change History (most recent first): - -Log: dnssd_ipc.c,v $ -Revision 1.23 2009/04/01 21:10:34 herscher -<rdar://problem/5925472> Current Bonjour code does not compile on Windows - -Revision 1.22 2009/02/12 20:28:31 cheshire -Added some missing "const" declarations - -Revision 1.21 2008/10/23 23:21:31 cheshire -Moved definition of dnssd_strerror() to be with the definition of dnssd_errno, in dnssd_ipc.h - -Revision 1.20 2007/07/23 22:12:53 cheshire -<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients - -Revision 1.19 2007/05/16 01:06:52 cheshire -<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines - -Revision 1.18 2007/03/21 19:01:57 cheshire -<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits - -Revision 1.17 2006/10/27 00:38:22 cheshire -Strip accidental trailing whitespace from lines - -Revision 1.16 2006/08/14 23:05:53 cheshire -Added "tab-width" emacs header line - -Revision 1.15 2005/01/27 22:57:56 cheshire -Fix compile errors on gcc4 - -Revision 1.14 2004/10/06 02:22:20 cheshire -Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)" - -Revision 1.13 2004/10/01 22:15:55 rpantos -rdar://problem/3824265: Replace APSL in client lib with BSD license. - -Revision 1.12 2004/09/16 23:14:24 cheshire -Changes for Windows compatibility - -Revision 1.11 2004/06/18 04:56:09 rpantos -casting goodness - -Revision 1.10 2004/06/12 01:08:14 cheshire -Changes for Windows compatibility - -Revision 1.9 2004/05/18 23:51:27 cheshire -Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers - -Revision 1.8 2003/11/05 22:44:57 ksekar -<rdar://problem/3335230>: No bounds checking when reading data from client -Reviewed by: Stuart Cheshire - -Revision 1.7 2003/08/12 19:56:25 cheshire -Update to APSL 2.0 - */ #include "dnssd_ipc.h" diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/mDNSDebug.c b/external/apache2/mDNSResponder/dist/mDNSShared/mDNSDebug.c index 9581ae7a062..f111a5dd7b5 100644 --- a/external/apache2/mDNSResponder/dist/mDNSShared/mDNSDebug.c +++ b/external/apache2/mDNSResponder/dist/mDNSShared/mDNSDebug.c @@ -20,61 +20,7 @@ Version: 1.0 - Change History (most recent first): - -Log: mDNSDebug.c,v $ -Revision 1.16 2009/04/11 01:43:28 jessic2 -<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically - -Revision 1.15 2009/04/11 00:20:26 jessic2 -<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically - -Revision 1.14 2008/11/26 00:01:08 cheshire -Get rid of "Unknown" tag in SIGINFO output on Leopard - -Revision 1.13 2007/12/01 00:40:30 cheshire -Fixes from Bob Bradley for building on EFI - -Revision 1.12 2007/10/01 19:06:19 cheshire -Defined symbolic constant MDNS_LOG_INITIAL_LEVEL to set the logging level we start out at - -Revision 1.11 2007/07/27 20:19:56 cheshire -For now, comment out unused log levels MDNS_LOG_ERROR, MDNS_LOG_WARN, MDNS_LOG_INFO, MDNS_LOG_DEBUG - -Revision 1.10 2007/06/15 21:54:51 cheshire -<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS - -Revision 1.9 2007/04/05 19:52:32 cheshire -Display correct ident in syslog messages (i.e. in dnsextd, ProgramName is not "mDNSResponder") - -Revision 1.8 2007/01/20 01:43:27 cheshire -<rdar://problem/4058383> Should not write log messages to /dev/console - -Revision 1.7 2006/08/14 23:24:56 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.6 2005/01/27 22:57:56 cheshire -Fix compile errors on gcc4 - -Revision 1.5 2004/09/17 01:08:55 cheshire -Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h - The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces - declared in that file are ONLY appropriate to single-address-space embedded applications. - For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. - -Revision 1.4 2004/06/11 22:36:51 cheshire -Fixes for compatibility with Windows - -Revision 1.3 2004/01/28 21:14:23 cheshire -Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode) - -Revision 1.2 2003/12/09 01:30:40 rpantos -Fix usage of ARGS... macros to build properly on Windows. - -Revision 1.1 2003/12/08 21:11:42; rpantos -Changes necessary to support mDNSResponder on Linux. - -*/ + */ #include "mDNSDebug.h" @@ -132,7 +78,6 @@ mDNSlocal void LogMsgWithLevelv(mDNSLogLevel_t logLevel, const char *format, va_ // see mDNSDebug.h #if !MDNS_HAS_VA_ARG_MACROS -void debug_noop(const char *format, ...) { (void) format; } void LogMsg_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_MSG) void LogOperation_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_OPERATION) void LogSPS_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_SPS) @@ -140,7 +85,7 @@ void LogInfo_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_INFO) #endif #if MDNS_DEBUGMSGS -void debugf_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_DEBUG) +void debugf_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_DEBUG) #endif // Log message with default "mDNSResponder" ident string at the start diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/mDNSResponder.8 b/external/apache2/mDNSResponder/dist/mDNSShared/mDNSResponder.8 index 355e0c36065..48fcbd5a8dd 100644 --- a/external/apache2/mDNSResponder/dist/mDNSShared/mDNSResponder.8 +++ b/external/apache2/mDNSResponder/dist/mDNSShared/mDNSResponder.8 @@ -14,39 +14,6 @@ .\" See the License for the specific language governing permissions and .\" limitations under the License. .\" -.\" Log: mDNSResponder.8,v $ -.\" Revision 1.10 2009/04/20 16:12:13 mcguire -.\" <rdar://problem/6807798> manpage: roff errors -.\" -.\" Revision 1.9 2009/04/11 00:20:27 jessic2 -.\" <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically -.\" -.\" Revision 1.8 2006/10/06 17:31:33 mkrochma -.\" <rdar://problem/4769407> Typo in man page for mDNSResponder(8) -.\" -.\" Revision 1.7 2006/08/14 23:24:56 cheshire -.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 -.\" -.\" Revision 1.6 2005/02/10 22:35:28 cheshire -.\" <rdar://problem/3727944> Update name -.\" -.\" Revision 1.5 2004/06/29 02:41:38 cheshire -.\" Add note that mDNSResponder is called mdnsd on some systems -.\" -.\" Revision 1.4 2004/05/18 18:14:36 cheshire -.\" Minor wording update -.\" -.\" Revision 1.3 2004/04/22 02:56:08 cheshire -.\" <rdar://problem/3619494>: mDNSResponder man page format error -.\" -.\" Revision 1.2 2004/04/12 18:03:24 ksekar -.\" <rdar://problem/3619494>: mDNSResponder man page format error -.\" -.\" Revision 1.1 2003/11/13 03:21:38 cheshire -.\" <rdar://problem/3086886>: No man page for mDNSResponder -.\" -.\" -.\" .Dd April 2004 \" Date .Dt mDNSResponder 8 \" Document Title .Os Darwin \" Operating System diff --git a/external/apache2/mDNSResponder/dist/mDNSShared/uds_daemon.h b/external/apache2/mDNSResponder/dist/mDNSShared/uds_daemon.h index 46425ab4a4a..93cfd1e9659 100644 --- a/external/apache2/mDNSResponder/dist/mDNSShared/uds_daemon.h +++ b/external/apache2/mDNSResponder/dist/mDNSShared/uds_daemon.h @@ -20,96 +20,7 @@ Version: 1.0 - Change History (most recent first): - -Log: uds_daemon.h,v $ -Revision 1.27 2009/04/30 20:07:51 mcguire -<rdar://problem/6822674> Support multiple UDSs from launchd - -Revision 1.26 2008/10/02 22:26:21 cheshire -Moved declaration of BPF_fd from uds_daemon.c to mDNSMacOSX.c, where it really belongs - -Revision 1.25 2008/09/27 01:08:25 cheshire -Added external declaration of "dnssd_sock_t BPF_fd" - -Revision 1.24 2007/09/19 20:25:17 cheshire -Deleted outdated comment - -Revision 1.23 2007/07/24 17:23:02 cheshire -Rename DefRegList as AutoRegistrationDomains - -Revision 1.22 2007/07/11 02:58:04 cheshire -<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services - -Revision 1.21 2007/04/21 21:47:47 cheshire -<rdar://problem/4376383> Daemon: Add watchdog timer - -Revision 1.20 2007/02/14 01:58:19 cheshire -<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup - -Revision 1.19 2007/02/07 19:32:00 cheshire -<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format - -Revision 1.18 2007/02/06 19:06:49 cheshire -<rdar://problem/3956518> Need to go native with launchd - -Revision 1.17 2007/01/05 05:46:07 cheshire -Add mDNS *const m parameter to udsserver_handle_configchange() - -Revision 1.16 2007/01/04 23:11:15 cheshire -<rdar://problem/4720673> uDNS: Need to start caching unicast records -When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries - -Revision 1.15 2006/08/14 23:24:57 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.14 2005/01/27 17:48:39 cheshire -Added comment about CFSocketInvalidate closing the underlying socket - -Revision 1.13 2004/12/10 05:27:26 cheshire -<rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine - -Revision 1.12 2004/12/10 04:28:28 cheshire -<rdar://problem/3914406> User not notified of name changes for services using new UDS API - -Revision 1.11 2004/12/06 21:15:23 ksekar -<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations - -Revision 1.10 2004/10/26 04:31:44 cheshire -Rename CountSubTypes() as ChopSubTypes() - -Revision 1.9 2004/09/30 00:25:00 ksekar -<rdar://problem/3695802> Dynamically update default registration domains on config change - -Revision 1.8 2004/09/21 21:05:11 cheshire -Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c, -into mDNSShared/uds_daemon.c - -Revision 1.7 2004/09/17 01:08:55 cheshire -Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h - The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces - declared in that file are ONLY appropriate to single-address-space embedded applications. - For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. - -Revision 1.6 2004/08/11 01:58:49 cheshire -Remove "mDNS *globalInstance" parameter from udsserver_init() - -Revision 1.5 2004/06/18 04:44:58 rpantos -Use platform layer for socket types - -Revision 1.4 2004/06/12 00:51:58 cheshire -Changes for Windows compatibility - -Revision 1.3 2004/01/25 00:03:21 cheshire -Change to use mDNSVal16() instead of private PORT_AS_NUM() macro - -Revision 1.2 2004/01/24 08:46:26 bradley -Added InterfaceID<->Index platform interfaces since they are now used by all platforms for the DNS-SD APIs. - -Revision 1.1 2003/12/08 21:11:42 rpantos; -Changes necessary to support mDNSResponder on Linux. - -*/ + */ #include "mDNSEmbeddedAPI.h" #include "dnssd_ipc.h" @@ -127,8 +38,9 @@ extern int udsserver_exit(void); // should be called prior to app exit /* Routines that uds_daemon expects to link against: */ typedef void (*udsEventCallback)(int fd, short filter, void *context); -extern mStatus udsSupportAddFDToEventLoop(dnssd_sock_t fd, udsEventCallback callback, void *context); -extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd); // Note: This also CLOSES the file descriptor as well +extern mStatus udsSupportAddFDToEventLoop(dnssd_sock_t fd, udsEventCallback callback, void *context, void **platform_data); +extern int udsSupportReadFD(dnssd_sock_t fd, char* buf, int len, int flags, void *platform_data); +extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd, void *platform_data); // Note: This also CLOSES the file descriptor as well extern void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay); @@ -147,7 +59,21 @@ extern int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs); #if APPLE_OSX_mDNSResponder extern void machserver_automatic_browse_domain_changed(const domainname *d, mDNSBool add); extern void machserver_automatic_registration_domain_changed(const domainname *d, mDNSBool add); -#endif +// External support +extern void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype); +extern void external_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype); +extern void external_start_advertising_service(const ResourceRecord *const resourceRecord); +extern void external_stop_advertising_service(const ResourceRecord *const resourceRecord); +extern void external_start_resolving_service(const domainname *const fqdn); +extern void external_stop_resolving_service(const domainname *const fqdn); +#else +#define external_start_browsing_for_service(A,B,C) (void)(A) +#define external_stop_browsing_for_service(A,B,C) (void)(A) +#define external_start_advertising_service(A) (void)(A) +#define external_stop_advertising_service(A) (void)(A) +#define external_start_resolving_service(A) (void)(A) +#define external_stop_resolving_service(A) (void)(A) +#endif // APPLE_OSX_mDNSResponder extern const char mDNSResponderVersionString_SCCS[]; #define mDNSResponderVersionString (mDNSResponderVersionString_SCCS+5) |
