From: Apple Date: Mon, 8 Jan 2007 22:13:12 +0000 (+0000) Subject: mDNSResponder-108.4.tar.gz X-Git-Tag: mac-os-x-1049ppc^0 X-Git-Url: https://git.saurik.com/apple/mdnsresponder.git/commitdiff_plain/cc340f17b1c2189bb2fe03df9e50871ecda4f8e7?ds=inline mDNSResponder-108.4.tar.gz --- diff --git a/Makefile b/Makefile index ce810eb..1c65768 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ include /Developer/Makefiles/pb_makefiles/platform.make -MVERS = "mDNSResponder-108.2" +MVERS = "mDNSResponder-108.4" install: cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) diff --git a/mDNSCore/DNSCommon.c b/mDNSCore/DNSCommon.c index 2ce2489..e16b4ae 100644 --- a/mDNSCore/DNSCommon.c +++ b/mDNSCore/DNSCommon.c @@ -1,4 +1,5 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ @@ -23,6 +24,31 @@ Change History (most recent first): $Log: DNSCommon.c,v $ +Revision 1.96.2.1 2006/10/31 02:50:16 cheshire + mDNSResponder insufficiently defensive against malformed browsing PTR responses + +Revision 1.96 2006/03/10 21:51:42 cheshire + After record update, old record sometimes remains in cache +Split out SameRDataBody() into a separate routine so it can be called from other code + +Revision 1.95 2006/03/08 22:43:11 cheshire +Use "localdomain" symbol instead of literal string + +Revision 1.94 2006/03/02 21:59:55 cheshire + Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use" +Improve sanity checks & debugging support in GetLargeResourceRecord() + +Revision 1.93 2006/03/02 20:30:47 cheshire +Improved GetRRDisplayString to also show priority, weight, and port for SRV records + +Revision 1.92 2005/09/16 21:06:49 cheshire +Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place + +Revision 1.91 2005/07/10 22:10:37 cheshire +The getOptRdata routine implicitly assumes the destination ResourceRecord is large enough to +hold MaximumRDSize bytes, but its parameter was a generic ResourceRecord, which need not be that +large. Changing the parameter to a LargeCacheRecord makes it clearer what the routine requires. + Revision 1.90 2005/03/21 00:33:51 shersche Fix build warnings on Win32 platform @@ -450,7 +476,8 @@ mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, case kDNSType_TXT: mDNS_snprintf(buffer+length, 79-length, "%#s", rd->txt.c); break; case kDNSType_AAAA: mDNS_snprintf(buffer+length, 79-length, "%.16a", &rd->ipv6); break; - case kDNSType_SRV: mDNS_snprintf(buffer+length, 79-length, "%##s", rd->srv.target.c); break; + case kDNSType_SRV: mDNS_snprintf(buffer+length, 79-length, "%u %u %u %##s", + rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); break; default: mDNS_snprintf(buffer+length, 79-length, "RDLen %d: %s", rr->rdlength, rd->data); break; } for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr='.'; @@ -863,7 +890,7 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn, src = type->c; // Put the service type into the domain name len = *src; - if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, (domainname*)"\x05" "local"))) + if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, &localdomain))) { errormsg="Application protocol name must be underscore plus 1-14 characters. See "; goto fail; @@ -896,6 +923,11 @@ fail: return(mDNSNULL); } +// A service name has the form: instance.application-protocol.transport-protocol.domain +// DeconstructServiceName is currently fairly forgiving: It doesn't try to enforce character +// set or length limits for the protocol names, and the final domain is allowed to be empty. +// However, if the given FQDN doesn't contain at least three labels, +// DeconstructServiceName will reject it and return mDNSfalse. mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel *const name, domainname *const type, domainname *const domain) { @@ -904,29 +936,32 @@ mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn, const mDNSu8 *max = fqdn->c + MAX_DOMAIN_NAME; mDNSu8 *dst; - dst = name->c; // Extract the service name from the domain name + dst = name->c; // Extract the service name len = *src; - if (len >= 0x40) { debugf("DeconstructServiceName: service name too long"); return(mDNSfalse); } + if (!len) { debugf("DeconstructServiceName: FQDN empty!"); return(mDNSfalse); } + if (len >= 0x40) { debugf("DeconstructServiceName: Instance name too long"); return(mDNSfalse); } for (i=0; i<=len; i++) *dst++ = *src++; - dst = type->c; // Extract the service type from the domain name + dst = type->c; // Extract the service type len = *src; - if (len >= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse); } + if (!len) { debugf("DeconstructServiceName: FQDN contains only one label!"); return(mDNSfalse); } + if (len >= 0x40) { debugf("DeconstructServiceName: Application protocol name too long"); return(mDNSfalse); } for (i=0; i<=len; i++) *dst++ = *src++; len = *src; - if (len >= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse); } + if (!len) { debugf("DeconstructServiceName: FQDN contains only two labels!"); return(mDNSfalse); } + if (len >= 0x40) { debugf("DeconstructServiceName: Transport protocol name too long"); return(mDNSfalse); } for (i=0; i<=len; i++) *dst++ = *src++; - *dst++ = 0; // Put the null root label on the end of the service type + *dst++ = 0; // Put terminator on the end of service type - dst = domain->c; // Extract the service domain from the domain name + dst = domain->c; // Extract the service domain while (*src) { len = *src; if (len >= 0x40) - { debugf("DeconstructServiceName: service domain label too long"); return(mDNSfalse); } + { debugf("DeconstructServiceName: Label in service domain too long"); return(mDNSfalse); } if (src + 1 + len + 1 >= max) - { debugf("DeconstructServiceName: service domain too long"); return(mDNSfalse); } + { debugf("DeconstructServiceName: Total service domain too long"); return(mDNSfalse); } for (i=0; i<=len; i++) *dst++ = *src++; } *dst++ = 0; // Put the null root label on the end @@ -1092,25 +1127,32 @@ mDNSexport mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const return(sum); } -mDNSexport mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2) +// r1 has to be a full ResourceRecord including rrtype and rdlength +// r2 is just a bare RDataBody, which MUST be the same rrtype and rdlength as r1 +mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2) { - if (r1->rrtype != r2->rrtype) return(mDNSfalse); - if (r1->rdlength != r2->rdlength) return(mDNSfalse); - if (r1->rdatahash != r2->rdatahash) return(mDNSfalse); switch(r1->rrtype) { case kDNSType_CNAME:// Same as PTR - case kDNSType_PTR: return(SameDomainName(&r1->rdata->u.name, &r2->rdata->u.name)); + case kDNSType_PTR: return(SameDomainName(&r1->rdata->u.name, &r2->name)); - case kDNSType_SRV: return(mDNSBool)( r1->rdata->u.srv.priority == r2->rdata->u.srv.priority && - r1->rdata->u.srv.weight == r2->rdata->u.srv.weight && - r1->rdata->u.srv.port.NotAnInteger == r2->rdata->u.srv.port.NotAnInteger && - SameDomainName(&r1->rdata->u.srv.target, &r2->rdata->u.srv.target) ); + case kDNSType_SRV: return(mDNSBool)( r1->rdata->u.srv.priority == r2->srv.priority && + r1->rdata->u.srv.weight == r2->srv.weight && + r1->rdata->u.srv.port.NotAnInteger == r2->srv.port.NotAnInteger && + SameDomainName(&r1->rdata->u.srv.target, &r2->srv.target) ); - default: return(mDNSPlatformMemSame(r1->rdata->u.data, r2->rdata->u.data, r1->rdlength)); + default: return(mDNSPlatformMemSame(r1->rdata->u.data, r2->data, r1->rdlength)); } } +mDNSexport mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2) + { + if (r1->rrtype != r2->rrtype) return(mDNSfalse); + if (r1->rdlength != r2->rdlength) return(mDNSfalse); + if (r1->rdatahash != r2->rdatahash) return(mDNSfalse); + return(SameRDataBody(r1, &r2->rdata->u)); + } + mDNSexport mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2) { return (r1->namehash == r2->namehash && @@ -1383,9 +1425,10 @@ mDNSlocal mDNSu16 getVal16(const mDNSu8 **ptr) return val; } -mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *rr, mDNSu16 pktRDLen) +mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit, LargeCacheRecord *const cr, mDNSu16 pktRDLen) { int nread = 0; + ResourceRecord *const rr = &cr->r.resrec; rdataOpt *opt = (rdataOpt *)rr->rdata->u.data; while (nread < pktRDLen && (mDNSu8 *)opt < rr->rdata->u.data + MaximumRDSize - sizeof(rdataOpt)) @@ -1787,11 +1830,10 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage CacheRecord *rr = &largecr->r; mDNSu16 pktrdlength; - if (largecr == &m->rec && rr->resrec.RecordType) - LogMsg("GetLargeResourceRecord: m->rec appears to be already in use"); + if (largecr == &m->rec && largecr->r.resrec.RecordType) + LogMsg("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &largecr->r)); rr->next = mDNSNULL; - rr->resrec.RecordType = RecordType; rr->resrec.name = &largecr->namestorage; rr->NextInKAList = mDNSNULL; @@ -1823,7 +1865,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly. pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]); if (ptr[2] & (kDNSClass_UniqueRRSet >> 8)) - rr->resrec.RecordType |= kDNSRecordTypePacketUniqueMask; + RecordType |= kDNSRecordTypePacketUniqueMask; ptr += 10; if (ptr + pktrdlength > end) { debugf("GetResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); } end = ptr + pktrdlength; // Adjust end to indicate the end of the rdata for this resource record @@ -1884,7 +1926,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage rr->resrec.rdata->u.soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]); break; - case kDNSType_OPT: getOptRdata(ptr, end, &rr->resrec, pktrdlength); break; + case kDNSType_OPT: getOptRdata(ptr, end, largecr, pktrdlength); break; default: if (pktrdlength > rr->resrec.rdata->MaxRDLength) { @@ -1907,6 +1949,8 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); SetNewRData(&rr->resrec, mDNSNULL, 0); + // Success! Now fill in RecordType to show this record contains valid data + rr->resrec.RecordType = RecordType; return(ptr + pktrdlength); } @@ -2047,14 +2091,14 @@ mDNSexport void mDNS_Lock(mDNS *const m) if (m->mDNS_busy == 0) { if (m->timenow) - LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m->timenow, mDNSPlatformRawTime() + m->timenow_adjust); - m->timenow = mDNSPlatformRawTime() + m->timenow_adjust; + LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m->timenow, mDNS_TimeNow_NoLock(m)); + m->timenow = mDNS_TimeNow_NoLock(m); if (m->timenow == 0) m->timenow = 1; } else if (m->timenow == 0) { LogMsg("mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy); - m->timenow = mDNSPlatformRawTime() + m->timenow_adjust; + m->timenow = mDNS_TimeNow_NoLock(m); if (m->timenow == 0) m->timenow = 1; } diff --git a/mDNSCore/DNSCommon.h b/mDNSCore/DNSCommon.h index 13b7ca8..0f236c0 100644 --- a/mDNSCore/DNSCommon.h +++ b/mDNSCore/DNSCommon.h @@ -23,6 +23,10 @@ Change History (most recent first): $Log: DNSCommon.h,v $ +Revision 1.33 2006/03/10 21:51:41 cheshire + After record update, old record sometimes remains in cache +Split out SameRDataBody() into a separate routine so it can be called from other code + Revision 1.32 2005/03/21 00:33:51 shersche Fix build warnings on Win32 platform @@ -235,6 +239,7 @@ extern void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus r extern mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb); +extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2); extern mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2); extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q); diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c index db6d0e5..8c9b566 100755 --- a/mDNSCore/mDNS.c +++ b/mDNSCore/mDNS.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -45,6 +45,45 @@ Change History (most recent first): $Log: mDNS.c,v $ +Revision 1.535.2.3 2006/11/10 19:36:42 cheshire +Further refinement: Only harmonize TTL if the value we're adjusting it to is at least 2 seconds + +Revision 1.535.2.2 2006/10/31 02:11:26 cheshire +Compile error: Need to put back AllDNSLinkGroupv4 definition + +Revision 1.535.2.1 2006/10/31 01:28:06 cheshire + After service restarts on different port, for a few seconds DNS-SD may return stale port number + +Revision 1.535 2006/03/02 20:41:17 cheshire + After record update, old record sometimes remains in cache +Minor code tidying and comments to reduce the risk of similar programming errors in future + +Revision 1.534 2006/03/02 03:25:46 cheshire + After record update, old record sometimes remains in cache +Code to harmonize RRSet TTLs was inadvertently rescuing expiring records + +Revision 1.533 2006/02/26 00:54:41 cheshire +Fixes to avoid code generation warning/error on FreeBSD 7 + +Revision 1.532 2005/12/02 20:24:36 cheshire + Adjust cutoff time for KA list by one second + +Revision 1.531 2005/12/02 19:05:42 cheshire +Tidy up constants + +Revision 1.530 2005/11/07 01:49:48 cheshire +For consistency, use NonZeroTime() function instead of ?: expression + +Revision 1.529 2005/10/25 23:42:24 cheshire + Error in ResolveSimultaneousProbe() when type or class don't match +Changed switch statement to an "if" + +Revision 1.528 2005/10/25 23:34:22 cheshire + RequireGoodbye state not set/respected sometimes when machine going to sleep + +Revision 1.527 2005/10/25 22:43:59 cheshire +Add clarifying comments + Revision 1.526 2005/10/20 00:10:33 cheshire Add check to avoid crashing NAT gateways that have buggy DNS relay code @@ -503,7 +542,7 @@ Revision 1.388 2004/07/30 17:40:06 ksekar : TXT Record updates not available for wide-area services Revision 1.387 2004/07/26 22:49:30 ksekar -: Feature #9516: Need support for NATPMP in client +: Feature #9516: Need support for NAT-PMP in client Revision 1.386 2004/07/13 21:24:24 rpantos Fix for . @@ -1737,22 +1776,30 @@ mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)1; mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0; -#define UnicastDNSPortAsNumber 53 +#define UnicastDNSPortAsNumber 53 +#define NATPMPPortAsNumber 5351 +#define DNSEXTPortAsNumber 5352 // Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc. #define MulticastDNSPortAsNumber 5353 +#define LoopbackIPCPortAsNumber 5354 + mDNSexport const mDNSIPPort UnicastDNSPort = { { UnicastDNSPortAsNumber >> 8, UnicastDNSPortAsNumber & 0xFF } }; +mDNSexport const mDNSIPPort NATPMPPort = { { NATPMPPortAsNumber >> 8, NATPMPPortAsNumber & 0xFF } }; +mDNSexport const mDNSIPPort DNSEXTPort = { { DNSEXTPortAsNumber >> 8, DNSEXTPortAsNumber & 0xFF } }; mDNSexport const mDNSIPPort MulticastDNSPort = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } }; +mDNSexport const mDNSIPPort LoopbackIPCPort = { { LoopbackIPCPortAsNumber >> 8, LoopbackIPCPortAsNumber & 0xFF } }; + mDNSexport const mDNSv4Addr AllDNSAdminGroup = { { 239, 255, 255, 251 } }; mDNSexport const mDNSv4Addr AllDNSLinkGroupv4 = { { 224, 0, 0, 251 } }; mDNSexport const mDNSv6Addr AllDNSLinkGroupv6 = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } }; mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 251 } } } }; mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } }; -mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } }; -mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } }; -mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } }; -mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } }; -mDNSexport const mDNSOpaque16 UpdateReqFlags= { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } }; -mDNSexport const mDNSOpaque16 UpdateRespFlags={ { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } }; +mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } }; +mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } }; +mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } }; +mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } }; +mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } }; +mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } }; // Any records bigger than this are considered 'large' records #define SmallRecordLimit 1024 @@ -3121,7 +3168,7 @@ mDNSlocal void SendResponses(mDNS *const m) numDereg++; responseptr = newptr; } - else if (rr->NewRData) // If we have new data for this record + else if (rr->NewRData && !m->SleepState) // If we have new data for this record { RData *OldRData = rr->resrec.rdata; mDNSu16 oldrdlength = rr->resrec.rdlength; @@ -3132,6 +3179,7 @@ mDNSlocal void SendResponses(mDNS *const m) if (!newptr && m->omsg.h.numAnswers) break; numDereg++; responseptr = newptr; + rr->RequireGoodbye = mDNSfalse; } // Now try to see if we can fit the update in the same packet (not fatal if we can't) SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); @@ -3139,7 +3187,7 @@ mDNSlocal void SendResponses(mDNS *const m) rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec); rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state - if (newptr) responseptr = newptr; + if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; } SetNewRData(&rr->resrec, OldRData, oldrdlength); } else @@ -3281,10 +3329,11 @@ mDNSlocal void SendResponses(mDNS *const m) // Note: MUST call SetNextCacheCheckTime any time we change: // rr->TimeRcvd -// rr->DelayDelivery // rr->resrec.rroriginalttl // rr->UnansweredQueries // rr->CRActiveQuestion +// Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary +// Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr) { rr->NextRequiredQuery = RRExpireTime(rr); @@ -3367,7 +3416,8 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not already in the known answer list rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet ResourceRecordAnswersQuestion(&rr->resrec, q) && // which answers our question - rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0) // and it is less than half-way to expiry + rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away + mDNSPlatformOneSecond) // (also ensures we never include goodbye records with TTL=1) { *ka = rr; // Link this record into our known answer chain ka = &rr->NextInKAList; @@ -3867,7 +3917,7 @@ mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, C mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr) { - rr->DelayDelivery = 0; + rr->DelayDelivery = 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared if (m->CurrentQuestion) LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set"); m->CurrentQuestion = m->Questions; while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) @@ -3892,7 +3942,7 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c if (threshhold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second if (delay - RRExpireTime(rr) < 0) // then delay until after they've been deleted delay = RRExpireTime(rr); - if (delay - start > 0) return(delay ? delay : 1); // Make sure we return non-zero if we want to delay + if (delay - start > 0) return(NonZeroTime(delay)); else return(0); } @@ -3950,6 +4000,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) } } m->CurrentQuestion = mDNSNULL; + SetNextCacheCheckTime(m, rr); } // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call. @@ -3965,7 +4016,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr) { LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c); - if (m->CurrentQuestion) LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set"); + if (m->CurrentQuestion) LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set"); m->CurrentQuestion = m->Questions; while (m->CurrentQuestion) { @@ -3996,7 +4047,7 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr) m->CurrentQuestion = q->next; if (ResourceRecordAnswersQuestion(&rr->resrec, q)) { - verbosedebugf("CacheRecordRmv %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr)); if (q->CurrentAnswers == 0) LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?", q, q->qname.c, DNSTypeName(q->qtype)); else @@ -4651,7 +4702,7 @@ mDNSlocal int CompareRData(AuthRecord *our, CacheRecord *pkt) if (*pktptr > *ourptr) return(-1); // Our data is numerically lower; We lost if (*pktptr < *ourptr) return(+1); // Packet data is numerically lower; We won - debugf("CompareRData: How did we get here?"); + LogMsg("CompareRData ERROR: Invalid state"); return(-1); } @@ -4754,14 +4805,13 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q int result = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass; if (!result) result = (int)our->resrec.rrtype - (int)m->rec.r.resrec.rrtype; if (!result) result = CompareRData(our, &m->rec.r); - switch (result) + if (result > 0) + debugf("ResolveSimultaneousProbe: %##s (%s): We won", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); + else if (result < 0) { - case 1: debugf("ResolveSimultaneousProbe: %##s (%s): We won", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); - break; - case 0: break; - case -1: debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); - mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict); - goto exit; + debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); + mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict); + goto exit; } } } @@ -5251,8 +5301,14 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, const mDNSInterfaceID InterfaceID) { int i; - const mDNSu8 *ptr = LocateAnswers(response, end); // We ignore questions (if any) in a DNS response packet - CacheRecord *CacheFlushRecords = (CacheRecord*)1; // "(CacheRecord*)1" is special (non-zero) end-of-list marker + + // We ignore questions (if any) in a DNS response packet + const mDNSu8 *ptr = LocateAnswers(response, end); + + // "(CacheRecord*)1" is a special (non-zero) end-of-list marker + // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList + // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling. + CacheRecord *CacheFlushRecords = (CacheRecord*)1; CacheRecord **cfp = &CacheFlushRecords; // All records in a DNS response packet are treated as equally valid statements of truth. If we want @@ -5461,9 +5517,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, rr->DelayDelivery = m->timenow + mDNSPlatformOneSecond; // to delay delivery of this 'add' event else rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot); - CacheRecordAdd(m, rr); - // MUST do this AFTER CacheRecordAdd(), because that's what sets CRActiveQuestion for us - SetNextCacheCheckTime(m, rr); + CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us } } } @@ -5484,33 +5538,38 @@ exit: r1->NextInCFList = mDNSNULL; for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next) if (SameResourceRecordSignature(&r1->resrec, &r2->resrec)) - { - // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics) - // else, if record is old, mark it to be flushed - if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond) - r2->resrec.rroriginalttl = r1->resrec.rroriginalttl; - else + if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond) { - verbosedebugf("Cache flush %p X %p %##s (%s)", r1, r2, r2->resrec.name->c, DNSTypeName(r2->resrec.rrtype)); - // We set stale records to expire in one second. - // This gives the owner a chance to rescue it if necessary. - // This is important in the case of multi-homing and bridged networks: - // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be - // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit - // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet - // will promptly delete their cached copies of the (still valid) Ethernet IP address record. - // By delaying the deletion by one second, we give X a change to notice that this bridging has - // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches. - // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary - // final expiration queries for this record. - r2->resrec.rroriginalttl = 1; - r2->TimeRcvd = m->timenow; - r2->UnansweredQueries = MaxUnansweredQueries; + // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics) + // else, if record is old, mark it to be flushed + if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond) + { + if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1) + r2->resrec.rroriginalttl = r1->resrec.rroriginalttl; + } + else // else, if record is old, mark it to be flushed + { + verbosedebugf("Cache flush %p X %p %s", r1, r2, CRDisplayString(m, r2)); + // We set stale records to expire in one second. + // This gives the owner a chance to rescue it if necessary. + // This is important in the case of multi-homing and bridged networks: + // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be + // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit + // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet + // will promptly delete their cached copies of the (still valid) Ethernet IP address record. + // By delaying the deletion by one second, we give X a change to notice that this bridging has + // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches. + // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary + // final expiration queries for this record. + r2->resrec.rroriginalttl = 1; + r2->UnansweredQueries = MaxUnansweredQueries; + } + r2->TimeRcvd = m->timenow; SetNextCacheCheckTime(m, r2); } - } if (r1->DelayDelivery) // If we were planning to delay delivery of this record, see if we still need to { + // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot); if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1); } @@ -5529,9 +5588,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co const mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update; #ifndef UNICAST_DISABLED - mDNSIPPort NATPort = mDNSOpaque16fromIntVal(NATMAP_PORT); - - if (srcport.NotAnInteger == NATPort.NotAnInteger) + if (srcport.NotAnInteger == NATPMPPort.NotAnInteger) { mDNS_Lock(m); uDNS_ReceiveNATMap(m, pkt, (mDNSu16)(end - (mDNSu8 *)pkt)); diff --git a/mDNSCore/mDNSEmbeddedAPI.h b/mDNSCore/mDNSEmbeddedAPI.h index e2d402d..3113ff1 100755 --- a/mDNSCore/mDNSEmbeddedAPI.h +++ b/mDNSCore/mDNSEmbeddedAPI.h @@ -119,7 +119,7 @@ Revision 1.269 2005/01/11 22:50:52 ksekar Fixed constant naming (was using kLLQ_DefLease for update leases) Revision 1.268 2004/12/22 22:25:47 ksekar - NATPMP: handle location changes + NAT-PMP: handle location changes Revision 1.267 2004/12/22 00:13:49 ksekar Change version, port, and polling interval for LLQ @@ -403,13 +403,13 @@ Revision 1.182 2004/07/30 17:40:06 ksekar : TXT Record updates not available for wide-area services Revision 1.181 2004/07/29 19:27:15 ksekar -NATPMP Support - minor fixes and cleanup +NAT-PMP Support - minor fixes and cleanup Revision 1.180 2004/07/29 02:03:35 ksekar Delete unused #define and structure field Revision 1.179 2004/07/26 22:49:30 ksekar -: Feature #9516: Need support for NATPMP in client +: Feature #9516: Need support for NAT-PMP in client Revision 1.178 2004/07/13 21:24:24 rpantos Fix for . diff --git a/mDNSCore/uDNS.c b/mDNSCore/uDNS.c index c129f9d..6e2d70e 100755 --- a/mDNSCore/uDNS.c +++ b/mDNSCore/uDNS.c @@ -211,7 +211,7 @@ Revision 1.168 2004/12/23 23:22:47 ksekar Unicast known answers "name" pointers point to garbage stack memory Revision 1.167 2004/12/22 22:25:47 ksekar - NATPMP: handle location changes + NAT-PMP: handle location changes Revision 1.166 2004/12/22 00:04:12 ksekar mDNSResponder crashing in ReceivePortMapReply @@ -558,16 +558,16 @@ Revision 1.61 2004/07/30 17:40:06 ksekar : TXT Record updates not available for wide-area services Revision 1.60 2004/07/29 19:40:05 ksekar -NATPMP Support - minor fixes and cleanup +NAT-PMP Support - minor fixes and cleanup Revision 1.59 2004/07/29 19:27:15 ksekar -NATPMP Support - minor fixes and cleanup +NAT-PMP Support - minor fixes and cleanup Revision 1.58 2004/07/27 07:35:38 shersche fix syntax error, variables declared in the middle of a block Revision 1.57 2004/07/26 22:49:30 ksekar -: Feature #9516: Need support for NATPMP in client +: Feature #9516: Need support for NAT-PMP in client Revision 1.56 2004/07/26 19:14:44 ksekar : 8A210: mDNSResponder crashed in startLLQHandshakeCallback diff --git a/mDNSCore/uDNS.h b/mDNSCore/uDNS.h index 6d86705..76943f7 100755 --- a/mDNSCore/uDNS.h +++ b/mDNSCore/uDNS.h @@ -83,13 +83,13 @@ Revision 1.15 2004/07/30 17:40:06 ksekar : TXT Record updates not available for wide-area services Revision 1.14 2004/07/29 19:27:15 ksekar -NATPMP Support - minor fixes and cleanup +NAT-PMP Support - minor fixes and cleanup Revision 1.13 2004/07/29 02:03:35 ksekar Delete unused #define and structure field Revision 1.12 2004/07/26 22:49:30 ksekar -: Feature #9516: Need support for NATPMP in client +: Feature #9516: Need support for NAT-PMP in client Revision 1.11 2004/06/17 01:13:11 ksekar : polling interval too short diff --git a/mDNSMacOS9/mDNSMacOS9.c b/mDNSMacOS9/mDNSMacOS9.c index 0dbbe5e..13cf72e 100644 --- a/mDNSMacOS9/mDNSMacOS9.c +++ b/mDNSMacOS9/mDNSMacOS9.c @@ -74,7 +74,7 @@ Convert ServiceRegDomain to domainname instead of C string Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs Revision 1.30 2004/07/29 19:26:03 ksekar -Plaform-level changes for NATPMP support +Plaform-level changes for NAT-PMP support Revision 1.29 2004/05/26 20:53:16 cheshire Remove unncecessary "return( -1 );" at the end of mDNSPlatformUTC() diff --git a/mDNSMacOSX/mDNSMacOSX.c b/mDNSMacOSX/mDNSMacOSX.c index b67eca9..5b9ab35 100644 --- a/mDNSMacOSX/mDNSMacOSX.c +++ b/mDNSMacOSX/mDNSMacOSX.c @@ -24,6 +24,12 @@ Change History (most recent first): $Log: mDNSMacOSX.c,v $ +Revision 1.318.2.2 2006/12/14 21:38:51 cheshire +Fix problem exposed by previous changes: kSecAccountItemAttr is not necessarily nul-terminated + +Revision 1.318.2.1 2006/10/31 02:37:04 cheshire + Stop creating HINFO records + Revision 1.318 2005/10/20 00:10:34 cheshire Add check to avoid crashing NAT gateways that have buggy DNS relay code @@ -536,10 +542,10 @@ Revision 1.161 2004/08/11 00:17:46 ksekar set default bit for their domains Revision 1.160 2004/07/29 19:27:16 ksekar -NATPMP Support - minor fixes and cleanup +NAT-PMP Support - minor fixes and cleanup Revision 1.159 2004/07/26 22:49:31 ksekar -: Feature #9516: Need support for NATPMP in client +: Feature #9516: Need support for NAT-PMP in client Revision 1.158 2004/07/13 21:24:24 rpantos Fix for . @@ -966,6 +972,12 @@ Minor code tidying // including ones that mDNSResponder chooses not to use. #define LIST_ALL_INTERFACES 0 +// For debugging, being able to identify software versions is useful. +// Some people are concerned that this information could be exploited by hackers. +// I'm not totally convinced by that argument, but we don't want to cause our users distress, +// so for shipping code, define "NO_HINFO" to suppress the generation of HINFO records. -- SC +#define NO_HINFO 1 + // For enabling AAAA records over IPv4. Setting this to 0 sends only // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both // AAAA and A records over both IPv4 and IPv6. @@ -2934,7 +2946,8 @@ mDNSlocal void SetSecretForDomain(mDNS *m, const domainname *domain) if (attr.tag == kSecAccountItemAttr) { if (!attr.length || attr.length > MAX_ESCAPED_DOMAIN_NAME) { LogMsg("SetSecretForDomain - Bad key length %d", attr.length); goto cleanup; } - strncpy(keybuf, attr.data, attr.length); + memcpy(keybuf, attr.data, attr.length); + keybuf[attr.length] = 0; if (!MakeDomainNameFromDNSNameString(&keyname, keybuf)) { LogMsg("SetSecretForDomain - bad key %s", keybuf); goto cleanup; } debugf("Setting shared secret for zone %s with key %##s", dstring, keyname.c); mDNS_SetSecretForZone(m, d, &keyname, secret); @@ -3517,6 +3530,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces; if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue; +#ifndef NO_HINFO mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring); mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring); if (hlen + slen < 254) @@ -3526,6 +3540,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) mDNSPlatformMemCopy(HINFO_HWstring, &m->HIHardware.c[1], hlen); mDNSPlatformMemCopy(HINFO_SWstring, &m->HISoftware.c[1], slen); } +#endif /* NO_HINFO */ m->p->unicastsockets.m = m; m->p->unicastsockets.info = NULL; diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c index 5290bf7..ec5670a 100755 --- a/mDNSPosix/mDNSPosix.c +++ b/mDNSPosix/mDNSPosix.c @@ -121,7 +121,7 @@ Revision 1.50 2004/08/11 01:20:20 cheshire Declare private local functions using "mDNSlocal" Revision 1.49 2004/07/26 22:49:31 ksekar -: Feature #9516: Need support for NATPMP in client +: Feature #9516: Need support for NAT-PMP in client Revision 1.48 2004/07/20 01:47:36 rpantos NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr. diff --git a/mDNSShared/GenLinkedList.c b/mDNSShared/GenLinkedList.c old mode 100755 new mode 100644 diff --git a/mDNSShared/GenLinkedList.h b/mDNSShared/GenLinkedList.h old mode 100755 new mode 100644 diff --git a/mDNSShared/dns_sd.h b/mDNSShared/dns_sd.h old mode 100755 new mode 100644 diff --git a/mDNSShared/dnssd_clientlib.c b/mDNSShared/dnssd_clientlib.c old mode 100755 new mode 100644 diff --git a/mDNSShared/dnssd_clientstub.c b/mDNSShared/dnssd_clientstub.c old mode 100755 new mode 100644 diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c index 86ea294..3a0842f 100644 --- a/mDNSShared/uds_daemon.c +++ b/mDNSShared/uds_daemon.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,6 +24,63 @@ Change History (most recent first): $Log: uds_daemon.c,v $ +Revision 1.199.2.1 2007/01/06 03:22:03 cheshire + Crash at resolve_result_callback + 192 + +Revision 1.199 2006/06/28 08:53:39 cheshire +Added (commented out) debugging messages + +Revision 1.198 2006/06/27 20:16:07 cheshire +Fix code layout + +Revision 1.197 2006/05/18 01:32:35 cheshire + iChat: Lost connection with Bonjour +(mDNSResponder insufficiently defensive against malformed browsing PTR responses) + +Revision 1.196 2006/05/05 07:07:13 cheshire + mDNSResponder fails when UDS reads deliver partial data + +Revision 1.195 2006/04/25 20:56:28 mkrochma +Added comment about previous checkin + +Revision 1.194 2006/04/25 18:29:36 mkrochma +Workaround for warning: unused variable 'status' when building mDNSPosix + +Revision 1.193 2006/03/19 17:14:38 cheshire + Need faster purging of stale records +read_rr_from_ipc_msg was not setting namehash and rdatahash + +Revision 1.192 2006/03/18 20:58:32 cheshire +Misplaced curly brace + +Revision 1.191 2006/03/10 22:19:43 cheshire +Update debugging message in resolve_result_callback() to indicate whether event is ADD or RMV + +Revision 1.190 2006/03/10 21:56:12 cheshire + After record update, old record sometimes remains in cache +When service TXT and SRV record both change, clients with active resolve calls get *two* callbacks, one +when the TXT data changes, and then immediately afterwards a second callback with the new port number +This change suppresses the first unneccessary (and confusing) callback + +Revision 1.189 2006/01/06 00:56:31 cheshire + Should remove PID file on exit + +Revision 1.188 2005/10/11 22:15:03 cheshire + Add memory corruption safeguards to uds_daemon.c +Only compile uds_validatelists() when building for Mac OS X + +Revision 1.187 2005/10/11 20:30:27 cheshire + Add memory corruption safeguards to uds_daemon.c + +Revision 1.186 2005/09/12 07:11:53 herscher + Lazily call RegisterSearchDomains to workaround crashes of several routers. This code is conditionally compiled, and currently is only enabled on Windows platforms. + +Revision 1.185 2005/07/29 00:55:10 ksekar +Removed validation check in uds_validatelists which generated false alarms + +Revision 1.184 2005/07/04 22:40:26 cheshire +Additional debugging code to help catch memory corruption + Revision 1.183 2005/06/13 22:39:11 cheshire Missing return statement in handle_enum_request() error handling @@ -590,9 +647,10 @@ Update to APSL 2.0 #if defined(_WIN32) #include +#define MDNS_LAZY_REGISTER_SEARCH_DOMAINS #define dnssd_strerror(X) win32_strerror(X) #define usleep(X) Sleep(((X)+999)/1000) -static char * win32_strerror(int inErrorCode); +static char * win32_strerror(int inErrorCode); #else #include #include @@ -619,6 +677,10 @@ static char * win32_strerror(int inErrorCode); #endif // LOCAL_PEERCRED #endif //__MACOSX__ +#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS) +extern mStatus dDNS_RegisterSearchDomains( mDNS * const m ); +#endif + // Types and Data Structures // ---------------------------------------------------------------------- @@ -790,8 +852,7 @@ typedef struct // const ResourceRecord *srv; mDNSBool srv; mDNSBool txt; - domainname target; - mDNSIPPort port; + rdataSRV srvdata; mDNSu16 txtlen; mDNSu8 txtdata[AbsoluteMaxDNSMessageData]; } resolve_termination_t; @@ -819,53 +880,50 @@ static request_state * all_requests = NULL; #define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee // n get_string() calls w/o buffer overrun // private function prototypes -static void connect_callback(void *info); -static int read_msg(request_state *rs); -static int send_msg(reply_state *rs); -static void abort_request(request_state *rs); -static void request_callback(void *info); -static void handle_resolve_request(request_state *rstate); -static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord); -static void question_termination_callback(void *context); -static void handle_browse_request(request_state *request); -static void browse_termination_callback(void *context); -static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord); -static void handle_regservice_request(request_state *request); -static void regservice_termination_callback(void *context); -static void process_service_registration(ServiceRecordSet *const srs, mDNSBool SuppressError); -static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result); -static mStatus handle_add_request(request_state *rstate); -static mStatus handle_update_request(request_state *rstate); -static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep); -static void append_reply(request_state *req, reply_state *rep); -static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain); -static void enum_termination_callback(void *context); -static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord); -static void handle_query_request(request_state *rstate); -static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err); -static void handle_enum_request(request_state *rstate); -static mStatus handle_regrecord_request(request_state *rstate); -static void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result); -static void connected_registration_termination(void *context); -static void handle_reconfirm_request(request_state *rstate); -static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags); -static mStatus handle_removerecord_request(request_state *rstate); -static void reset_connected_rstate(request_state *rstate); -static int deliver_error(request_state *rstate, mStatus err); -static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err); -static transfer_state send_undelivered_error(request_state *rs); -static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request); -static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd); -static void my_perror(char *errmsg); -static void unlink_request(request_state *rs); -static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord); -static void resolve_termination_callback(void *context); -static int validate_message(request_state *rstate); -static mStatus remove_extra(request_state *rstate, service_instance *serv); -static mStatus remove_record(request_state *rstate); -static void free_service_instance(service_instance *srv); -static uint32_t dnssd_htonl(uint32_t l); -static void handle_setdomain_request(request_state *rstate); +mDNSlocal void connect_callback(void *info); +mDNSlocal int read_msg(request_state *rs); +mDNSlocal int send_msg(reply_state *rs); +mDNSlocal void abort_request(request_state *rs); +mDNSlocal void request_callback(void *info); +mDNSlocal void handle_resolve_request(request_state *rstate); +mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord); +mDNSlocal void question_termination_callback(void *context); +mDNSlocal void handle_browse_request(request_state *request); +mDNSlocal void browse_termination_callback(void *context); +mDNSlocal void handle_regservice_request(request_state *request); +mDNSlocal void regservice_termination_callback(void *context); +mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result); +mDNSlocal mStatus handle_add_request(request_state *rstate); +mDNSlocal mStatus handle_update_request(request_state *rstate); +mDNSlocal void append_reply(request_state *req, reply_state *rep); +mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain); +mDNSlocal void enum_termination_callback(void *context); +mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord); +mDNSlocal void handle_query_request(request_state *rstate); +mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err); +mDNSlocal void handle_enum_request(request_state *rstate); +mDNSlocal mStatus handle_regrecord_request(request_state *rstate); +mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result); +mDNSlocal void connected_registration_termination(void *context); +mDNSlocal void handle_reconfirm_request(request_state *rstate); +mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags); +mDNSlocal mStatus handle_removerecord_request(request_state *rstate); +mDNSlocal void reset_connected_rstate(request_state *rstate); +mDNSlocal int deliver_error(request_state *rstate, mStatus err); +mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err); +mDNSlocal transfer_state send_undelivered_error(request_state *rs); +mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request); +mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd); +mDNSlocal void my_perror(char *errmsg); +mDNSlocal void unlink_request(request_state *rs); +mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord); +mDNSlocal void resolve_termination_callback(void *context); +mDNSlocal int validate_message(request_state *rstate); +mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv); +mDNSlocal mStatus remove_record(request_state *rstate); +mDNSlocal void free_service_instance(service_instance *srv); +mDNSlocal uint32_t dnssd_htonl(uint32_t l); +mDNSlocal void handle_setdomain_request(request_state *rstate); // initialization, setup/teardown functions @@ -900,7 +958,7 @@ mDNSlocal void LogClientInfo(request_state *req) } } -static void FatalError(char *errmsg) +mDNSlocal void FatalError(char *errmsg) { LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno())); *(long*)0 = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does @@ -1037,6 +1095,8 @@ int udsserver_exit(void) debugf("Unable to remove %s", MDNS_UDS_SERVERPATH); #endif + if (PID_FILE[0]) unlink(PID_FILE); + return 0; } @@ -1088,7 +1148,7 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent) else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond; // try again in a second } if (result == t_terminated || result == t_error) - //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request() + //since we're already doing a list traversal, we unlink the request manually instead of calling unlink_request() { tmp = req; if (prev) prev->next = req->next; @@ -1105,7 +1165,7 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent) return nextevent; } -void udsserver_info(mDNS *const m) +mDNSexport void udsserver_info(mDNS *const m) { mDNSs32 now = mDNS_TimeNow(m); mDNSu32 CacheUsed = 0, CacheActive = 0; @@ -1116,6 +1176,7 @@ void udsserver_info(mDNS *const m) LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now); + LogMsgNoIdent("Slt Q TTL U Type if len rdata"); for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) for(cg = m->rrcache_hash[slot]; cg; cg=cg->next) { @@ -1125,10 +1186,14 @@ void udsserver_info(mDNS *const m) mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond; CacheUsed++; if (rr->CRActiveQuestion) CacheActive++; - LogMsgNoIdent("%s%6ld %s%-6s%-6s%s", - rr->CRActiveQuestion ? "*" : " ", remain, - (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ", DNSTypeName(rr->resrec.rrtype), - ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname, CRDisplayString(m, rr)); + LogMsgNoIdent("%3d %s%6ld %s %-6s%-6s%s", + slot, + rr->CRActiveQuestion ? "*" : " ", + remain, + (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ", + DNSTypeName(rr->resrec.rrtype), + ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname, + CRDisplayString(m, rr)); usleep(1000); // Limit rate a little so we don't flood syslog too fast } } @@ -1146,7 +1211,17 @@ void udsserver_info(mDNS *const m) LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now); } -static void rename_service(service_instance *srv) +#if __MACOSX__ && MACOSX_MDNS_MALLOC_DEBUGGING +mDNSexport void uds_validatelists(void) + { + request_state *req; + for (req = all_requests; req; req=req->next) + if (req->sd < 0 && req->sd != -2) + LogMemCorruption("UDS request list: %p is garbage (%X)", req, req->sd); + } +#endif + +mDNSlocal void rename_service(service_instance *srv) { if (srv->autoname && !SameDomainLabel(srv->name.c, gmDNS->nicelabel.c)) { @@ -1156,11 +1231,10 @@ static void rename_service(service_instance *srv) } } -void udsserver_handle_configchange(void) +mDNSexport void udsserver_handle_configchange(void) { request_state *req; - for (req = all_requests; req; req = req->next) { if (req->service_registration) @@ -1172,7 +1246,7 @@ void udsserver_handle_configchange(void) } } -static void connect_callback(void *info) +mDNSlocal void connect_callback(void *info) { dnssd_sock_t sd; dnssd_socklen_t len; @@ -1229,7 +1303,7 @@ static void connect_callback(void *info) } // handler -static void request_callback(void *info) +mDNSlocal void request_callback(void *info) { request_state *rstate = info; transfer_state result; @@ -1299,6 +1373,8 @@ static void request_callback(void *info) return; } + //LogOperation("request_callback: Opened dedicated errfd %d", errfd); + #if defined(USE_TCP_LOOPBACK) { mDNSOpaque16 port; @@ -1318,8 +1394,10 @@ static void request_callback(void *info) strcpy(cliaddr.sun_path, ctrl_path); } #endif + //LogOperation("request_callback: Connecting to “%s”", cliaddr.sun_path); if (connect(errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0) { + //LogOperation("request_callback: Couldn't connect to “%s”", cliaddr.sun_path); my_perror("ERROR: connect"); abort_request(rstate); unlink_request(rstate); @@ -1346,6 +1424,7 @@ static void request_callback(void *info) default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op); } + //LogOperation("request_callback: Returning error code %d on socket %d", err, errfd); err = dnssd_htonl(err); nwritten = send(errfd, (dnssd_sockbuf_t) &err, sizeof(err), 0); // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us. @@ -1353,7 +1432,9 @@ static void request_callback(void *info) if (nwritten < (int)sizeof(err)) LogMsg("ERROR: failed to write error response back to caller: %d %d %s", nwritten, dnssd_errno(), dnssd_strerror(dnssd_errno())); + //else LogOperation("request_callback: Returned error code %d on socket %d", err, errfd); dnssd_close(errfd); + //LogOperation("request_callback: Closed errfd %d", errfd); reset_connected_rstate(rstate); // Reset ready to accept the next request on this pipe } else @@ -1381,7 +1462,7 @@ static void request_callback(void *info) // massage the name parameters appropriately, but the rest of the operations (making the query call, // delivering the result to the client, and termination) are identical. -static void handle_query_request(request_state *rstate) +mDNSlocal void handle_query_request(request_state *rstate) { DNSServiceFlags flags; uint32_t ifi; @@ -1447,7 +1528,7 @@ error: return; } -static void handle_resolve_request(request_state *rstate) +mDNSlocal void handle_resolve_request(request_state *rstate) { DNSServiceFlags flags; uint32_t interfaceIndex; @@ -1547,7 +1628,7 @@ bad_param: unlink_request(rstate); } -static void resolve_termination_callback(void *context) +mDNSlocal void resolve_termination_callback(void *context) { resolve_termination_t *term = context; request_state *rs; @@ -1567,8 +1648,8 @@ static void resolve_termination_callback(void *context) rs->termination_context = NULL; } -static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) -{ +mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) + { size_t len = 0; char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME]; char *data; @@ -1578,7 +1659,8 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const resolve_termination_t *res = rs->termination_context; (void)m; // Unused - LogOperation("%3d: DNSServiceResolve(%##s, %s) RESULT %s", rs->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer)); + LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s", + rs->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer)); // This code used to do this trick of just keeping a copy of the pointer to // the answer record in the cache, but the unicast query code doesn't currently @@ -1586,20 +1668,32 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const if (!AddRecord) { - // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL; + // After unicast query code is updated to store its records in the common cache, use this... // if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL; + // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL; + // intead of this... + if (answer->rrtype == kDNSType_SRV && res->srv && SameRDataBody(answer, (RDataBody *)&res->srvdata)) + res->srv = mDNSfalse; + if (answer->rrtype == kDNSType_TXT && res->txt && answer->rdlength == res->txtlen && SameRDataBody(answer, (RDataBody *)&res->txtdata)) + res->txt = mDNSfalse; return; } - // if (answer->rrtype == kDNSType_TXT) res->txt = answer; + // After unicast query code is updated to store its records in the common cache, use this... // if (answer->rrtype == kDNSType_SRV) res->srv = answer; - + // if (answer->rrtype == kDNSType_TXT) res->txt = answer; + // intead of this... if (answer->rrtype == kDNSType_SRV) - { - AssignDomainName(&res->target, &answer->rdata->u.srv.target); - res->port = answer->rdata->u.srv.port; - res->srv = mDNStrue; - } + { + // Don't copy structure in its entirety, because the CacheEntity may be an intentionally truncated object + // (to economize on space) and reading past the end may run into unmapped memory, causing a crash. + //res->srvdata = answer->rdata->u.srv; + // The AssignDomainName() macro is smart enough to only copy the valid part of the name, and not + // try to copy the full 255 bytes which may not all be there. + AssignDomainName(&res->srvdata.target, &answer->rdata->u.srv.target); + res->srvdata.port = answer->rdata->u.srv.port; + res->srv = mDNStrue; + } if (answer->rrtype == kDNSType_TXT) { if (answer->rdlength > AbsoluteMaxDNSMessageData) return; @@ -1611,7 +1705,7 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const if (!res->txt || !res->srv) return; // only deliver result to client if we have both answers ConvertDomainNameToCString(answer->name, fullname); - ConvertDomainNameToCString(&res->target, target); + ConvertDomainNameToCString(&res->srvdata.target, target); // calculate reply length len += sizeof(DNSServiceFlags); @@ -1633,8 +1727,8 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const // write reply data to message put_string(fullname, &data); put_string(target, &data); - *data++ = res->port.b[0]; - *data++ = res->port.b[1]; + *data++ = res->srvdata.port.b[0]; + *data++ = res->srvdata.port.b[1]; put_short(res->txtlen, &data); put_rdata(res->txtlen, res->txtdata, &data); @@ -1650,7 +1744,7 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const } // what gets called when a resolve is completed and we need to send the data back to the client -static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) { char *data; char name[MAX_ESCAPED_DOMAIN_NAME]; @@ -1674,7 +1768,7 @@ static void question_result_callback(mDNS *const m, DNSQuestion *question, const rep = create_reply(query_reply, len, req); rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0); - rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID)); + rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID)); rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError); data = rep->sdata; @@ -1690,7 +1784,7 @@ static void question_result_callback(mDNS *const m, DNSQuestion *question, const return; } -static void question_termination_callback(void *context) +mDNSlocal void question_termination_callback(void *context) { DNSQuestion *q = context; LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state *)q->QuestionContext)->sd, q->qname.c, DNSTypeName(q->qtype)); @@ -1701,7 +1795,7 @@ static void question_termination_callback(void *context) // If there's a comma followed by another character, // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character. // Otherwise, it returns a pointer to the final nul at the end of the string -static char *FindFirstSubType(char *p) +mDNSlocal char *FindFirstSubType(char *p) { while (*p) { @@ -1716,7 +1810,7 @@ static char *FindFirstSubType(char *p) // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character. // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL // Otherwise, it returns a pointer to the final nul at the end of the string -static char *FindNextSubType(char *p) +mDNSlocal char *FindNextSubType(char *p) { while (*p) { @@ -1770,14 +1864,14 @@ mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p) } #ifdef _HAVE_SETDOMAIN_SUPPORT_ -static void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result) +mDNSlocal void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result) { (void)m; // unused if (result == mStatus_MemFree) free(rr->RecordContext); // context is the enclosing list structure } #endif -static void handle_setdomain_request(request_state *request) +mDNSlocal void handle_setdomain_request(request_state *request) { mStatus err = mStatus_NoError; char *ptr; @@ -1866,11 +1960,80 @@ static void handle_setdomain_request(request_state *request) unlink_request(request); } -static mStatus add_domain_to_browser(browser_info_t *info, const domainname *d) +// Generates a response message giving name, type, domain, plus interface index, +// suitable for a browse result or service registration result. +// On successful completion rep is set to point to a malloc'd reply_state struct +mDNSlocal mStatus GenerateNTDResponse(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep) + { + domainlabel name; + domainname type, dom; + *rep = NULL; + if (!DeconstructServiceName(servicename, &name, &type, &dom)) + return kDNSServiceErr_Invalid; + else + { + char namestr[MAX_DOMAIN_LABEL+1]; + char typestr[MAX_ESCAPED_DOMAIN_NAME]; + char domstr [MAX_ESCAPED_DOMAIN_NAME]; + int len; + char *data; + + ConvertDomainLabelToCString_unescaped(&name, namestr); + ConvertDomainNameToCString(&type, typestr); + ConvertDomainNameToCString(&dom, domstr); + + // Calculate reply data length + len = sizeof(DNSServiceFlags); + len += sizeof(uint32_t); // if index + len += sizeof(DNSServiceErrorType); + len += (int) (strlen(namestr) + 1); + len += (int) (strlen(typestr) + 1); + len += (int) (strlen(domstr) + 1); + + // Build reply header + *rep = create_reply(query_reply, len, request); + (*rep)->rhdr->flags = dnssd_htonl(0); + (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id)); + (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError); + + // Build reply body + data = (*rep)->sdata; + put_string(namestr, &data); + put_string(typestr, &data); + put_string(domstr, &data); + + return mStatus_NoError; + } + } + +mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) + { + request_state *req = question->QuestionContext; + reply_state *rep; + (void)m; // Unused + + if (answer->rrtype != kDNSType_PTR) + { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; } + + if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep) != mStatus_NoError) + { + LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer", + req->sd, answer->name->c, answer->rdata->u.name.c); + return; + } + + LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s", + req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer)); + + if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd); + append_reply(req, rep); + } + +mDNSlocal mStatus add_domain_to_browser(browser_info_t *info, const domainname *d) { browser_t *b, *p; mStatus err; - + for (p = info->browsers; p; p = p->next) { if (SameDomainName(&p->domain, d)) @@ -1880,7 +2043,7 @@ static mStatus add_domain_to_browser(browser_info_t *info, const domainname *d) b = mallocL("browser_t", sizeof(*b)); if (!b) return mStatus_NoMemoryErr; AssignDomainName(&b->domain, d); - err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, browse_result_callback, info->rstate); + err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, FoundInstance, info->rstate); if (err) { LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->regtype.c, d->c); @@ -1894,7 +2057,7 @@ static mStatus add_domain_to_browser(browser_info_t *info, const domainname *d) return err; } -static void handle_browse_request(request_state *request) +mDNSlocal void handle_browse_request(request_state *request) { DNSServiceFlags flags; uint32_t interfaceIndex; @@ -1928,6 +2091,13 @@ static void handle_browse_request(request_state *request) InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex); if (interfaceIndex && !InterfaceID) { err = mStatus_BadParamErr; goto error; } +#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS) + if ( !domain || ( domain[0] == '\0' ) ) + { + dDNS_RegisterSearchDomains( gmDNS ); + } +#endif + typedn.c[0] = 0; NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes if (NumSubTypes < 0 || NumSubTypes > 1) { err = mStatus_BadParamErr; goto error; } @@ -1989,31 +2159,7 @@ error: unlink_request(request); } -static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) - { - request_state *req = question->QuestionContext; - reply_state *rep; - mStatus err; - (void)m; // Unused - LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s", - req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer)); - - err = gen_rr_response(&answer->rdata->u.name, answer->InterfaceID, req, &rep); - if (err) - { - if (deliver_async_error(req, browse_reply, err) < 0) - { - abort_request(req); - unlink_request(req); - } - return; - } - if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd); // non-zero TTL indicates add - append_reply(req, rep); - return; - } - -static void browse_termination_callback(void *context) +mDNSlocal void browse_termination_callback(void *context) { browser_info_t *info = context; browser_t *ptr; @@ -2108,7 +2254,7 @@ mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port) return(count); } -static mStatus register_service_instance(request_state *request, const domainname *domain) +mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain) { service_info *info = request->service_registration; service_instance *ptr, *instance; @@ -2193,7 +2339,7 @@ mDNSexport void udsserver_default_reg_domain_changed(const domainname *d, mDNSBo } // service registration -static void handle_regservice_request(request_state *request) +mDNSlocal void handle_regservice_request(request_state *request) { DNSServiceFlags flags; uint32_t ifi; @@ -2246,7 +2392,7 @@ static void handle_regservice_request(request_state *request) if (!service->txtdata) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; } memcpy(service->txtdata, get_rdata(&ptr, service->txtlen), service->txtlen); } - else service->txtdata = NULL; + else service->txtdata = NULL; // Check for sub-types after the service type service->num_subtypes = ChopSubTypes(service->type_as_string); // Note: Modifies regtype string to remove trailing subtypes @@ -2342,7 +2488,7 @@ bad_param: // handles name conflicts, and delivers completed registration information to the client (via // process_service_registraion()) -static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result) +mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result) { mStatus err; mDNSBool SuppressError = mDNSfalse; @@ -2356,7 +2502,7 @@ static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mSta service_info *info = instance->request->service_registration; if (info->default_domain && !instance->default_local) SuppressError = mDNStrue; // don't send errors up to client for wide-area, empty-string registrations - } + } if (result == mStatus_NoError) LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED ", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port)); @@ -2369,6 +2515,7 @@ static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mSta if (result == mStatus_NoError) { + request_state *req = instance->request; if (instance->allowremotequery) { ExtraResourceRecord *e; @@ -2378,7 +2525,22 @@ static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mSta srs->RR_TXT.AllowRemoteQuery = mDNStrue; for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue; } - process_service_registration(srs, SuppressError); + + if (!req) LogMsg("ERROR: regservice_callback - null request object"); + else + { + reply_state *rep; + if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep) != mStatus_NoError) + LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", req->sd, srs->RR_SRV.resrec.name->c); + else + { + transfer_state send_result = send_msg(rep); + if (send_result == t_error || send_result == t_terminated) + { abort_request(req); unlink_request(req); freeL("reply_state", rep); } + else if (send_result == t_complete) freeL("regservice_callback", rep); + else append_reply(req, rep); + } + } if (instance->autoname && CountPeerRegistrations(m, srs) == 0) RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately return; @@ -2453,7 +2615,7 @@ mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result) freeL("ExtraResourceRecord", extra); } -static mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl) +mDNSlocal mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl) { ServiceRecordSet *srs = &instance->srs; ExtraResourceRecord *extra; @@ -2483,7 +2645,7 @@ static mStatus add_record_to_service(request_state *rstate, service_instance *in return result; } -static mStatus handle_add_request(request_state *rstate) +mDNSlocal mStatus handle_add_request(request_state *rstate) { uint32_t ttl; uint16_t rrtype, rdlen; @@ -2517,7 +2679,7 @@ static mStatus handle_add_request(request_state *rstate) return(result); } -static mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl) +mDNSlocal mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl) { int rdsize; RData *newrd; @@ -2540,7 +2702,7 @@ static mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32 return result; } -static mStatus handle_update_request(request_state *rstate) +mDNSlocal mStatus handle_update_request(request_state *rstate) { uint16_t rdlen; char *ptr, *rdata; @@ -2599,43 +2761,13 @@ end: return(result); } -static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd) +mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd) { (void)m; // Unused if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd); } - -static void process_service_registration(ServiceRecordSet *const srs, mDNSBool SuppressError) - { - reply_state *rep; - transfer_state send_result; - mStatus err; - service_instance *instance = srs->ServiceContext; - request_state *req = instance->request; - - if (!req) { LogMsg("ERROR: process_service_registration - null request object"); return; } - err = gen_rr_response(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep); - if (err) - { - if (SuppressError && deliver_async_error(req, reg_service_reply, err) < 0) - { - abort_request(req); - unlink_request(req); - } - return; - } - send_result = send_msg(rep); - if (send_result == t_error || send_result == t_terminated) - { - abort_request(req); - unlink_request(req); - freeL("process_service_registration", rep); - } - else if (send_result == t_complete) freeL("process_service_registration", rep); - else append_reply(req, rep); - } -static void free_service_instance(service_instance *srv) +mDNSlocal void free_service_instance(service_instance *srv) { request_state *rstate = srv->request; ExtraResourceRecord *e = srv->srs.Extras, *tmp; @@ -2669,7 +2801,7 @@ static void free_service_instance(service_instance *srv) freeL("regservice_callback", srv); } -static void regservice_termination_callback(void *context) +mDNSlocal void regservice_termination_callback(void *context) { service_info *info = context; service_instance *i, *p; @@ -2690,7 +2822,7 @@ static void regservice_termination_callback(void *context) freeL("service_info", info); } -static mStatus handle_regrecord_request(request_state *rstate) +mDNSlocal mStatus handle_regrecord_request(request_state *rstate) { AuthRecord *rr; registered_record_entry *re; @@ -2733,7 +2865,7 @@ static mStatus handle_regrecord_request(request_state *rstate) return(result); } -static void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result) +mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result) { registered_record_entry *re = rr->RecordContext; request_state *rstate = re ? re->rstate : NULL; @@ -2785,7 +2917,7 @@ static void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result) else if (ts == t_morecoming) append_reply(rstate, reply); // client is blocked, link reply into list } -static void connected_registration_termination(void *context) +mDNSlocal void connected_registration_termination(void *context) { int shared; registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs; @@ -2800,7 +2932,7 @@ static void connected_registration_termination(void *context) } } -static mStatus handle_removerecord_request(request_state *rstate) +mDNSlocal mStatus handle_removerecord_request(request_state *rstate) { mStatus err = mStatus_BadReferenceErr; char *ptr; @@ -2828,7 +2960,7 @@ static mStatus handle_removerecord_request(request_state *rstate) } // remove a resource record registered via DNSServiceRegisterRecord() -static mStatus remove_record(request_state *rstate) +mDNSlocal mStatus remove_record(request_state *rstate) { int shared; mStatus err = mStatus_UnknownErr; @@ -2852,7 +2984,7 @@ static mStatus remove_record(request_state *rstate) return err; } -static mStatus remove_extra(request_state *rstate, service_instance *serv) +mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv) { mStatus err = mStatus_BadReferenceErr; ExtraResourceRecord *ptr; @@ -2866,7 +2998,7 @@ static mStatus remove_extra(request_state *rstate, service_instance *serv) } // domain enumeration -static void handle_enum_request(request_state *rstate) +mDNSlocal void handle_enum_request(request_state *rstate) { DNSServiceFlags flags; uint32_t ifi; @@ -2902,6 +3034,10 @@ static void handle_enum_request(request_state *rstate) term = mallocL("handle_enum_request", sizeof(enum_termination_t)); if (!def || !all || !term) FatalError("ERROR: malloc"); +#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS) + dDNS_RegisterSearchDomains( gmDNS ); +#endif + // enumeration requires multiple questions, so we must link all the context pointers so that // necessary context can be reached from the callbacks def->rstate = rstate; @@ -2938,7 +3074,7 @@ static void handle_enum_request(request_state *rstate) } } -static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) { char domain[MAX_ESCAPED_DOMAIN_NAME]; domain_enum_t *de = question->QuestionContext; @@ -2954,7 +3090,7 @@ static void enum_result_callback(mDNS *const m, DNSQuestion *question, const Res flags |= kDNSServiceFlagsAdd; if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault) flags |= kDNSServiceFlagsDefault; - } + } ConvertDomainNameToCString(&answer->rdata->u.name, domain); // note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the @@ -2970,18 +3106,17 @@ static void enum_result_callback(mDNS *const m, DNSQuestion *question, const Res return; } -static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err) +mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err) { size_t len; reply_state *reply; char *data; - - + len = sizeof(DNSServiceFlags); len += sizeof(uint32_t); len += sizeof(DNSServiceErrorType); len += strlen(domain) + 1; - + reply = create_reply(enumeration_reply, len, rstate); reply->rhdr->flags = dnssd_htonl(flags); reply->rhdr->ifi = dnssd_htonl(ifi); @@ -2991,7 +3126,7 @@ static reply_state *format_enumeration_reply(request_state *rstate, const char * return reply; } -static void enum_termination_callback(void *context) +mDNSlocal void enum_termination_callback(void *context) { enum_termination_t *t = context; mDNS *coredata = gmDNS; @@ -3004,21 +3139,27 @@ static void enum_termination_callback(void *context) freeL("enum_termination_callback", t); } -static void handle_reconfirm_request(request_state *rstate) +mDNSlocal void handle_reconfirm_request(request_state *rstate) { - AuthRecord *rr; - - rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 1); - if (!rr) return; - LogOperation("%3d: DNSServiceReconfirmRecord(%##s) %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec)); - mDNS_ReconfirmByValue(gmDNS, &rr->resrec); - abort_request(rstate); - unlink_request(rstate); - freeL("handle_reconfirm_request", rr); - } + AuthRecord *rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 0); + if (rr) + { + mStatus status = mDNS_ReconfirmByValue(gmDNS, &rr->resrec); + LogOperation( + (status == mStatus_NoError) ? + "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" : + "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d", + rstate->sd, RRDisplayString(gmDNS, &rr->resrec), + mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID), status); + status = 0; // Adding this line eliminates a build failure when building mDNSPosix on Tiger + } + abort_request(rstate); + unlink_request(rstate); + freeL("handle_reconfirm_request", rr); + } // setup rstate to accept new reg/dereg requests -static void reset_connected_rstate(request_state *rstate) +mDNSlocal void reset_connected_rstate(request_state *rstate) { rstate->ts = t_morecoming; rstate->hdr_bytes = 0; @@ -3031,7 +3172,7 @@ static void reset_connected_rstate(request_state *rstate) // returns a resource record (allocated w/ malloc) containing the data found in an IPC message // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error -static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags) +mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags) { char *rdata, name[256]; AuthRecord *rr; @@ -3075,65 +3216,20 @@ static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_f freeL("read_rr_from_ipc_msg", rr); return NULL; } + if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue; rr->resrec.rrclass = class; rr->resrec.rdlength = rdlen; rr->resrec.rdata->MaxRDLength = rdlen; rdata = get_rdata(&msgbuf, rdlen); memcpy(rr->resrec.rdata->u.data, rdata, rdlen); - if (GetTTL) - { - rr->resrec.rroriginalttl = get_long(&msgbuf); - } + if (GetTTL) rr->resrec.rroriginalttl = get_long(&msgbuf); + rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); + SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us return rr; } -// generate a response message for a browse result, service registration result, or any other call with the -// identical callback signature. on successful completion rep is set to point to a malloc'd reply_state struct, -// and mStatus_NoError is returned. otherwise the appropriate error is returned. - -static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep) - { - char *data; - int len; - domainlabel name; - domainname type, dom; - char namestr[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL. - char typestr[MAX_ESCAPED_DOMAIN_NAME]; - char domstr [MAX_ESCAPED_DOMAIN_NAME]; - - *rep = NULL; - - if (!DeconstructServiceName(servicename, &name, &type, &dom)) - return kDNSServiceErr_Unknown; - - ConvertDomainLabelToCString_unescaped(&name, namestr); - ConvertDomainNameToCString(&type, typestr); - ConvertDomainNameToCString(&dom, domstr); - - // calculate reply data length - len = sizeof(DNSServiceFlags); - len += sizeof(uint32_t); // if index - len += sizeof(DNSServiceErrorType); - len += (int) (strlen(namestr) + 1); - len += (int) (strlen(typestr) + 1); - len += (int) (strlen(domstr) + 1); - - *rep = create_reply(query_reply, len, request); - - (*rep)->rhdr->flags = dnssd_htonl(0); - (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id)); - (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError); - - data = (*rep)->sdata; - - put_string(namestr, &data); - put_string(typestr, &data); - put_string(domstr, &data); - return mStatus_NoError; - } - -static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain) +mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain) { domainlabel n; domainname d, t; @@ -3146,7 +3242,7 @@ static int build_domainname_from_strings(domainname *srv, char *name, char *regt } // append a reply to the list in a request object -static void append_reply(request_state *req, reply_state *rep) +mDNSlocal void append_reply(request_state *req, reply_state *rep) { reply_state *ptr; @@ -3163,7 +3259,7 @@ static void append_reply(request_state *req, reply_state *rep) // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming. // returns the current state of the request (morecoming, error, complete, terminated.) // if there is no data on the socket, the socket will be closed and t_terminated will be returned -static int read_msg(request_state *rs) +mDNSlocal int read_msg(request_state *rs) { uint32_t nleft; int nread; @@ -3238,8 +3334,8 @@ static int read_msg(request_state *rs) return t_error; } rs->msgdata = rs->msgbuf; - } bzero(rs->msgbuf, rs->hdr.datalen + MSG_PAD_BYTES); + } nleft = rs->hdr.datalen - rs->data_bytes; nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0); if (nread == 0) { rs->ts = t_terminated; return t_terminated; } @@ -3266,7 +3362,7 @@ rerror: return t_error; } -static int send_msg(reply_state *rs) +mDNSlocal int send_msg(reply_state *rs) { ssize_t nwriten; @@ -3318,12 +3414,11 @@ static int send_msg(reply_state *rs) return rs->ts; } -static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request) -{ +mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request) + { reply_state *reply; int totallen; - if ((unsigned)datalen < sizeof(reply_hdr)) { LogMsg("ERROR: create_reply - data length less than lenght of required fields"); @@ -3350,7 +3445,7 @@ static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *r return reply; } -static int deliver_error(request_state *rstate, mStatus err) +mDNSlocal int deliver_error(request_state *rstate, mStatus err) { int nwritten = -1; undelivered_error_t *undeliv; @@ -3382,7 +3477,7 @@ static int deliver_error(request_state *rstate, mStatus err) } // returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted) -static transfer_state send_undelivered_error(request_state *rs) +mDNSlocal transfer_state send_undelivered_error(request_state *rs) { int nwritten; @@ -3410,7 +3505,7 @@ static transfer_state send_undelivered_error(request_state *rs) // send bogus data along with an error code to the app callback // returns 0 on success (linking reply into list of not fully delivered), // -1 on failure (request should be aborted) -static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err) +mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err) { int len; reply_state *reply; @@ -3431,7 +3526,7 @@ static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err) return 0; } -static void abort_request(request_state *rs) +mDNSlocal void abort_request(request_state *rs) { reply_state *rep, *ptr; @@ -3439,7 +3534,10 @@ static void abort_request(request_state *rs) if (rs->msgbuf) freeL("abort_request", rs->msgbuf); LogOperation("%3d: Removing FD", rs->sd); udsSupportRemoveFDFromEventLoop(rs->sd); // Note: This also closes file descriptor rs->sd for us - rs->sd = dnssd_InvalidSocket; + + // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses + // for detecting when the memory for an object is inadvertently freed while the object is still on some list + rs->sd = -2; // free pending replies rep = rs->replies; @@ -3458,7 +3556,7 @@ static void abort_request(request_state *rs) } } -static void unlink_request(request_state *rs) +mDNSlocal void unlink_request(request_state *rs) { request_state *ptr; @@ -3478,7 +3576,7 @@ static void unlink_request(request_state *rs) } //hack to search-replace perror's to LogMsg's -static void my_perror(char *errmsg) +mDNSlocal void my_perror(char *errmsg) { LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno())); } @@ -3487,7 +3585,7 @@ static void my_perror(char *errmsg) // without overrunning it. // returns 0 on success, -1 on error. -static int validate_message(request_state *rstate) +mDNSlocal int validate_message(request_state *rstate) { uint32_t min_size; @@ -3546,7 +3644,7 @@ static int validate_message(request_state *rstate) } -static uint32_t dnssd_htonl(uint32_t l) +mDNSlocal uint32_t dnssd_htonl(uint32_t l) { uint32_t ret; char * data; @@ -3560,7 +3658,7 @@ static uint32_t dnssd_htonl(uint32_t l) #if defined(_WIN32) -static char * win32_strerror(int inErrorCode) +mDNSlocal char * win32_strerror(int inErrorCode) { static char buffer[1024]; DWORD n; diff --git a/mDNSVxWorks/mDNSVxWorksIPv4Only.c b/mDNSVxWorks/mDNSVxWorksIPv4Only.c index d8c2824..3b2926a 100644 --- a/mDNSVxWorks/mDNSVxWorksIPv4Only.c +++ b/mDNSVxWorks/mDNSVxWorksIPv4Only.c @@ -65,7 +65,7 @@ Convert ServiceRegDomain to domainname instead of C string Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs Revision 1.17 2004/07/29 19:26:03 ksekar -Plaform-level changes for NATPMP support +Plaform-level changes for NAT-PMP support Revision 1.16 2004/04/22 05:11:28 bradley Added mDNSPlatformUTC for TSIG signed dynamic updates. diff --git a/mDNSWindows/mDNSWin32.c b/mDNSWindows/mDNSWin32.c index 93a14a7..50df66f 100755 --- a/mDNSWindows/mDNSWin32.c +++ b/mDNSWindows/mDNSWin32.c @@ -222,7 +222,7 @@ Revision 1.46 2004/08/05 05:43:01 shersche Bug #: 3751566 Revision 1.45 2004/07/26 22:49:31 ksekar -: Feature #9516: Need support for NATPMP in client +: Feature #9516: Need support for NAT-PMP in client Revision 1.44 2004/07/26 05:42:50 shersche use "Computer Description" for nicename if available, track dynamic changes to "Computer Description"