From 030b743d04071f8345b376fca3677ecaddb166c6 Mon Sep 17 00:00:00 2001 From: Apple Date: Sat, 5 Jan 2008 00:13:11 +0000 Subject: [PATCH] mDNSResponder-170.tar.gz --- Clients/dns-sd.c | 69 +- Makefile | 2 +- mDNSCore/DNSCommon.c | 191 +++--- mDNSCore/DNSCommon.h | 50 +- mDNSCore/DNSDigest.c | 18 +- mDNSCore/mDNS.c | 622 +++++++++++------- mDNSCore/mDNSDebug.h | 45 +- mDNSCore/mDNSEmbeddedAPI.h | 145 +++- mDNSCore/uDNS.c | 468 +++++++------ mDNSCore/uDNS.h | 10 +- mDNSMacOSX/LegacyNATTraversal.c | 9 + .../PreferencePane/DNSServiceDiscoveryPref.m | 9 +- .../PreferencePane/PrivilegedOperations.c | 4 +- mDNSMacOSX/PreferencePane/ddnswriteconfig.m | 13 +- mDNSMacOSX/SamplemDNSClient.c | 25 +- mDNSMacOSX/daemon.c | 165 +++-- mDNSMacOSX/helper-error.h | 5 + mDNSMacOSX/helper-stubs.c | 8 +- mDNSMacOSX/helper.c | 77 ++- mDNSMacOSX/mDNSMacOSX.c | 523 +++++++++------ mDNSMacOSX/mDNSMacOSX.h | 7 +- .../mDNSResponder.xcodeproj/project.pbxproj | 60 +- mDNSMacOSX/pfkey.c | 5 + mDNSPosix/mDNSUNP.c | 5 +- mDNSShared/Java/JNISupport.c | 11 +- mDNSShared/PlatformCommon.c | 28 + mDNSShared/dns_sd.h | 34 +- mDNSShared/dnsextd.c | 47 +- mDNSShared/dnssd_clientlib.c | 7 +- mDNSShared/dnssd_clientshim.c | 5 +- mDNSShared/dnssd_clientstub.c | 85 ++- mDNSShared/mDNSDebug.c | 45 +- mDNSShared/uds_daemon.c | 64 +- mDNSWindows/mDNSWin32.c | 5 +- 34 files changed, 1839 insertions(+), 1027 deletions(-) diff --git a/Clients/dns-sd.c b/Clients/dns-sd.c index 718547c..e80ee39 100644 --- a/Clients/dns-sd.c +++ b/Clients/dns-sd.c @@ -433,6 +433,7 @@ static void myTimerCallBack(void) else updatetest[1] = 'A'; updatetest[0] = 3 - updatetest[0]; updatetest[2] = updatetest[1]; + printtimestamp(); printf("Updating Test TXT record to %c\n", updatetest[1]); err = DNSServiceUpdateRecord(client, NULL, 0, 1+updatetest[0], &updatetest[0], 0); } @@ -689,19 +690,19 @@ static int getfirstoption(int argc, char **argv, const char *optstr, int *pOptIn } #else { - int operation = getopt(argc, (char *const *)argv, optstr); + int o = getopt(argc, (char *const *)argv, optstr); *pOptInd = optind; - return operation; + return o; } #endif -static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordRef record, const DNSServiceFlags flags, +static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordRef rec, const DNSServiceFlags flags, DNSServiceErrorType errorCode, void *context) { char *name = (char *)context; (void)service; // Unused - (void)record; // Unused + (void)rec; // Unused (void)flags; // Unused printtimestamp(); @@ -714,7 +715,7 @@ static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordR default: printf("Error %d\n", errorCode); break; } if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout); - // DNSServiceRemoveRecord(service, record, 0); to test record removal + // DNSServiceRemoveRecord(service, rec, 0); to test record removal } static unsigned long getip(const char *const name) @@ -811,7 +812,7 @@ int main(int argc, char **argv) { DNSServiceErrorType err; char buffer[TypeBufferSize], *typ, *dom; - int optind; + int opi; // Extract the program name from argv[0], which by convention contains the path to this executable. // Note that this is just a voluntary convention, not enforced by the kernel -- @@ -852,7 +853,7 @@ int main(int argc, char **argv) #if HAS_ADDRINFO_API "G" #endif - , &optind); + , &opi); if (operation == -1) goto Fail; if (opinterface) printf("Using interface %d\n", opinterface); @@ -871,38 +872,38 @@ int main(int argc, char **argv) //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "dns-sd.ibm.com.", NULL); break; - case 'B': typ = (argc < optind+1) ? "" : argv[optind+0]; - dom = (argc < optind+2) ? "" : argv[optind+1]; // Missing domain argument is the same as empty string i.e. use system default(s) + case 'B': typ = (argc < opi+1) ? "" : argv[opi+0]; + dom = (argc < opi+2) ? "" : argv[opi+1]; // Missing domain argument is the same as empty string i.e. use system default(s) typ = gettype(buffer, typ); if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string printf("Browsing for %s%s%s\n", typ, dom[0] ? "." : "", dom); err = DNSServiceBrowse(&client, 0, opinterface, typ, dom, browse_reply, NULL); break; - case 'L': if (argc < optind+2) goto Fail; - typ = (argc < optind+2) ? "" : argv[optind+1]; - dom = (argc < optind+3) ? "local" : argv[optind+2]; + case 'L': if (argc < opi+2) goto Fail; + typ = (argc < opi+2) ? "" : argv[opi+1]; + dom = (argc < opi+3) ? "local" : argv[opi+2]; typ = gettype(buffer, typ); if (dom[0] == '.' && dom[1] == 0) dom = "local"; // We allow '.' on the command line as a synonym for "local" - printf("Lookup %s.%s.%s\n", argv[optind+0], typ, dom); - err = DNSServiceResolve(&client, 0, opinterface, argv[optind+0], typ, dom, (DNSServiceResolveReply)resolve_reply, NULL); + printf("Lookup %s.%s.%s\n", argv[opi+0], typ, dom); + err = DNSServiceResolve(&client, 0, opinterface, argv[opi+0], typ, dom, (DNSServiceResolveReply)resolve_reply, NULL); break; - case 'R': if (argc < optind+4) goto Fail; - typ = (argc < optind+2) ? "" : argv[optind+1]; - dom = (argc < optind+3) ? "" : argv[optind+2]; + case 'R': if (argc < opi+4) goto Fail; + typ = (argc < opi+2) ? "" : argv[opi+1]; + dom = (argc < opi+3) ? "" : argv[opi+2]; typ = gettype(buffer, typ); if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string - err = RegisterService(&client, argv[optind+0], typ, dom, NULL, argv[optind+3], argc-(optind+4), argv+(optind+4)); + err = RegisterService(&client, argv[opi+0], typ, dom, NULL, argv[opi+3], argc-(opi+4), argv+(opi+4)); break; - case 'P': if (argc < optind+6) goto Fail; + case 'P': if (argc < opi+6) goto Fail; err = DNSServiceCreateConnection(&client_pa); if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); } - err = RegisterProxyAddressRecord(client_pa, argv[optind+4], argv[optind+5]); - //err = RegisterProxyAddressRecord(client_pa, "two", argv[optind+5]); + err = RegisterProxyAddressRecord(client_pa, argv[opi+4], argv[opi+5]); + //err = RegisterProxyAddressRecord(client_pa, "two", argv[opi+5]); if (err) break; - err = RegisterService(&client, argv[optind+0], argv[optind+1], argv[optind+2], argv[optind+4], argv[optind+3], argc-(optind+6), argv+(optind+6)); + err = RegisterService(&client, argv[opi+0], argv[opi+1], argv[opi+2], argv[opi+4], argv[opi+3], argc-(opi+6), argv+(opi+6)); //DNSServiceRemoveRecord(client_pa, record, 0); //DNSServiceRemoveRecord(client_pa, record, 0); break; @@ -911,11 +912,11 @@ int main(int argc, char **argv) case 'C': { uint16_t rrtype, rrclass; DNSServiceFlags flags = kDNSServiceFlagsReturnIntermediates; - if (argc < optind+1) goto Fail; - rrtype = (argc <= optind+1) ? kDNSServiceType_A : GetRRType(argv[optind+1]); - rrclass = (argc <= optind+2) ? kDNSServiceClass_IN : atoi(argv[optind+2]); + if (argc < opi+1) goto Fail; + rrtype = (argc <= opi+1) ? kDNSServiceType_A : GetRRType(argv[opi+1]); + rrclass = (argc <= opi+2) ? kDNSServiceClass_IN : atoi(argv[opi+2]); if (rrtype == kDNSServiceType_TXT || rrtype == kDNSServiceType_PTR) flags |= kDNSServiceFlagsLongLivedQuery; - err = DNSServiceQueryRecord(&client, flags, opinterface, argv[optind+0], rrtype, rrclass, qr_reply, NULL); + err = DNSServiceQueryRecord(&client, flags, opinterface, argv[opi+0], rrtype, rrclass, qr_reply, NULL); break; } @@ -963,14 +964,14 @@ int main(int argc, char **argv) #if HAS_NAT_PMP_API case 'X': { - if (argc == optind) // If no arguments, just fetch IP address + if (argc == opi) // If no arguments, just fetch IP address err = DNSServiceNATPortMappingCreate(&client, 0, 0, 0, 0, 0, 0, port_mapping_create_reply, NULL); - else if (argc >= optind+2 && atoi(argv[optind+0]) == 0) + else if (argc >= opi+2 && atoi(argv[opi+0]) == 0) { - DNSServiceProtocol prot = GetProtocol(argv[optind+0]); // Must specify TCP or UDP - uint16_t IntPortAsNumber = atoi(argv[optind+1]); // Must specify internal port - uint16_t ExtPortAsNumber = (argc < optind+3) ? 0 : atoi(argv[optind+2]); // Optional desired external port - uint32_t ttl = (argc < optind+4) ? 0 : atoi(argv[optind+3]); // Optional desired lease lifetime + DNSServiceProtocol prot = GetProtocol(argv[opi+0]); // Must specify TCP or UDP + uint16_t IntPortAsNumber = atoi(argv[opi+1]); // Must specify internal port + uint16_t ExtPortAsNumber = (argc < opi+3) ? 0 : atoi(argv[opi+2]); // Optional desired external port + uint32_t ttl = (argc < opi+4) ? 0 : atoi(argv[opi+3]); // Optional desired lease lifetime Opaque16 intp = { { IntPortAsNumber >> 8, IntPortAsNumber & 0xFF } }; Opaque16 extp = { { ExtPortAsNumber >> 8, ExtPortAsNumber & 0xFF } }; err = DNSServiceNATPortMappingCreate(&client, 0, 0, prot, intp.NotAnInteger, extp.NotAnInteger, ttl, port_mapping_create_reply, NULL); @@ -982,8 +983,8 @@ int main(int argc, char **argv) #if HAS_ADDRINFO_API case 'G': { - if (argc != optind+2) goto Fail; - else err = DNSServiceGetAddrInfo(&client, kDNSServiceFlagsReturnIntermediates, opinterface, GetProtocol(argv[optind+0]), argv[optind+1], addrinfo_reply, NULL); + if (argc != opi+2) goto Fail; + else err = DNSServiceGetAddrInfo(&client, kDNSServiceFlagsReturnIntermediates, opinterface, GetProtocol(argv[opi+0]), argv[opi+1], addrinfo_reply, NULL); break; } #endif diff --git a/Makefile b/Makefile index d774618..c6aca02 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ include /Developer/Makefiles/pb_makefiles/platform.make -MVERS = "mDNSResponder-164" +MVERS = "mDNSResponder-170" DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig" diff --git a/mDNSCore/DNSCommon.c b/mDNSCore/DNSCommon.c index 01e063a..7c17df6 100644 --- a/mDNSCore/DNSCommon.c +++ b/mDNSCore/DNSCommon.c @@ -17,6 +17,37 @@ Change History (most recent first): $Log: DNSCommon.c,v $ +Revision 1.193 2007/12/17 23:42:36 cheshire +Added comments about DNSDigest_SignMessage() + +Revision 1.192 2007/12/17 21:24:09 cheshire + BTMM: Need to deregister records and services on shutdown/sleep +We suspend sending of mDNS queries responses when going to sleep, so calculate GetNextScheduledEvent() time accordingly + +Revision 1.191 2007/12/14 00:59:36 cheshire + BTMM: Need to deregister records and services on shutdown/sleep +While going to sleep, don't block event scheduling + +Revision 1.190 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.189 2007/12/13 00:17:32 cheshire +RDataHashValue was not calculating hash value reliably for RDATA types that have 'holes' in the +in-memory representation (particularly SOA was affected by this, resulting in multiple duplicate +cache entities for the same SOA record, because they had erroneously different rdatahash values). + +Revision 1.188 2007/12/13 00:13:03 cheshire +Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody + +Revision 1.187 2007/12/08 00:35:20 cheshire + Updating TXT records is too slow +m->SuppressSending should not suppress all activity, just mDNS Query/Probe/Response + +Revision 1.186 2007/11/15 22:52:29 cheshire + ERROR: mDNSPlatformWriteTCP - send Broken pipe + Revision 1.185 2007/10/10 20:22:03 cheshire Added sanity checks in mDNSSendDNSMessage -- we've seen crashes in DNSDigest_SignMessage apparently caused by trying to sign zero-length messages @@ -1273,20 +1304,52 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD rr->namestorage.c[0] = 0; // MUST be set by client before calling mDNS_Register() } -mDNSexport mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb) +mDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr) { - mDNSu32 sum = 0; - int i; - for (i=0; i+1 < rdlength; i+=2) - { - sum += (((mDNSu32)(rdb->data[i])) << 8) | rdb->data[i+1]; - sum = (sum<<3) | (sum>>29); - } - if (i < rdlength) + switch(rr->rrtype) { - sum += ((mDNSu32)(rdb->data[i])) << 8; + case kDNSType_NS: + case kDNSType_CNAME: + case kDNSType_PTR: + case kDNSType_DNAME: return DomainNameHashValue(&rr->rdata->u.name); + + case kDNSType_SOA: return rr->rdata->u.soa.serial + + rr->rdata->u.soa.refresh + + rr->rdata->u.soa.retry + + rr->rdata->u.soa.expire + + rr->rdata->u.soa.min + + DomainNameHashValue(&rr->rdata->u.soa.mname) + + DomainNameHashValue(&rr->rdata->u.soa.rname); + + case kDNSType_MX: + case kDNSType_AFSDB: + case kDNSType_RT: + case kDNSType_KX: return DomainNameHashValue(&rr->rdata->u.mx.exchange); + + case kDNSType_RP: return DomainNameHashValue(&rr->rdata->u.rp.mbox) + DomainNameHashValue(&rr->rdata->u.rp.txt); + + case kDNSType_PX: return DomainNameHashValue(&rr->rdata->u.px.map822) + DomainNameHashValue(&rr->rdata->u.px.mapx400); + + case kDNSType_SRV: return DomainNameHashValue(&rr->rdata->u.srv.target); + + case kDNSType_OPT: // Okay to use blind memory sum because there are no 'holes' in the in-memory representation + + default: + { + mDNSu32 sum = 0; + int i; + for (i=0; i+1 < rr->rdlength; i+=2) + { + sum += (((mDNSu32)(rr->rdata->u.data[i])) << 8) | rr->rdata->u.data[i+1]; + sum = (sum<<3) | (sum>>29); + } + if (i < rr->rdlength) + { + sum += ((mDNSu32)(rr->rdata->u.data[i])) << 8; + } + return(sum); + } } - return(sum); } // r1 has to be a full ResourceRecord including rrtype and rdlength @@ -1326,28 +1389,12 @@ mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBod mDNSSameIPPort(r1->rdata->u.srv.port, r2->srv.port) && SameDomainName(&r1->rdata->u.srv.target, &r2->srv.target)); - case kDNSType_OPT: // Okay to use memory compare because there are no 'holes' in the in-memory representation + case kDNSType_OPT: // Okay to use blind memory compare because there are no 'holes' in the in-memory representation 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 && - r1->rrtype == r2->rrtype && - SameDomainName(r1->name, r2->name) && - SameRData(r1, r2)); - } - // ResourceRecordAnswersQuestion returns mDNStrue if the given resource record is a valid answer to the given question. // SameNameRecordAnswersQuestion is the same, except it skips the expensive SameDomainName() call. // SameDomainName() is generally cheap when the names don't match, but expensive when they do match, @@ -1368,14 +1415,6 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr if (rr->rrtype != kDNSType_CNAME && rr->rrtype != q->qtype && q->qtype != kDNSQType_ANY ) return(mDNSfalse); if ( rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); -#if VerifySameNameAssumptions - if (rr->namehash != q->qnamehash || !SameDomainName(rr->name, &q->qname)) - { - LogMsg("Bogus SameNameRecordAnswersQuestion call: RR %##s does not match Q %##s", rr->name->c, q->qname.c); - return(mDNSfalse); - } -#endif - return(mDNStrue); } @@ -2007,7 +2046,7 @@ mDNSexport void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 r target = GetRRDomainNameTarget(rr); rr->rdlength = GetRDLength(rr, mDNSfalse); rr->rdestimate = GetRDLength(rr, mDNStrue); - rr->rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(rr->rdlength, &rr->rdata->u); + rr->rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(rr); } mDNSexport const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end) @@ -2159,9 +2198,9 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c); - // IMPORTANT: Any record type we understand and unpack into a structure containing domainnames needs to have - // a corresponding case in SameRDataBody() to do a semantic comparison of the structure instead of a blind - // bitwise memory compare. This is because a domainname is a fixed size structure holding variable-length data. + // IMPORTANT: Any record type we understand and unpack into a structure containing domainnames needs to have corresponding + // cases in SameRDataBody() and RDataHashValue() to do a semantic comparison (or checksum) of the structure instead of a blind + // bitwise memory compare (or sum). This is because a domainname is a fixed size structure holding variable-length data. // Any bytes past the logical end of the name are undefined, and a blind bitwise memory compare may indicate that // two domainnames are different when semantically they are the same name and it's only the unused bytes that differ. if (rr->resrec.rrclass == kDNSQClass_ANY && pktrdlength == 0) // Used in update packets to mean "Delete An RRset" (RFC 2136) @@ -2486,13 +2525,12 @@ mDNSexport void DumpPacket(mDNS *const m, mDNSBool sent, char *transport, const // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.) struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ }; +// Note: When we sign a DNS message using DNSDigest_SignMessage(), the current real-time clock value is used, which +// is why we generally defer signing until we send the message, to ensure the signature is as fresh as possible. mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end, mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo) { - mStatus status; - long nsent; - unsigned long msglen; - mDNSu8 lenbuf[2]; + mStatus status = mStatus_NoError; mDNSu16 numQuestions = msg->h.numQuestions; mDNSu16 numAnswers = msg->h.numAnswers; mDNSu16 numAuthorities = msg->h.numAuthorities; @@ -2515,30 +2553,25 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS *ptr++ = (mDNSu8)(numAdditionals >> 8); *ptr++ = (mDNSu8)(numAdditionals & 0xFF); - if (authInfo) - { - end = DNSDigest_SignMessage(msg, &end, authInfo, 0); - if (!end) return mStatus_UnknownErr; - } - - // Send the packet on the wire - if (sock) - { - msglen = (mDNSu16)(end - (mDNSu8 *)msg); - lenbuf[0] = (mDNSu8)(msglen >> 8); // host->network byte conversion - lenbuf[1] = (mDNSu8)(msglen & 0xFF); - - nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2); - //!!!KRS make sure kernel is sending these as 1 packet! - if (nsent != 2) goto tcp_error; - - nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen); - if (nsent != (long)msglen) goto tcp_error; - status = mStatus_NoError; - } + if (authInfo) DNSDigest_SignMessage(msg, &end, authInfo, 0); // DNSDigest_SignMessage operates on message in network byte order + if (!end) { LogMsg("mDNSSendDNSMessage: DNSDigest_SignMessage failed"); status = mStatus_NoMemoryErr; } else { - status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, dst, dstport); + // Send the packet on the wire + if (!sock) + status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, dst, dstport); + else + { + mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg); + mDNSu8 lenbuf[2] = { (mDNSu8)(msglen >> 8), (mDNSu8)(msglen & 0xFF) }; + long nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2); // Should do scatter/gather here -- this is probably going out as two packets + if (nsent != 2) { LogMsg("mDNSSendDNSMessage: write msg length failed %d/%d", nsent, 2); status = mStatus_ConnFailed; } + else + { + nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen); + if (nsent != msglen) { LogMsg("mDNSSendDNSMessage: write msg body failed %d/%d", nsent, msglen); status = mStatus_ConnFailed; } + } + } } // Put all the integer values back the way they were before we return @@ -2555,10 +2588,6 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS } return(status); - - tcp_error: - LogMsg("mDNSSendDNSMessage: error sending message over tcp"); - return mStatus_UnknownErr; } // *************************************************************************** @@ -2615,7 +2644,7 @@ mDNSexport void mDNS_Lock_(mDNS *const m) mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m) { mDNSs32 e = m->timenow + 0x78000000; - if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) return(e); + if (m->mDNSPlatformStatus != mStatus_NoError) return(e); if (m->NewQuestions) { if (m->NewQuestions->DelayAnswering) e = m->NewQuestions->DelayAnswering; @@ -2623,15 +2652,25 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m) } if (m->NewLocalOnlyQuestions) return(m->timenow); if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) return(m->timenow); - if (m->SuppressSending) return(m->SuppressSending); #ifndef UNICAST_DISABLED if (e - m->NextuDNSEvent > 0) e = m->NextuDNSEvent; + if (e - m->NextScheduledNATOp > 0) e = m->NextScheduledNATOp; #endif if (e - m->NextCacheCheck > 0) e = m->NextCacheCheck; - if (e - m->NextScheduledQuery > 0) e = m->NextScheduledQuery; - if (e - m->NextScheduledProbe > 0) e = m->NextScheduledProbe; - if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse; - if (e - m->NextScheduledNATOp > 0) e = m->NextScheduledNATOp; + + if (!m->SleepState) + { + if (m->SuppressSending) + { + if (e - m->SuppressSending > 0) e = m->SuppressSending; + } + else + { + if (e - m->NextScheduledQuery > 0) e = m->NextScheduledQuery; + if (e - m->NextScheduledProbe > 0) e = m->NextScheduledProbe; + if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse; + } + } return(e); } diff --git a/mDNSCore/DNSCommon.h b/mDNSCore/DNSCommon.h index 8479573..f186ac6 100644 --- a/mDNSCore/DNSCommon.h +++ b/mDNSCore/DNSCommon.h @@ -17,6 +17,17 @@ Change History (most recent first): $Log: DNSCommon.h,v $ +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 @@ -192,18 +203,47 @@ extern void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText) #pragma mark - Resource Record Utility Functions #endif -extern mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb); +// IdenticalResourceRecord returns true if two resources records have +// the same name, type, class, and identical rdata (InterfaceID and TTL may differ) + +// IdenticalSameNameRecord is the same, except it skips the expensive SameDomainName() check, +// which is at its most expensive and least useful in cases where we know in advance that the names match + +// Note: The dominant use of IdenticalResourceRecord is from ProcessQuery(), handling known-answer lists. In this case +// it's common to have a whole bunch or records with exactly the same name (e.g. "_http._tcp.local") but different RDATA. +// The SameDomainName() check is expensive when the names match, and in this case *all* the names match, so we +// used to waste a lot of CPU time verifying that the names match, only then to find that the RDATA is different. +// We observed mDNSResponder spending 30% of its total CPU time on this single task alone. +// By swapping the checks so that we check the RDATA first, we can quickly detect when it's different +// (99% of the time) and then bail out before we waste time on the expensive SameDomainName() check. + +#define IdenticalResourceRecord(r1,r2) ( \ + (r1)->rrtype == (r2)->rrtype && \ + (r1)->rrclass == (r2)->rrclass && \ + (r1)->namehash == (r2)->namehash && \ + (r1)->rdlength == (r2)->rdlength && \ + (r1)->rdatahash == (r2)->rdatahash && \ + SameRDataBody((r1), &(r2)->rdata->u) && \ + SameDomainName((r1)->name, (r2)->name)) + +#define IdenticalSameNameRecord(r1,r2) ( \ + (r1)->rrtype == (r2)->rrtype && \ + (r1)->rrclass == (r2)->rrclass && \ + (r1)->rdlength == (r2)->rdlength && \ + (r1)->rdatahash == (r2)->rdatahash && \ + SameRDataBody((r1), &(r2)->rdata->u)) + +extern mDNSu32 RDataHashValue(const ResourceRecord *const rr); extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2); -extern mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2); +#define SameRData(r1,r2) ((r1)->rrtype == (r2)->rrtype && (r1)->rdlength == (r2)->rdlength && (r1)->rdatahash == (r2)->rdatahash && SameRDataBody((r1), &(r2)->rdata->u)) extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q); extern mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q); -extern mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2); extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate); extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd); #define GetRRDomainNameTarget(RR) ( \ - ((RR)->rrtype == kDNSType_CNAME || (RR)->rrtype == kDNSType_PTR || (RR)->rrtype == kDNSType_NS) \ - ? &(RR)->rdata->u.name : \ + ((RR)->rrtype == kDNSType_NS || (RR)->rrtype == kDNSType_CNAME || (RR)->rrtype == kDNSType_PTR || (RR)->rrtype == kDNSType_DNAME) ? &(RR)->rdata->u.name : \ + ((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) diff --git a/mDNSCore/DNSDigest.c b/mDNSCore/DNSDigest.c index 809499b..09ff7c7 100644 --- a/mDNSCore/DNSDigest.c +++ b/mDNSCore/DNSDigest.c @@ -17,6 +17,12 @@ Change History (most recent first): $Log: DNSDigest.c,v $ +Revision 1.25 2007/12/17 23:48:29 cheshire +DNSDigest_SignMessage doesn't need to return a result -- it already updates the 'end' parameter + +Revision 1.24 2007/11/30 23:03:51 cheshire +Fixes for EFI: Use "mDNSPlatformMemCopy" instead of assuming existence of "memcpy" + Revision 1.23 2007/09/21 21:12:36 cheshire DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter @@ -810,7 +816,7 @@ int HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len) #if !defined(HASH_BLOCK_DATA_ORDER) while (sw--) { - memcpy (p=c->data,data,HASH_CBLOCK); + mDNSPlatformMemCopy(p=c->data,data,HASH_CBLOCK); HASH_BLOCK_DATA_ORDER_ALIGNED(c,p,1); data+=HASH_CBLOCK; len-=HASH_CBLOCK; @@ -853,7 +859,7 @@ void HASH_TRANSFORM (HASH_CTX *c, const unsigned char *data) else #if !defined(HASH_BLOCK_DATA_ORDER) { - memcpy (c->data,data,HASH_CBLOCK); + mDNSPlatformMemCopy(c->data,data,HASH_CBLOCK); HASH_BLOCK_DATA_ORDER_ALIGNED (c,c->data,1); } #endif @@ -1404,7 +1410,7 @@ mDNSexport mDNSs32 DNSDigest_ConstructHMACKeyfromBase64(DomainAuthInfo *info, co return(keylen); } -mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode) +mDNSexport void DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode) { AuthRecord tsig; mDNSu8 *rdata, *const countPtr = (mDNSu8 *)&msg->h.numAdditionals; // Get existing numAdditionals value @@ -1447,7 +1453,7 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAu // time // get UTC (universal time), convert to 48-bit unsigned in network byte order utc32 = (mDNSu32)mDNSPlatformUTC(); - if (utc32 == (unsigned)-1) { LogMsg("ERROR: DNSDigest_SignMessage - mDNSPlatformUTC returned bad time -1"); return mDNSNULL; } + if (utc32 == (unsigned)-1) { LogMsg("ERROR: DNSDigest_SignMessage - mDNSPlatformUTC returned bad time -1"); *end = mDNSNULL; } utc48[0] = 0; utc48[1] = 0; utc48[2] = (mDNSu8)((utc32 >> 24) & 0xff); @@ -1497,13 +1503,11 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAu tsig.resrec.rdlength = (mDNSu16)(rdata - tsig.resrec.rdata->u.data); *end = PutResourceRecordTTLJumbo(msg, ptr, &numAdditionals, &tsig.resrec, 0); - if (!*end) { LogMsg("ERROR: DNSDigest_SignMessage - could not put TSIG"); return mDNSNULL; } + if (!*end) { LogMsg("ERROR: DNSDigest_SignMessage - could not put TSIG"); *end = mDNSNULL; return; } // Write back updated numAdditionals value countPtr[0] = (mDNSu8)(numAdditionals >> 8); countPtr[1] = (mDNSu8)(numAdditionals & 0xFF); - - return *end; } mDNSexport mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCacheRecord * lcr, DomainAuthInfo *info, mDNSu16 * rcode, mDNSu16 * tcode) diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c index 854c656..2d4f110 100755 --- a/mDNSCore/mDNS.c +++ b/mDNSCore/mDNS.c @@ -38,6 +38,62 @@ Change History (most recent first): $Log: mDNS.c,v $ +Revision 1.767 2007/12/22 02:25:29 cheshire + Records and Services sometimes not re-registering on wake from sleep + +Revision 1.766 2007/12/15 01:12:27 cheshire + Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown + +Revision 1.765 2007/12/15 00:18:51 cheshire +Renamed question->origLease to question->ReqLease + +Revision 1.764 2007/12/14 00:49:53 cheshire +Fixed crash in mDNS_StartExit -- the service deregistration loop needs to use +the CurrentServiceRecordSet mechanism to guard against services being deleted, +just like the record deregistration loop uses m->CurrentRecord. + +Revision 1.763 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.762 2007/12/13 00:13:03 cheshire +Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody + +Revision 1.761 2007/12/13 00:03:31 cheshire +Improved efficiency in IdenticalResourceRecord() by doing SameRData() check before SameDomainName() check + +Revision 1.760 2007/12/08 00:36:19 cheshire + Updating TXT records is too slow +Remove unnecessary delays on announcing record updates, and on processing them on reception + +Revision 1.759 2007/12/07 22:41:29 cheshire + BTMM: Need to clean up registrations on shutdown +Further refinements -- records on the DuplicateRecords list were getting missed on shutdown + +Revision 1.758 2007/12/07 00:45:57 cheshire + BTMM: Need to clean up registrations on shutdown + +Revision 1.757 2007/12/06 00:22:27 mcguire + BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp) + +Revision 1.756 2007/12/05 01:52:30 cheshire + BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname +Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to) + +Revision 1.755 2007/12/03 23:36:45 cheshire + mDNSResponder unicast DNS improvements +Need to check GetServerForName() result is non-null before dereferencing pointer + +Revision 1.754 2007/12/01 01:21:27 jgraessley + mDNSResponder unicast DNS improvements + +Revision 1.753 2007/12/01 00:44:15 cheshire +Fixed compile warnings, e.g. declaration of 'rr' shadows a previous local + +Revision 1.752 2007/11/14 01:10:51 cheshire +Fixed LogOperation() message wording + Revision 1.751 2007/10/30 23:49:41 cheshire BTMM: Machines don't appear in the sidebar on wake from sleep LLQ state was not being transferred properly between duplicate questions @@ -893,7 +949,7 @@ mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID Int mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, QC_result AddRecord) { // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it - if (AddRecord) rr->LocalAnswer = mDNStrue; + if (AddRecord) rr->AnsweredLocalQ = mDNStrue; mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback if (q->QuestionCallback && !q->NoAnswer) q->QuestionCallback(m, q, &rr->resrec, AddRecord); @@ -1015,40 +1071,7 @@ mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, cons SameDomainName(pktrr->resrec.name, authrr->resrec.name)); } -// IdenticalResourceRecord returns true if two resources records have -// the same name, type, class, and identical rdata (InterfaceID and TTL may differ) - -// IdenticalSameNameRecord is the same, except it skips the expensive SameDomainName() check, -// which is at its most expensive and least useful in cases where we know in advance that the names match - -mDNSlocal mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const ResourceRecord *const r2) - { - if (!r1) { LogMsg("IdenticalResourceRecord ERROR: r1 is NULL"); return(mDNSfalse); } - if (!r2) { LogMsg("IdenticalResourceRecord ERROR: r2 is NULL"); return(mDNSfalse); } - if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name)) - return(mDNSfalse); - return(SameRData(r1, r2)); - } - -mDNSlocal mDNSBool IdenticalSameNameRecord(const ResourceRecord *const r1, const ResourceRecord *const r2) - { - if (!r1) { LogMsg("IdenticalSameNameRecord ERROR: r1 is NULL"); return(mDNSfalse); } - if (!r2) { LogMsg("IdenticalSameNameRecord ERROR: r2 is NULL"); return(mDNSfalse); } - if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass) - return(mDNSfalse); - -#if VerifySameNameAssumptions - if (r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name)) - { - LogMsg("Bogus IdenticalSameNameRecord call: %##s does not match %##s", r1->name->c, r1->name->c); - return(mDNSfalse); - } -#endif - - return(SameRData(r1, r2)); - } - -// CacheRecord *ks is the CacheRecord from the known answer list in the query. +// CacheRecord *ka is the CacheRecord from the known answer list in the query. // This is the information that the requester believes to be correct. // AuthRecord *rr is the answer we are proposing to give, if not suppressed. // This is the information that we believe to be correct. @@ -1088,8 +1111,10 @@ mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const r } } -mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) +mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr, mDNSs32 interval) { + rr->ThisAPInterval = interval; + // To allow us to aggregate probes when a group of services are registered together, // the first probe is delayed 1/4 second. This means the common-case behaviour is: // 1/4 second wait; probe @@ -1097,19 +1122,22 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) // 1/4 second wait; probe // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered) - // If we have no probe suppression time set, or it is in the past, set it now - if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0) + if (rr->ProbeCount) { - m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique); - // If we already have a probe scheduled to go out sooner, then use that time to get better aggregation - if (m->SuppressProbes - m->NextScheduledProbe >= 0) - m->SuppressProbes = m->NextScheduledProbe; - // If we already have a query scheduled to go out sooner, then use that time to get better aggregation - if (m->SuppressProbes - m->NextScheduledQuery >= 0) - m->SuppressProbes = m->NextScheduledQuery; + // If we have no probe suppression time set, or it is in the past, set it now + if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0) + { + m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique); + // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation + if (m->SuppressProbes - m->NextScheduledProbe >= 0) + m->SuppressProbes = m->NextScheduledProbe; + // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation + if (m->SuppressProbes - m->NextScheduledQuery >= 0) + m->SuppressProbes = m->NextScheduledQuery; + } } - - rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval; + + rr->LastAPTime = m->SuppressProbes - interval; // Set LastMCTime to now, to inhibit multicast responses // (no need to send additional multicast responses when we're announcing anyway) rr->LastMCTime = m->timenow; @@ -1118,12 +1146,16 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) // If this is a record type that's not going to probe, then delay its first announcement so that // it will go out synchronized with the first announcement for the other records that *are* probing. // This is a minor performance tweak that helps keep groups of related records synchronized together. - // The addition of "rr->ThisAPInterval / 2" is to make sure that, in the event that any of the probes are + // The addition of "interval / 2" is to make sure that, in the event that any of the probes are // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete. // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated, // because they will meet the criterion of being at least half-way to their scheduled announcement time. - if (rr->resrec.RecordType != kDNSRecordTypeUnique) - rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2; + // The exception is unique records that have already been verified and are just being updated + // via mDNS_Update() -- for these we want to announce the new value immediately, without delay. + if (rr->resrec.RecordType == kDNSRecordTypeVerified) + rr->LastAPTime = m->timenow - interval; + else if (rr->resrec.RecordType != kDNSRecordTypeUnique) + rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + interval / 2; SetNextAnnounceProbeTime(m, rr); } @@ -1158,8 +1190,7 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr) rr->AnnounceCount = InitialAnnounceCount; rr->RequireGoodbye = mDNSfalse; - rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType); - InitializeLastAPTime(m,rr); + InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType)); } } @@ -1176,6 +1207,16 @@ mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr) } } +mDNSlocal void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr) + { + rr->ProbeCount = 0; + rr->AnnounceCount = 0; + rr->ThisAPInterval = 5 * mDNSPlatformOneSecond; // After doubling, first retry will happen after ten seconds + rr->LastAPTime = m->timenow - rr->ThisAPInterval; + rr->state = regState_FetchingZoneData; + rr->uselease = mDNStrue; + } + // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \ ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified)) @@ -1259,7 +1300,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); rr->AnnounceCount = InitialAnnounceCount; rr->RequireGoodbye = mDNSfalse; - rr->LocalAnswer = mDNSfalse; + rr->AnsweredLocalQ = mDNSfalse; rr->IncludeInProbe = mDNSfalse; rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; @@ -1270,8 +1311,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) rr->NextResponse = mDNSNULL; rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; - rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType); - if (!rr->AutoTarget) InitializeLastAPTime(m, rr); + if (!rr->AutoTarget) InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType)); // rr->LastAPTime = Set for us in InitializeLastAPTime() // rr->LastMCTime = Set for us in InitializeLastAPTime() // rr->LastMCInterface = Set for us in InitializeLastAPTime() @@ -1328,7 +1368,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); } rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); - rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u); + rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec); if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly) { @@ -1384,11 +1424,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) else { if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified; - rr->ProbeCount = 0; - rr->AnnounceCount = 0; - rr->state = regState_FetchingZoneData; - rr->uselease = mDNStrue; - rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr); + ActivateUnicastRegistration(m, rr); } #endif @@ -1522,7 +1558,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, } #endif UNICAST_DISABLED - if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->LocalAnswer)) + if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ)) { verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m, rr)); rr->resrec.RecordType = kDNSRecordTypeDeregistering; @@ -1732,7 +1768,7 @@ mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr) // it should go ahead and immediately dispose of this registration rr->resrec.RecordType = kDNSRecordTypeShared; rr->RequireGoodbye = mDNSfalse; - if (rr->LocalAnswer) { AnswerLocalQuestions(m, rr, mDNSfalse); rr->LocalAnswer = mDNSfalse; } + if (rr->AnsweredLocalQ) { AnswerLocalQuestions(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; } mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this } @@ -2062,13 +2098,13 @@ mDNSlocal void SendResponses(mDNS *const m) if (rr->SendRNow) { if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly) - LogMsg("SendResponses: No active interface to send: %s", ARDisplayString(m, rr)); + LogMsg("SendResponses: No active interface to send: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr)); rr->SendRNow = mDNSNULL; } if (rr->ImmedAnswer) { - if (rr->NewRData) CompleteRDataUpdate(m,rr); // Update our rdata, clear the NewRData pointer, and return memory to the client + if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) CompleteDeregistration(m, rr); // Don't touch rr after this @@ -2094,11 +2130,14 @@ mDNSlocal void SendResponses(mDNS *const m) // and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late // 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets), // so allow at most 1/10 second lateness +// 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately +// (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients). #define CacheCheckGracePeriod(RR) ( \ ((RR)->DelayDelivery ) ? (mDNSPlatformOneSecond/10) : \ ((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \ ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \ - ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : (mDNSPlatformOneSecond/10)) + ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \ + ((RR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0) // Note: MUST call SetNextCacheCheckTime any time we change: // rr->TimeRcvd @@ -2211,7 +2250,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer q->qname.c, DNSTypeName(q->qtype), newptr + forecast - query->data); query->h.numQuestions--; ka = *kalistptrptr; // Go back to where we started and retract these answer records - while (*ka) { CacheRecord *rr = *ka; *ka = mDNSNULL; ka = &rr->NextInKAList; } + while (*ka) { CacheRecord *c = *ka; *ka = mDNSNULL; ka = &c->NextInKAList; } return(mDNSfalse); // Return false, so we'll try again in the next packet } } @@ -2623,16 +2662,16 @@ mDNSlocal void SendQueries(mDNS *const m) // Put our known answer list (either new one from this question or questions, or remainder of old one from last time) while (KnownAnswerList) { - CacheRecord *rr = KnownAnswerList; - mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond; - mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl - SecsSinceRcvd); + CacheRecord *ka = KnownAnswerList; + mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - ka->TimeRcvd)) / mDNSPlatformOneSecond; + mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd); if (newptr) { verbosedebugf("SendQueries: Put %##s (%s) at %d - %d", - rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data); + ka->resrec.name->c, DNSTypeName(ka->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data); queryptr = newptr; - KnownAnswerList = rr->NextInKAList; - rr->NextInKAList = mDNSNULL; + KnownAnswerList = ka->NextInKAList; + ka->NextInKAList = mDNSNULL; } else { @@ -2886,7 +2925,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) m->CurrentQuestion = m->Questions; while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) { - DNSQuestion *q = m->CurrentQuestion; + q = m->CurrentQuestion; if (ResourceRecordAnswersQuestion(&rr->resrec, q)) AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now @@ -3068,7 +3107,6 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg) mDNSlocal void AnswerNewQuestion(mDNS *const m) { mDNSBool ShouldQueryImmediately = mDNStrue; - CacheRecord *rr; DNSQuestion *q = m->NewQuestions; // Grab the question we're going to answer const mDNSu32 slot = HashSlot(&q->qname); CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); @@ -3120,6 +3158,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) if (m->CurrentQuestion == q) { + CacheRecord *rr; for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) if (SameNameRecordAnswersQuestion(&rr->resrec, q)) { @@ -3487,15 +3526,8 @@ mDNSlocal void SuspendLLQs(mDNS *m) { DNSQuestion *q; for (q = m->Questions; q; q = q->next) - if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived) - { - // If necessary, tell server it can delete this LLQ state - if (q->state == LLQ_Established) sendLLQRefresh(m, q, 0); - if (q->nta) { CancelGetZoneData(m, q->nta); q->nta = mDNSNULL; } - if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; } - q->state = LLQ_InitialRequest; // Will need to set up new LLQ on wake from sleep - q->id = zeroOpaque64; - } + if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->state == LLQ_Established) + { q->ReqLease = 0; sendLLQRefresh(m, q); } } mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question) @@ -3503,7 +3535,12 @@ mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question) // For now this AutoTunnel stuff is specific to Mac OS X. // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer #if APPLE_OSX_mDNSResponder - if (question->qtype == kDNSType_AAAA && question->AuthInfo && question->AuthInfo->AutoTunnel && question->QuestionCallback != AutoTunnelCallback) + // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally. + // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the + // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel. + // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then + // returns results for both at the same time. + if (RRTypeIsAddressType(question->qtype) && question->AuthInfo && question->AuthInfo->AutoTunnel && question->QuestionCallback != AutoTunnelCallback) { question->NoAnswer = NoAnswer_Suspended; AddNewClientTunnel(m, question); @@ -3516,7 +3553,7 @@ mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question) LogOperation("ActivateUnicastQuery: %##s %s%s", question->qname.c, DNSTypeName(question->qtype), question->AuthInfo ? " (Private)" : ""); if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; } - if (question->LongLived) question->state = LLQ_InitialRequest; + if (question->LongLived) { question->state = LLQ_InitialRequest; question->id = zeroOpaque64; } question->ThisQInterval = InitialQuestionInterval; question->LastQTime = m->timenow - question->ThisQInterval; SetNextQueryTime(m, question); @@ -3570,12 +3607,13 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate) m->CurrentQuestion = m->Questions; while (m->CurrentQuestion) { - DNSQuestion *q = m->CurrentQuestion; + q = m->CurrentQuestion; m->CurrentQuestion = m->CurrentQuestion->next; if (!mDNSOpaque16IsZero(q->TargetQID)) ActivateUnicastQuery(m, q); } - // and reactivtate record (and service) registrations - uDNS_Wake(m); + // and reactivtate service registrations + m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond); + LogOperation("WakeServiceRegistrations %d %d", m->timenow, m->NextSRVUpdate); #endif // 1. Retrigger all our mDNS questions for (q = m->Questions; q; q=q->next) // Scan our list of questions @@ -3596,13 +3634,16 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate) // 3. Retrigger probing and announcing for all our authoritative records for (rr = m->ResourceRecords; rr; rr=rr->next) - if (!AuthRecord_uDNS(rr)) + if (AuthRecord_uDNS(rr)) + { + ActivateUnicastRegistration(m, rr); + } + else { if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); rr->AnnounceCount = InitialAnnounceCount; - rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType); - InitializeLastAPTime(m, rr); + InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType)); } } @@ -3824,7 +3865,7 @@ exit: m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it } -mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, ResourceRecord *pktrr) +mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const ResourceRecord *const pktrr) { mDNSu32 slot = HashSlot(pktrr->name); CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr); @@ -3928,24 +3969,24 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con { const mDNSu32 slot = HashSlot(&pktq.qname); CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname); - CacheRecord *rr; + CacheRecord *cr; // Make a list indicating which of our own cache records we expect to see updated as a result of this query // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated - for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) - if (SameNameRecordAnswersQuestion(&rr->resrec, &pktq) && rr->resrec.rdlength <= SmallRecordLimit) - if (!rr->NextInKAList && eap != &rr->NextInKAList) + for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) + if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit) + if (!cr->NextInKAList && eap != &cr->NextInKAList) { - *eap = rr; - eap = &rr->NextInKAList; - if (rr->MPUnansweredQ == 0 || m->timenow - rr->MPLastUnansweredQT >= mDNSPlatformOneSecond) + *eap = cr; + eap = &cr->NextInKAList; + if (cr->MPUnansweredQ == 0 || m->timenow - cr->MPLastUnansweredQT >= mDNSPlatformOneSecond) { // Although MPUnansweredQ is only really used for multi-packet query processing, // we increment it for both single-packet and multi-packet queries, so that it stays in sync // with the MPUnansweredKA value, which by necessity is incremented for both query types. - rr->MPUnansweredQ++; - rr->MPLastUnansweredQT = m->timenow; - rr->MPExpectingKA = mDNStrue; + cr->MPUnansweredQ++; + cr->MPLastUnansweredQT = m->timenow; + cr->MPExpectingKA = mDNStrue; } } @@ -3983,7 +4024,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con for (i=0; ih.numAnswers; i++) // For each record in the query's answer section... { // Get the record... - AuthRecord *rr; CacheRecord *ourcacherr; ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec); if (!ptr) goto exit; @@ -4033,10 +4073,10 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con eap = &ExpectedAnswers; while (*eap) { - CacheRecord *rr = *eap; - if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec)) - { *eap = rr->NextInKAList; rr->NextInKAList = mDNSNULL; } - else eap = &rr->NextInKAList; + CacheRecord *cr = *eap; + if (cr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &cr->resrec)) + { *eap = cr->NextInKAList; cr->NextInKAList = mDNSNULL; } + else eap = &cr->NextInKAList; } // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query. @@ -4183,38 +4223,37 @@ exit: while (ExpectedAnswers) { - CacheRecord *rr; - rr = ExpectedAnswers; - ExpectedAnswers = rr->NextInKAList; - rr->NextInKAList = mDNSNULL; + CacheRecord *cr = ExpectedAnswers; + ExpectedAnswers = cr->NextInKAList; + cr->NextInKAList = mDNSNULL; // For non-truncated queries, we can definitively say that we should expect // to be seeing a response for any records still left in the ExpectedAnswers list if (!(query->h.flags.b[0] & kDNSFlag0_TC)) - if (rr->UnansweredQueries == 0 || m->timenow - rr->LastUnansweredTime >= mDNSPlatformOneSecond) + if (cr->UnansweredQueries == 0 || m->timenow - cr->LastUnansweredTime >= mDNSPlatformOneSecond) { - rr->UnansweredQueries++; - rr->LastUnansweredTime = m->timenow; - if (rr->UnansweredQueries > 1) + cr->UnansweredQueries++; + cr->LastUnansweredTime = m->timenow; + if (cr->UnansweredQueries > 1) debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s", - rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr)); - SetNextCacheCheckTime(m, rr); + cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); + SetNextCacheCheckTime(m, cr); } // If we've seen multiple unanswered queries for this record, // then mark it to expire in five seconds if we don't get a response by then. - if (rr->UnansweredQueries >= MaxUnansweredQueries) + if (cr->UnansweredQueries >= MaxUnansweredQueries) { // Only show debugging message if this record was not about to expire anyway - if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond) + if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond) debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s", - rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr)); - mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer); + cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); + mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); } // Make a guess, based on the multi-packet query / known answer counts, whether we think we // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for // possible packet loss of up to 20% of the additional KA packets.) - else if (rr->MPUnansweredQ * 4 > rr->MPUnansweredKA * 5 + 8) + else if (cr->MPUnansweredQ * 4 > cr->MPUnansweredKA * 5 + 8) { // We want to do this conservatively. // If there are so many machines on the network that they have to use multi-packet known-answer lists, @@ -4222,30 +4261,29 @@ exit: // By setting the record to expire in four minutes, we achieve two things: // (a) the 90-95% final expiration queries will be less bunched together // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own - mDNSu32 remain = (mDNSu32)(RRExpireTime(rr) - m->timenow) / 4; + mDNSu32 remain = (mDNSu32)(RRExpireTime(cr) - m->timenow) / 4; if (remain > 240 * (mDNSu32)mDNSPlatformOneSecond) remain = 240 * (mDNSu32)mDNSPlatformOneSecond; // Only show debugging message if this record was not about to expire anyway - if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond) + if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond) debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s", - rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr)); + cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond) - rr->UnansweredQueries++; // Treat this as equivalent to one definite unanswered query - rr->MPUnansweredQ = 0; // Clear MPQ/MPKA statistics - rr->MPUnansweredKA = 0; - rr->MPExpectingKA = mDNSfalse; + cr->UnansweredQueries++; // Treat this as equivalent to one definite unanswered query + cr->MPUnansweredQ = 0; // Clear MPQ/MPKA statistics + cr->MPUnansweredKA = 0; + cr->MPExpectingKA = mDNSfalse; if (remain < kDefaultReconfirmTimeForNoAnswer) remain = kDefaultReconfirmTimeForNoAnswer; - mDNS_Reconfirm_internal(m, rr, remain); + mDNS_Reconfirm_internal(m, cr, remain); } } while (DupQuestions) { - int i; DNSQuestion *q = DupQuestions; DupQuestions = q->NextInDQList; q->NextInDQList = mDNSNULL; @@ -4338,7 +4376,7 @@ mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAd if (mDNSSameOpaque16(q->TargetQID, id)) return(mDNStrue); // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking if (TrustedSource(m, srcaddr)) return(mDNStrue); - LogOperation("WARNING: Ignoring suspect uDNS response for %##s (%s) %#a from %#a: %s", + LogOperation("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a] from %#a: %s", q->qname.c, DNSTypeName(q->qtype), &q->Target, srcaddr, CRDisplayString(m, rr)); return(mDNSfalse); } @@ -4618,8 +4656,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); rr->resrec.RecordType = kDNSRecordTypeUnique; rr->ProbeCount = DefaultProbeCountForTypeUnique + 1; - rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique); - InitializeLastAPTime(m, rr); + InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(kDNSRecordTypeUnique)); RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate } // If we're probing for this record, we just failed @@ -4711,6 +4748,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries. // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth. + debugf("DE for %s", CRDisplayString(m, rr)); rr->resrec.rroriginalttl = 1; rr->UnansweredQueries = MaxUnansweredQueries; SetNextCacheCheckTime(m, rr); @@ -4756,58 +4794,76 @@ exit: // in one second, thereby inadvertently delaying its actual expiration, instead of hastening it. // If this were to happen repeatedly, the record's expiration could be deferred indefinitely. // To avoid this, we need to ensure that the cache flushing operation will only act to - // *decrease* a record's remaining lifetime, never *increase* it. If a record has less than - // one second to go, we simply leave it alone, and leave it to expire at its assigned time. + // *decrease* a record's remaining lifetime, never *increase* it. for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next) if (r1->resrec.InterfaceID == r2->resrec.InterfaceID && r1->resrec.rrtype == r2->resrec.rrtype && r1->resrec.rrclass == r2->resrec.rrclass) - if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond) + { + // 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 && RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond) { - // 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 we find mismatched TTLs in an RRSet, correct them. + // We only do this for records with a TTL of 2 or higher. It's possible to have a + // goodbye announcement with the cache flush bit set (or a case change on record rdata, + // which we treat as a goodbye followed by an addition) and in that case it would be + // inappropriate to synchronize all the other records to a TTL of 0 (or 1). + // We suppress the message for the specific case of correcting from 240 to 60 for type TXT, + // because certain early Bonjour devices are known to have this specific mismatch, and + // there's no point filling syslog with messages about something we already know about. + // We also don't log this for uDNS responses, since a caching name server is obliged + // to give us an aged TTL to correct for how long it has held the record, + // so our received TTLs are expected to vary in that case + if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1) { - // If we find mismatched TTLs in an RRSet, correct them. - // We only do this for records with a TTL of 2 or higher. It's possible to have a - // goodbye announcement with the cache flush bit set (or a case change on record rdata, - // which we treat as a goodbye followed by an addition) and in that case it would be - // inappropriate to synchronize all the other records to a TTL of 0 (or 1). - // We suppress the message for the specific case of correcting from 240 to 60 for type TXT, - // because certain early Bonjour devices are known to have this specific mismatch, and - // there's no point filling syslog with messages about something we already know about. - // We also don't log this for uDNS responses, since a caching name server is obliged - // to give us an aged TTL to correct for how long it has held the record, - // so our received TTLs are expected to vary in that case - if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1) - { - if (!(r2->resrec.rroriginalttl == 240 && r1->resrec.rroriginalttl == 60 && r2->resrec.rrtype == kDNSType_TXT) && - mDNSOpaque16IsZero(response->h.id)) - LogOperation("Correcting TTL from %4d to %4d for %s", - r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2)); - r2->resrec.rroriginalttl = r1->resrec.rroriginalttl; - } + if (!(r2->resrec.rroriginalttl == 240 && r1->resrec.rroriginalttl == 60 && r2->resrec.rrtype == kDNSType_TXT) && + mDNSOpaque16IsZero(response->h.id)) + LogOperation("Correcting TTL from %4d to %4d for %s", + r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2)); + r2->resrec.rroriginalttl = r1->resrec.rroriginalttl; + } + r2->TimeRcvd = m->timenow; + } + 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. + + // If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache + // flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual + // one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates. + if (r2->TimeRcvd == m->timenow && r2->resrec.rroriginalttl <= 1 && r2->UnansweredQueries == MaxUnansweredQueries) + { + debugf("Cache flush for DE record %s", CRDisplayString(m, r2)); + r2->resrec.rroriginalttl = 0; + m->NextCacheCheck = m->timenow; + m->NextScheduledEvent = m->timenow; } - else // else, if record is old, mark it to be flushed + else if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond) { - 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. + // We only set a record to expire in one second if it currently has *more* than a second to live + // If it's already due to expire in a second or less, we just leave it alone r2->resrec.rroriginalttl = 1; r2->UnansweredQueries = MaxUnansweredQueries; + r2->TimeRcvd = m->timenow - 1; + // We use (m->timenow - 1) instead of m->timenow, because we use that to identify records + // that we marked for deletion via an explicit DE record } - r2->TimeRcvd = m->timenow; - SetNextCacheCheckTime(m, r2); } + 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 @@ -4942,6 +4998,11 @@ mDNSexport void MakeNegativeCacheRecord(mDNS *const m, const domainname *const n m->rec.r.NextInCFList = mDNSNULL; } +struct UDPSocket_struct + { + mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port + }; + mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID) @@ -4959,22 +5020,22 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co #ifndef UNICAST_DISABLED if (mDNSSameAddress(srcaddr, &m->Router)) { - if (mDNSSameIPPort(srcport, NATPMPPort)) +#ifdef _LEGACY_NAT_TRAVERSAL_ + if (mDNSSameIPPort(srcport, SSDPPort) || (m->SSDPSocket && mDNSSameIPPort(dstport, m->SSDPSocket->port))) { mDNS_Lock(m); - uDNS_ReceiveNATPMPPacket(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt)); + LNT_ConfigureRouterInfo(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt)); mDNS_Unlock(m); return; } -#ifdef _LEGACY_NAT_TRAVERSAL_ - if (mDNSSameIPPort(srcport, SSDPPort)) +#endif + if (mDNSSameIPPort(srcport, NATPMPPort)) { mDNS_Lock(m); - LNT_ConfigureRouterInfo(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt)); + uDNS_ReceiveNATPMPPacket(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt)); mDNS_Unlock(m); return; } -#endif } #endif if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; } @@ -5058,8 +5119,7 @@ mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuest return(mDNSNULL); } -// This is called after a question is deleted, in case other identical questions were being -// suppressed as duplicates +// This is called after a question is deleted, in case other identical questions were being suppressed as duplicates mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const question) { DNSQuestion *q; @@ -5083,7 +5143,7 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi q->state = question->state; // q->tcp = question->tcp; - q->origLease = question->origLease; + q->ReqLease = question->ReqLease; q->expire = question->expire; q->ntries = question->ntries; q->id = question->id; @@ -5109,7 +5169,7 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi } } -// lookup a DNS Server, matching by name in split-dns configurations. Result stored in addr parameter if successful +// Look up a DNS Server, matching by name in split-dns configurations. mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name) { DNSServer *curmatch = mDNSNULL, *p; @@ -5118,7 +5178,7 @@ mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name) for (p = m->DNSServers; p; p = p->next) { int scount = CountLabels(&p->domain); - if (!p->del && ncount >= scount && scount > curmatchlen) + if (!(p->flags & DNSServer_FlagDelete) && ncount >= scount && scount > curmatchlen) if (SameDomainName(SkipLeadingLabels(name, ncount - scount), &p->domain)) { curmatch = p; curmatchlen = scount; } } @@ -5242,7 +5302,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu question->NoAnswer = NoAnswer_Normal; question->state = LLQ_InitialRequest; - question->origLease = 0; + question->ReqLease = 0; question->expire = 0; question->ntries = 0; question->id = zeroOpaque64; @@ -5311,13 +5371,13 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que const mDNSu32 slot = HashSlot(&question->qname); CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname); CacheRecord *rr; - DNSQuestion **q = &m->Questions; + DNSQuestion **qp = &m->Questions; //LogOperation("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); - if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions; - while (*q && *q != question) q=&(*q)->next; - if (*q) *q = (*q)->next; + if (question->InterfaceID == mDNSInterface_LocalOnly) qp = &m->LocalOnlyQuestions; + while (*qp && *qp != question) qp=&(*qp)->next; + if (*qp) *qp = (*qp)->next; else { #if !ForceAlerts @@ -5401,7 +5461,20 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que } // If necessary, tell server it can delete this LLQ state - if (question->state == LLQ_Established) sendLLQRefresh(m, question, 0); + if (question->state == LLQ_Established) + { + question->ReqLease = 0; + sendLLQRefresh(m, question); + // If we need need to make a TCP connection to cancel the LLQ, that's going to take a little while. + // We clear the tcp->question backpointer so that when the TCP connection completes, it doesn't + // crash trying to access our cancelled question, but we don't cancel the TCP operation itself -- + // we let that run out its natural course and complete asynchronously. + if (question->tcp) + { + question->tcp->question = mDNSNULL; + question->tcp = mDNSNULL; + } + } } return(mStatus_NoError); @@ -5824,8 +5897,7 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us. // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement. if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1; - rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType); - InitializeLastAPTime(m, rr); + InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType)); while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr); if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--; if (!rr->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval); @@ -5950,7 +6022,7 @@ mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) intf->RR_A.RRSet = A; // Unregister these records. - // When doing the mDNS_Close processing, we first call DeadvertiseInterface for each interface, so by the time the platform + // When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it. // Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered. // To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal(). @@ -6135,7 +6207,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID); mDNSs32 initial = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval; mDNSs32 qdelay = dodelay ? mDNSPlatformOneSecond * 5 : 0; - if (dodelay) LogOperation("No cache records for expired %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype)); + if (dodelay) LogOperation("No cache records expired for %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype)); if (!q->ThisQInterval || q->ThisQInterval > initial) { @@ -6156,8 +6228,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); if (rr->AnnounceCount < announce) rr->AnnounceCount = announce; - rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType); - InitializeLastAPTime(m, rr); + InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType)); } } @@ -6293,7 +6364,7 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off, // giving the false impression that there's an active representative of this interface when there really isn't. // Don't need to do this when shutting down, because *all* interfaces are about to go away - if (revalidate && !m->mDNS_shutdown) + if (revalidate && !m->ShutdownTime) { mDNSu32 slot; CacheGroup *cg; @@ -6394,9 +6465,10 @@ mDNSlocal mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs) return mStatus_NoError; } + ActivateUnicastRegistration(m, &srs->RR_SRV); srs->state = regState_FetchingZoneData; - srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs); - return srs->nta ? mStatus_NoError : mStatus_NoMemoryErr; + srs->nta = mDNSNULL; + return mStatus_NoError; } // Note: @@ -6532,7 +6604,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, err = mDNS_Register_internal(m, &sr->RR_SRV); if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT); // We register the RR_PTR last, because we want to be sure that in the event of a forced call to - // mDNS_Close, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers + // mDNS_StartExit, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers // the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to // the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to // make sure we've deregistered all our records and done any other necessary cleanup before that happens. @@ -6826,7 +6898,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, // For debugging: To catch and report locking failures m->mDNS_busy = 0; m->mDNS_reentrancy = 0; - m->mDNS_shutdown = mDNSfalse; + m->ShutdownTime = 0; m->lock_rrcache = 0; m->lock_Questions = 0; m->lock_Records = 0; @@ -6922,6 +6994,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->LastNATReplyLocalTime = timenow; m->UPnPInterfaceID = 0; + m->SSDPSocket = mDNSNULL; m->UPnPRouterPort = zeroIPPort; m->UPnPSOAPPort = zeroIPPort; m->UPnPRouterURL = mDNSNULL; @@ -6971,7 +7044,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) // Let the platform layer get the current DNS information // The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand // (no need to hit the network with domain enumeration queries until we actually need that information). - for (ptr = m->DNSServers; ptr; ptr = ptr->next) ptr->del = mDNStrue; + for (ptr = m->DNSServers; ptr; ptr = ptr->next) ptr->flags |= DNSServer_FlagDelete; mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL); @@ -6993,15 +7066,28 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) } } + // Flush all records that match a new resolver + FORALL_CACHERECORDS(slot, cg, cr) + { + ptr = GetServerForName(m, cr->resrec.name); + if (ptr && (ptr->flags & DNSServer_FlagNew) && !cr->resrec.InterfaceID) + { + if (cr->resrec.RecordType == kDNSRecordTypePacketNegative) + mDNS_PurgeCacheResourceRecord(m, cr); + else + mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); + } + } + while (*p) { - if ((*p)->del) + if (((*p)->flags & DNSServer_FlagDelete) != 0) { // Scan our cache, looking for uDNS records that we would have queried this server for. // We reconfirm any records that match, because in this world of split DNS, firewalls, etc. // different DNS servers can give different answers to the same question. ptr = *p; - ptr->del = mDNSfalse; // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted + ptr->flags &= ~DNSServer_FlagDelete; // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted FORALL_CACHERECORDS(slot, cg, cr) if (!cr->resrec.InterfaceID && GetServerForName(m, cr->resrec.name) == ptr) mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); @@ -7009,7 +7095,10 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) mDNSPlatformMemFree(ptr); } else + { + (*p)->flags &= ~DNSServer_FlagNew; p = &(*p)->next; + } } // If we now have no DNS servers at all and we used to have some, then immediately purge all unicast cache records (including for LLQs). @@ -7073,44 +7162,24 @@ mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result) } } -mDNSexport void mDNS_Close(mDNS *const m) +extern ServiceRecordSet *CurrentServiceRecordSet; + +mDNSexport void mDNS_StartExit(mDNS *const m) { - mDNSu32 rrcache_active = 0; - mDNSu32 rrcache_totalused = 0; - mDNSu32 slot; NetworkInterfaceInfo *intf; AuthRecord *rr; + mDNS_Lock(m); - - m->mDNS_shutdown = mDNStrue; + + m->ShutdownTime = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5); #ifndef UNICAST_DISABLED SuspendLLQs(m); - SleepServiceRegistrations(m); + // Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here, + // because we deregister all records and services later in this routine while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn); #endif - rrcache_totalused = m->rrcache_totalused; - for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) - { - while (m->rrcache_hash[slot]) - { - CacheGroup *cg = m->rrcache_hash[slot]; - while (cg->members) - { - CacheRecord *cr = cg->members; - cg->members = cg->members->next; - if (cr->CRActiveQuestion) rrcache_active++; - ReleaseCacheRecord(m, cr); - } - cg->rrcache_tail = &cg->members; - ReleaseCacheGroup(m, &m->rrcache_hash[slot]); - } - } - debugf("mDNS_Close: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active); - if (rrcache_active != m->rrcache_active) - LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active); - for (intf = m->HostInterfaces; intf; intf = intf->next) if (intf->Advertise) DeadvertiseInterface(m, intf); @@ -7134,17 +7203,22 @@ mDNSexport void mDNS_Close(mDNS *const m) // Make sure there are nothing but deregistering records remaining in the list if (m->CurrentRecord) - LogMsg("mDNS_Close ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); + LogMsg("mDNS_StartExit ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); // First we deregister any non-shared records. In particular, we want to make sure we deregister - // any extra records added to a Service Record Set first, before we deregister its PTR record. + // any extra records added to a Service Record Set first, before we deregister its PTR record, + // because the freeing of the memory is triggered off the mStatus_MemFree for the PTR record. m->CurrentRecord = m->ResourceRecords; while (m->CurrentRecord) { rr = m->CurrentRecord; - m->CurrentRecord = rr->next; if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); + // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because when + // we have records on the DuplicateRecords list, the duplicate gets inserted in place of the record + // we're removing, and if we've already advanced to rr->next we'll miss the newly activated duplicate + if (m->CurrentRecord == rr) // If m->CurrentRecord was not auto-advanced, do it ourselves now + m->CurrentRecord = rr->next; } // Now deregister any remaining records we didn't get the first time through @@ -7152,23 +7226,79 @@ mDNSexport void mDNS_Close(mDNS *const m) while (m->CurrentRecord) { rr = m->CurrentRecord; - m->CurrentRecord = rr->next; if (rr->resrec.RecordType != kDNSRecordTypeDeregistering) + { + //LogOperation("mDNS_StartExit: Deregistering %s", ARDisplayString(m, rr)); mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); + } + // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because when + // we have records on the DuplicateRecords list, the duplicate gets inserted in place of the record + // we're removing, and if we've already advanced to rr->next we'll miss the newly activated duplicate + if (m->CurrentRecord == rr) // If m->CurrentRecord was not auto-advanced, do it ourselves now + m->CurrentRecord = rr->next; + } + + CurrentServiceRecordSet = m->ServiceRegistrations; + while (CurrentServiceRecordSet) + { + ServiceRecordSet *srs = CurrentServiceRecordSet; + LogOperation("mDNS_StartExit: Deregistering %##s", srs->RR_SRV.resrec.name->c); + uDNS_DeregisterService(m, srs); + if (CurrentServiceRecordSet == srs) + CurrentServiceRecordSet = srs->uDNS_next; } - if (m->ResourceRecords) LogOperation("mDNS_Close: Sending final packets for deregistering records"); - else LogOperation("mDNS_Close: No deregistering records remain"); + if (m->ResourceRecords) LogOperation("mDNS_StartExit: Sending final record deregistrations"); + else LogOperation("mDNS_StartExit: No deregistering records remain"); + + if (m->ServiceRegistrations) LogOperation("mDNS_StartExit: Sending final service deregistrations"); + else LogOperation("mDNS_StartExit: No deregistering services remain"); // If any deregistering records remain, send their deregistration announcements before we exit if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m); - else if (m->ResourceRecords) SendResponses(m); - for (rr = m->ResourceRecords; rr; rr = rr->next) - LogMsg("mDNS_Close failed to send goodbye for: %s", ARDisplayString(m, rr)); - mDNS_Unlock(m); - debugf("mDNS_Close: mDNSPlatformClose"); + + LogOperation("mDNS_StartExit: done"); + } + +mDNSexport void mDNS_FinalExit(mDNS *const m) + { + mDNSu32 rrcache_active = 0; + mDNSu32 rrcache_totalused = 0; + mDNSu32 slot; + AuthRecord *rr; + ServiceRecordSet *srs; + + LogOperation("mDNS_FinalExit: mDNSPlatformClose"); mDNSPlatformClose(m); - debugf("mDNS_Close: done"); + + rrcache_totalused = m->rrcache_totalused; + for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) + { + while (m->rrcache_hash[slot]) + { + CacheGroup *cg = m->rrcache_hash[slot]; + while (cg->members) + { + CacheRecord *cr = cg->members; + cg->members = cg->members->next; + if (cr->CRActiveQuestion) rrcache_active++; + ReleaseCacheRecord(m, cr); + } + cg->rrcache_tail = &cg->members; + ReleaseCacheGroup(m, &m->rrcache_hash[slot]); + } + } + debugf("mDNS_StartExit: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active); + if (rrcache_active != m->rrcache_active) + LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active); + + for (rr = m->ResourceRecords; rr; rr = rr->next) + LogMsg("mDNS_FinalExit failed to send goodbye for: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr)); + + for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next) + LogMsg("mDNS_FinalExit failed to deregister service: %##s", srs->RR_SRV.resrec.name->c); + + LogOperation("mDNS_FinalExit: done"); } diff --git a/mDNSCore/mDNSDebug.h b/mDNSCore/mDNSDebug.h index e5ad7d0..81bcedb 100755 --- a/mDNSCore/mDNSDebug.h +++ b/mDNSCore/mDNSDebug.h @@ -17,6 +17,12 @@ Change History (most recent first): $Log: mDNSDebug.h,v $ +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 @@ -140,14 +146,39 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release extern "C" { #endif +// Variable argument macro support. Use ANSI C99 __VA_ARGS__ where possible. Otherwise, use the next best thing. + +#if (defined(__GNUC__)) + #if ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 2))) + #define MDNS_C99_VA_ARGS 1 + #define MDNS_GNU_VA_ARGS 0 + #else + #define MDNS_C99_VA_ARGS 0 + #define MDNS_GNU_VA_ARGS 1 + #endif + #define MDNS_HAS_VA_ARG_MACROS 1 +#elif (_MSC_VER >= 1400) // Visual Studio 2005 and later + #define MDNS_C99_VA_ARGS 1 + #define MDNS_GNU_VA_ARGS 0 + #define MDNS_HAS_VA_ARG_MACROS 1 +#elif (defined(__MWERKS__)) + #define MDNS_C99_VA_ARGS 1 + #define MDNS_GNU_VA_ARGS 0 + #define MDNS_HAS_VA_ARG_MACROS 1 +#else + #define MDNS_C99_VA_ARGS 0 + #define MDNS_GNU_VA_ARGS 0 + #define MDNS_HAS_VA_ARG_MACROS 0 +#endif + #if MDNS_DEBUGMSGS #define debugf debugf_ extern void debugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); #else // If debug breaks are off, use a preprocessor trick to optimize those calls out of the code - #if (defined(__GNUC__)) + #if (MDNS_C99_VA_ARGS) + #define debugf( ... ) ((void)0) + #elif (MDNS_GNU_VA_ARGS) #define debugf( ARGS... ) ((void)0) - #elif (defined(__MWERKS__)) - #define debugf( ... ) #else #define debugf 1 ? ((void)0) : (void) #endif @@ -157,10 +188,10 @@ extern void debugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); #define verbosedebugf verbosedebugf_ extern void verbosedebugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); #else - #if (defined(__GNUC__)) + #if (MDNS_C99_VA_ARGS) + #define verbosedebugf( ... ) ((void)0) + #elif (MDNS_GNU_VA_ARGS) #define verbosedebugf( ARGS... ) ((void)0) - #elif (defined(__MWERKS__)) - #define verbosedebugf( ... ) #else #define verbosedebugf 1 ? ((void)0) : (void) #endif @@ -216,8 +247,6 @@ extern void udns_validatelists(void *const v); #define ForceAlerts 0 -#define VerifySameNameAssumptions 0 - #ifdef __cplusplus } #endif diff --git a/mDNSCore/mDNSEmbeddedAPI.h b/mDNSCore/mDNSEmbeddedAPI.h index 8673da9..a67e1f3 100755 --- a/mDNSCore/mDNSEmbeddedAPI.h +++ b/mDNSCore/mDNSEmbeddedAPI.h @@ -54,6 +54,36 @@ Change History (most recent first): $Log: mDNSEmbeddedAPI.h,v $ +Revision 1.463 2007/12/17 23:53:25 cheshire +Added DNSDigest_SignMessageHostByteOrder, for signing messages not yet converted to network byte order + +Revision 1.462 2007/12/17 23:48:29 cheshire +DNSDigest_SignMessage doesn't need to return a result -- it already updates the 'end' parameter + +Revision 1.461 2007/12/15 00:18:51 cheshire +Renamed question->origLease to question->ReqLease + +Revision 1.460 2007/12/14 23:55:28 cheshire +Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h + +Revision 1.459 2007/12/07 22:40:34 cheshire +Rename 'LocalAnswer' to more descriptive 'AnsweredLocalQ' + +Revision 1.458 2007/12/07 00:45:58 cheshire + BTMM: Need to clean up registrations on shutdown + +Revision 1.457 2007/12/06 00:22:27 mcguire + BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp) + +Revision 1.456 2007/12/05 01:45:35 cheshire +Renamed markedForDeletion -> MarkedForDeletion + +Revision 1.455 2007/12/01 01:21:27 jgraessley + mDNSResponder unicast DNS improvements + +Revision 1.454 2007/12/01 00:34:03 cheshire +Fixes from Bob Bradley for building on EFI + Revision 1.453 2007/10/29 23:51:22 cheshire Added comment about NATTraversalInfo ExternalAddress field @@ -605,13 +635,15 @@ Fixes to avoid code generation warning/error on FreeBSD 7 #ifndef __mDNSClientAPI_h #define __mDNSClientAPI_h -#if defined(EFI32) || defined(EFI64) -// EFI doesn't have stdarg.h +#if defined(EFI32) || defined(EFI64) || defined(EFIX64) +// EFI doesn't have stdarg.h unless it's building with GCC. #include "Tiano.h" +#if !defined(__GNUC__) #define va_list VA_LIST #define va_start(a, b) VA_START(a, b) #define va_end(a) VA_END(a) #define va_arg(a, b) VA_ARG(a, b) +#endif #else #include // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration #endif @@ -921,6 +953,21 @@ typedef struct { mDNSu8 c[256]; } UTF8str255; // Null-terminated C string #define DefaultTTLforRRType(X) (((X) == kDNSType_A || (X) == kDNSType_AAAA || (X) == kDNSType_SRV) ? kHostNameTTL : kStandardTTL) +typedef struct AuthRecord_struct AuthRecord; +typedef struct ServiceRecordSet_struct ServiceRecordSet; +typedef struct CacheRecord_struct CacheRecord; +typedef struct CacheGroup_struct CacheGroup; +typedef struct DNSQuestion_struct DNSQuestion; +typedef struct ZoneData_struct ZoneData; +typedef struct mDNS_struct mDNS; +typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport; +typedef struct NATTraversalInfo_struct NATTraversalInfo; + +// Structure to abstract away the differences between TCP/SSL sockets, and one for UDP sockets +// The actual definition of these structures in the in the appropriate platform support code +typedef struct TCPSocket_struct TCPSocket; +typedef struct UDPSocket_struct UDPSocket; + // *************************************************************************** #if 0 #pragma mark - DNS Message structures @@ -951,6 +998,23 @@ typedef packedstruct mDNSu8 data[AbsoluteMaxDNSMessageData]; // 40 (IPv6) + 8 (UDP) + 12 (DNS header) + 8940 (data) = 9000 } DNSMessage; +typedef struct tcpInfo_t + { + mDNS *m; + TCPSocket *sock; + DNSMessage request; + int requestLen; + DNSQuestion *question; // For queries + ServiceRecordSet *srs; // For service record updates + AuthRecord *rr; // For record updates + mDNSAddr Addr; + mDNSIPPort Port; + DNSMessage *reply; + mDNSu16 replylen; + unsigned long nread; + int numReplies; + } tcpInfo_t; + // *************************************************************************** #if 0 #pragma mark - Resource Record structures @@ -1120,16 +1184,7 @@ typedef struct } RData; #define sizeofRDataHeader (sizeof(RData) - sizeof(RDataBody)) -typedef struct AuthRecord_struct AuthRecord; -typedef struct CacheRecord_struct CacheRecord; -typedef struct CacheGroup_struct CacheGroup; -typedef struct DNSQuestion_struct DNSQuestion; -typedef struct ZoneData_struct ZoneData; -typedef struct mDNS_struct mDNS; -typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport; -typedef struct NATTraversalInfo_struct NATTraversalInfo; - -// Note: Within an mDNSRecordCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() +// Note: Within an mDNSRecordCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute() typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result); // Note: @@ -1149,11 +1204,6 @@ typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData #define NATMAP_DEFAULT_LEASE (60 * 60) // lease life in seconds #define NATMAP_VERS 0 -// Structure to abstract away the differences between TCP/SSL sockets, and one for UDP sockets -// The actual definition of these structures in the in the appropriate platform support code -typedef struct TCPSocket_struct TCPSocket; -typedef struct UDPSocket_struct UDPSocket; - typedef enum { NATOp_AddrRequest = 0, @@ -1361,7 +1411,7 @@ struct AuthRecord_struct mDNSu8 ProbeCount; // Number of probes remaining before this record is valid (kDNSRecordTypeUnique) mDNSu8 AnnounceCount; // Number of announcements remaining (kDNSRecordTypeShared) mDNSu8 RequireGoodbye; // Set if this RR has been announced on the wire and will require a goodbye packet - mDNSu8 LocalAnswer; // Set if this RR has been delivered to LocalOnly questions + mDNSu8 AnsweredLocalQ; // Set if this RR has been delivered to LocalOnly questions mDNSu8 IncludeInProbe; // Set if this RR is being put into a probe right now mDNSInterfaceID ImmedAnswer; // Someone on this interface issued a query we need to answer (all-ones for all interfaces) mDNSu8 ImmedUnicast; // Set if we may send our response directly via unicast to the requester @@ -1427,7 +1477,7 @@ struct AuthRecord_struct typedef struct ARListElem { struct ARListElem *next; - AuthRecord ar; // Note: Must be last struct in field to accomodate oversized AuthRecords + AuthRecord ar; // Note: Must be last element of structure, to accomodate oversized AuthRecords } ARListElem; struct CacheGroup_struct // Header object for a list of CacheRecords with the same name @@ -1493,13 +1543,19 @@ enum DNSServer_Disabled = 3 }; +enum + { + DNSServer_FlagDelete = 1, + DNSServer_FlagNew = 2 + }; + typedef struct DNSServer { struct DNSServer *next; mDNSInterfaceID interface; // For specialized uses; we can have DNS servers reachable over specific interfaces mDNSAddr addr; mDNSIPPort port; - mDNSBool del; // Set when we're planning to delete this from the list + mDNSu32 flags; // Set when we're planning to delete this from the list mDNSu32 teststate; // Have we sent bug-detection query to this server? mDNSs32 lasttest; // Time we sent last bug-detection query to this server domainname domain; // name->server matching for "split dns" @@ -1550,8 +1606,7 @@ struct ExtraResourceRecord_struct // that this extra memory is available, which would result in any fields after the AuthRecord getting smashed }; -// Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() -typedef struct ServiceRecordSet_struct ServiceRecordSet; +// Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute() typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result); // A ServiceRecordSet is basically a convenience structure to group together @@ -1695,7 +1750,7 @@ typedef struct DomainAuthInfo mDNSu8 keydata_opad[HMAC_LEN]; // padded key for outer hash rounds } DomainAuthInfo; -// Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() +// Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute() typedef enum { QC_rmv = 0, QC_add = 1, QC_addnocache = 2 } QC_result; typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord); struct DNSQuestion_struct @@ -1738,7 +1793,7 @@ struct DNSQuestion_struct // LLQ-specific fields. These fields are only meaningful when LongLived flag is set LLQ_State state; - mDNSu32 origLease; // seconds (relative) + mDNSu32 ReqLease; // seconds (relative) mDNSs32 expire; // ticks (absolute) mDNSs16 ntries; mDNSOpaque64 id; @@ -1771,7 +1826,7 @@ typedef struct mDNSu8 TXTinfo[2048]; // Additional demultiplexing information (e.g. LPR queue name) } ServiceInfo; -// Note: Within an mDNSServiceInfoQueryCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() +// Note: Within an mDNSServiceInfoQueryCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute() typedef struct ServiceInfoQuery_struct ServiceInfoQuery; typedef void mDNSServiceInfoQueryCallback(mDNS *const m, ServiceInfoQuery *query); struct ServiceInfoQuery_struct @@ -1830,7 +1885,7 @@ typedef struct ClientTunnel { struct ClientTunnel *next; domainname dstname; - mDNSBool markedForDeletion; + mDNSBool MarkedForDeletion; mDNSv6Addr loc_inner; mDNSv4Addr loc_outer; mDNSv6Addr rmt_inner; @@ -1875,7 +1930,6 @@ struct mDNS_struct // For debugging: To catch and report locking failures mDNSu32 mDNS_busy; // Incremented between mDNS_Lock/mDNS_Unlock section mDNSu32 mDNS_reentrancy; // Incremented when calling a client callback - mDNSu8 mDNS_shutdown; // Set when we're shutting down, allows us to skip some unnecessary steps mDNSu8 lock_rrcache; // For debugging: Set at times when these lists may not be modified mDNSu8 lock_Questions; mDNSu8 lock_Records; @@ -1887,6 +1941,7 @@ struct mDNS_struct mDNSs32 timenow; // The time that this particular activation of the mDNS code started mDNSs32 timenow_last; // The time the last time we ran mDNSs32 NextScheduledEvent; // Derived from values below + mDNSs32 ShutdownTime; // Set when we're shutting down, allows us to skip some unnecessary steps mDNSs32 SuppressSending; // Don't send *any* packets during this time mDNSs32 NextCacheCheck; // Next time to refresh cache record before it expires mDNSs32 NextScheduledQuery; // Next time to send query in its exponential backoff sequence @@ -1972,6 +2027,7 @@ struct mDNS_struct tcpLNTInfo tcpDeviceInfo; // legacy NAT traversal TCP connection info for device info tcpLNTInfo *tcpInfoUnmapList; // list of pending unmap requests mDNSInterfaceID UPnPInterfaceID; + UDPSocket *SSDPSocket; // For SSDP request/response mDNSIPPort UPnPRouterPort; // port we send discovery messages to mDNSIPPort UPnPSOAPPort; // port we send SOAP messages to mDNSu8 *UPnPRouterURL; // router's URL string @@ -2109,7 +2165,9 @@ mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v) // When mDNS has finished setting up the client's callback is called // A client can also spin and poll the mDNSPlatformStatus field to see when it changes from mStatus_Waiting to mStatus_NoError // -// Call mDNS_Close to tidy up before exiting +// Call mDNS_StartExit to tidy up before exiting +// Because exiting may be an asynchronous process (e.g. if unicast records need to be deregistered) +// client layer may choose to wait until mDNS_ExitNow() returns true before calling mDNS_FinalExit(). // // Call mDNS_Register with a completed AuthRecord object to register a resource record // If the resource record type is kDNSRecordTypeUnique (or kDNSknownunique) then if a conflicting resource record is discovered, @@ -2143,7 +2201,11 @@ extern mStatus mDNS_Init (mDNS *const m, mDNS_PlatformSupport *const p, #define mDNS_Init_NoInitCallbackContext mDNSNULL extern void mDNS_GrowCache (mDNS *const m, CacheEntity *storage, mDNSu32 numrecords); -extern void mDNS_Close (mDNS *const m); +extern void mDNS_StartExit (mDNS *const m); +extern void mDNS_FinalExit (mDNS *const m); +#define mDNS_Close(m) do { mDNS_StartExit(m); mDNS_FinalExit(m); } while(0) +#define mDNS_ExitNow(m, now) ((now) - (m)->ShutdownTime >= 0 || (!(m)->ResourceRecords && !(m)->ServiceRegistrations)) + extern mDNSs32 mDNS_Execute (mDNS *const m); extern mStatus mDNS_Register (mDNS *const m, AuthRecord *const rr); @@ -2261,8 +2323,8 @@ extern mDNSOpaque16 mDNS_NewMessageID(mDNS *const m); // A simple C structure assignment of a domainname can cause a protection fault by accessing unmapped memory, // because that object is defined to be 256 bytes long, but not all domainname objects are truly the full size. // This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid. -#define AssignDomainName(DST, SRC) do { mDNSu16 len = DomainNameLength((SRC)); \ - if (len <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len); else (DST)->c[0] = 0; } while(0) +#define AssignDomainName(DST, SRC) do { mDNSu16 len__ = DomainNameLength((SRC)); \ + if (len__ <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len__); else (DST)->c[0] = 0; } while(0) // Comparison functions #define SameDomainLabelCS(A,B) ((A)[0] == (B)[0] && mDNSPlatformMemSame((A)+1, (B)+1, (A)[0])) @@ -2432,7 +2494,7 @@ extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mD extern void mDNS_AddSearchDomain(const domainname *const domain); #define mDNS_AddSearchDomain_CString(X) \ - do { domainname d; if ((X) && MakeDomainNameFromDNSNameString(&d, (X)) && d.c[0]) mDNS_AddSearchDomain(&d); } while(0) + do { domainname d__; if ((X) && MakeDomainNameFromDNSNameString(&d__, (X)) && d__.c[0]) mDNS_AddSearchDomain(&d__); } while(0) // Routines called by the core, exported by DNSDigest.c @@ -2443,7 +2505,17 @@ extern mDNSs32 DNSDigest_ConstructHMACKeyfromBase64(DomainAuthInfo *info, const // of the message, and is modified by this routine. numAdditionals is a pointer to the number of additional // records in HOST byte order, which is incremented upon successful completion of this routine. The function returns // the new end pointer on success, and NULL on failure. -extern mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode); +extern void DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode); + +#define SwapDNSHeaderBytes(M) do { \ + (M)->h.numQuestions = (mDNSu16)((mDNSu8 *)&(M)->h.numQuestions )[0] << 8 | ((mDNSu8 *)&(M)->h.numQuestions )[1]; \ + (M)->h.numAnswers = (mDNSu16)((mDNSu8 *)&(M)->h.numAnswers )[0] << 8 | ((mDNSu8 *)&(M)->h.numAnswers )[1]; \ + (M)->h.numAuthorities = (mDNSu16)((mDNSu8 *)&(M)->h.numAuthorities)[0] << 8 | ((mDNSu8 *)&(M)->h.numAuthorities)[1]; \ + (M)->h.numAdditionals = (mDNSu16)((mDNSu8 *)&(M)->h.numAdditionals)[0] << 8 | ((mDNSu8 *)&(M)->h.numAdditionals)[1]; \ + } while (0) + +#define DNSDigest_SignMessageHostByteOrder(M,E,INFO) \ + do { SwapDNSHeaderBytes(M); DNSDigest_SignMessage((M), (E), (INFO), 0); SwapDNSHeaderBytes(M); } while (0) // verify a DNS message. The message must be complete, with all values in network byte order. end points to the // end of the record. tsig is a pointer to the resource record that contains the TSIG OPT record. info is @@ -2510,10 +2582,15 @@ extern mDNSs32 mDNSPlatformRawTime (void); extern mDNSs32 mDNSPlatformUTC (void); #define mDNS_TimeNow_NoLock(m) (mDNSPlatformRawTime() + m->timenow_adjust) +#if MDNS_DEBUGMSGS +extern void mDNSPlatformWriteDebugMsg(const char *msg); +#endif +extern void mDNSPlatformWriteLogMsg(const char *ident, const char *msg, int flags); + // Platform support modules should provide the following functions to map between opaque interface IDs // and interface indexes in order to support the DNS-SD API. If your target platform does not support // multiple interfaces and/or does not support the DNS-SD API, these functions can be empty. -extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index); +extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex); extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id); // Every platform support module must provide the following functions if it is to support unicast DNS diff --git a/mDNSCore/uDNS.c b/mDNSCore/uDNS.c index d6fddfa..bcf8ddf 100755 --- a/mDNSCore/uDNS.c +++ b/mDNSCore/uDNS.c @@ -22,6 +22,63 @@ Change History (most recent first): $Log: uDNS.c,v $ +Revision 1.545 2007/12/22 02:25:29 cheshire + Records and Services sometimes not re-registering on wake from sleep + +Revision 1.544 2007/12/18 00:40:11 cheshire + 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 + 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 + 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 + 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 + 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 + 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 + BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp) + +Revision 1.534 2007/12/04 00:49:37 cheshire + BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1 + +Revision 1.533 2007/12/01 01:21:27 jgraessley + 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 + 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 + ERROR: mDNSPlatformWriteTCP - send Broken pipe + Revision 1.528 2007/11/02 21:32:30 cheshire BTMM: Deferring deregistration of record log messages on sleep/wake @@ -1044,23 +1101,6 @@ Revision 1.227 2006/01/09 20:47:05 cheshire #pragma warning(disable:4706) #endif -typedef struct tcpInfo_t - { - mDNS *m; - TCPSocket *sock; - DNSMessage request; - int requestLen; - DNSQuestion *question; // For queries - ServiceRecordSet *srs; // For service record updates - AuthRecord *rr; // For record updates - mDNSAddr Addr; - mDNSIPPort Port; - DNSMessage *reply; - mDNSu16 replylen; - unsigned long nread; - int numReplies; - } tcpInfo_t; - typedef struct SearchListElem { struct SearchListElem *next; @@ -1086,7 +1126,7 @@ static SearchListElem *SearchList = mDNSNULL; // -- 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. -static ServiceRecordSet *CurrentServiceRecordSet = mDNSNULL; +ServiceRecordSet *CurrentServiceRecordSet = mDNSNULL; // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK @@ -1175,6 +1215,7 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr) 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; @@ -1201,8 +1242,8 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons if ((*p)->interface == interface && (*p)->teststate != DNSServer_Disabled && mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d)) { - if (!(*p)->del) LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c); - (*p)->del = mDNSfalse; + if (!((*p)->flags & DNSServer_FlagDelete)) LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c); + (*p)->flags &= ~DNSServer_FlagDelete; return(*p); } p=&(*p)->next; @@ -1216,7 +1257,7 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons (*p)->interface = interface; (*p)->addr = *addr; (*p)->port = port; - (*p)->del = mDNSfalse; + (*p)->flags = DNSServer_FlagNew; (*p)->teststate = DNSServer_Untested; (*p)->lasttest = m->timenow - INIT_UCAST_POLL_INTERVAL; AssignDomainName(&(*p)->domain, d); @@ -1662,7 +1703,7 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const llqBuf.llqOp = kLLQOp_Setup; llqBuf.err = LLQErr_NoError; // Don't need to tell server UDP notification port when sending over UDP llqBuf.id = q->id; - llqBuf.llqlease = q->origLease; + llqBuf.llqlease = q->ReqLease; llq = &llqBuf; } @@ -1676,14 +1717,22 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags); responsePtr = putQuestion(&m->omsg, responsePtr, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass); if (responsePtr) responsePtr = putLLQ(&m->omsg, responsePtr, q, llq, mDNSfalse); - if (responsePtr) mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo); + if (responsePtr) + { + mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, &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; } + } + } else StartLLQPolling(m,q); } mDNSlocal void SetLLQTimer(mDNS *const m, DNSQuestion *const q, const LLQOptData *const llq) { mDNSs32 lease = (mDNSs32)llq->llqlease * mDNSPlatformOneSecond; - q->origLease = llq->llqlease; + q->ReqLease = llq->llqlease; q->LastQTime = m->timenow; q->expire = m->timenow + lease; q->ThisQInterval = lease/2 + mDNSRandom(lease/10); @@ -1707,11 +1756,11 @@ mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const if (llq->err) { LogMsg("recvSetupResponse - received llq->err %d from server", llq->err); StartLLQPolling(m,q); return; } - if (q->origLease != llq->llqlease) - debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q->origLease, llq->llqlease); + if (q->ReqLease != llq->llqlease) + debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q->ReqLease, llq->llqlease); // cache expiration in case we go to sleep before finishing setup - q->origLease = llq->llqlease; + q->ReqLease = llq->llqlease; q->expire = m->timenow + ((mDNSs32)llq->llqlease * mDNSPlatformOneSecond); // update state @@ -1825,33 +1874,43 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs { tcpInfo_t *tcpInfo = (tcpInfo_t *)context; mDNSBool closed = mDNSfalse; - mDNSu8 *end; mDNS *m = tcpInfo->m; - + DNSQuestion *const q = tcpInfo->question; tcpInfo_t **backpointer = - tcpInfo->question ? &tcpInfo->question->tcp : + q ? &q ->tcp : tcpInfo->srs ? &tcpInfo->srs->tcp : - tcpInfo->rr ? &tcpInfo->rr->tcp : mDNSNULL; - if (!backpointer) LogMsg("tcpCallback: Purpose of connection unidentified"); - else if (*backpointer != tcpInfo) + 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, tcpInfo->question, tcpInfo->srs, tcpInfo->rr); + mDNSPlatformTCPGetFD(tcpInfo->sock), *backpointer, tcpInfo, q, tcpInfo->srs, tcpInfo->rr); if (err) goto exit; if (ConnectionEstablished) { + mDNSu8 *end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen; DomainAuthInfo *AuthInfo; + + // Defensive coding for 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; + // connection is established - send the message - if (tcpInfo->question && tcpInfo->question->LongLived && tcpInfo->question->state == LLQ_Established) + if (q && q->LongLived && q->state == LLQ_Established) { - //LogMsg("tcpCallback calling sendLLQRefresh %##s (%s)", tcpInfo->question->qname.c, DNSTypeName(tcpInfo->question->qtype)); - mDNS_Lock(m); - sendLLQRefresh(m, tcpInfo->question, tcpInfo->question->origLease); - mDNS_Unlock(m); - return; + end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen; } - else if (tcpInfo->question && tcpInfo->question->LongLived && tcpInfo->question->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort)) + else if (q && q->LongLived && q->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort)) { // Notes: // If we have a NAT port mapping, ExternalPort is the external port @@ -1864,45 +1923,28 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs LogOperation("tcpCallback: eventPort %d", llqData.err); llqData.id = zeroOpaque64; llqData.llqlease = kLLQ_DefLease; - InitializeDNSMessage(&tcpInfo->request.h, tcpInfo->question->TargetQID, uQueryFlags); - end = putLLQ(&tcpInfo->request, tcpInfo->request.data, tcpInfo->question, &llqData, mDNStrue); + InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, uQueryFlags); + end = putLLQ(&tcpInfo->request, tcpInfo->request.data, q, &llqData, mDNStrue); if (!end) { LogMsg("ERROR: tcpCallback - putLLQ"); err = mStatus_UnknownErr; goto exit; } + AuthInfo = q->AuthInfo; // Need to add TSIG to this message } - else if (tcpInfo->question) + else if (q) { - DNSQuestion *q = tcpInfo->question; 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 } - else - end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen; - - // Defensive coding for 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->question ? tcpInfo->question->AuthInfo : - tcpInfo->srs ? GetAuthInfoForName(m, tcpInfo->srs->RR_SRV.resrec.name) : - tcpInfo->rr ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name) : mDNSNULL; err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo); - if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %ld", err); err = mStatus_UnknownErr; goto exit; } // Record time we sent this question - if (tcpInfo->question) + if (q) { mDNS_Lock(m); - tcpInfo->question->LastQTime = m->timenow; - tcpInfo->question->ThisQInterval = MAX_UCAST_POLL_INTERVAL; - SetNextQueryTime(m, tcpInfo->question); + q->LastQTime = m->timenow; + q->ThisQInterval = MAX_UCAST_POLL_INTERVAL; + SetNextQueryTime(m, q); mDNS_Unlock(m); } } @@ -1920,7 +1962,7 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs // 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 %d", tcpInfo->nread); + if (tcpInfo->numReplies == 0) LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo->nread); err = mStatus_ConnFailed; goto exit; } @@ -1956,7 +1998,11 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs tcpInfo->replylen = 0; // If we're going to dispose this connection, do it FIRST, before calling client callback - if (!tcpInfo->question || !tcpInfo->question->LongLived) { *backpointer = mDNSNULL; DisposeTCPConn(tcpInfo); } + // Note: Sleep code depends on us clearing *backpointer here -- it uses the clearing of rr->tcp and srs->tcp + // as the signal that the DNS deregistration operation with the server has completed, and the machine may now sleep + if (backpointer) + if (!q || !q->LongLived || m->SleepState) + { *backpointer = mDNSNULL; DisposeTCPConn(tcpInfo); } if (rr && rr->resrec.RecordType == kDNSRecordTypeDeregistering) { @@ -1980,13 +2026,12 @@ exit: { // Clear client backpointer FIRST -- that way if one of the callbacks cancels its operation // we won't end up double-disposing our tcpInfo_t - *backpointer = mDNSNULL; + if (backpointer) *backpointer = mDNSNULL; mDNS_Lock(m); // Need to grab the lock to get m->timenow - if (tcpInfo->question) + if (q) { - DNSQuestion *q = tcpInfo->question; if (q->ThisQInterval == 0 || q->LastQTime + q->ThisQInterval - m->timenow > MAX_UCAST_POLL_INTERVAL) { q->LastQTime = m->timenow; @@ -1995,7 +2040,10 @@ exit: } // ConnFailed is actually okay. It just means that the server closed the connection but the LLQ is still okay. // If the error isn't ConnFailed, then the LLQ is in bad shape. - if (err != mStatus_ConnFailed) StartLLQPolling(m, tcpInfo->question); + if (err != mStatus_ConnFailed) + { + if (q->LongLived && q->state != LLQ_Poll) StartLLQPolling(m, q); + } } if (tcpInfo->rr) SetRecordRetry(m, tcpInfo->rr, mStatus_NoError); @@ -2016,21 +2064,27 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con mDNSIPPort srcport = zeroIPPort; tcpInfo_t *info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t)); if (!info) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL); } - mDNSPlatformMemZero(info, sizeof(tcpInfo_t)); + info->m = m; - if (msg) - { - info->request = *msg; - info->requestLen = (int) (end - ((mDNSu8*)msg)); - } + info->sock = mDNSPlatformTCPSocket(m, flags, &srcport); + info->requestLen = 0; info->question = question; info->srs = srs; info->rr = rr; info->Addr = *Addr; info->Port = Port; + info->reply = mDNSNULL; + info->replylen = 0; + info->nread = 0; + info->numReplies = 0; + + if (msg) + { + info->requestLen = (int) (end - ((mDNSu8*)msg)); + mDNSPlatformMemCopy(&info->request, msg, info->requestLen); + } - info->sock = mDNSPlatformTCPSocket(m, flags, &srcport); if (!info->sock) { LogMsg("SendServiceRegistration: uanble to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); } err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpCallback, info); @@ -2042,7 +2096,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 ) { LogOperation("MakeTCPConnection: connection failed"); mDNSPlatformMemFree(info); return(mDNSNULL); } + else if (err != mStatus_ConnPending ) { LogOperation("MakeTCPConnection: connection failed"); DisposeTCPConn(info); return(mDNSNULL); } return(info); } @@ -2095,7 +2149,7 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q) else { q->state = LLQ_SecondaryRequest; // Right now, for private DNS, we skip the four-way LLQ handshake - q->origLease = kLLQ_DefLease; + q->ReqLease = kLLQ_DefLease; q->ThisQInterval = 0; } q->LastQTime = m->timenow; @@ -2133,7 +2187,7 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q) // update question state q->state = LLQ_InitialRequest; - q->origLease = kLLQ_DefLease; + q->ReqLease = kLLQ_DefLease; q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond); q->LastQTime = m->timenow; SetNextQueryTime(m, q); @@ -2303,11 +2357,9 @@ mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs) 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; @@ -2405,6 +2457,16 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question mDNS_StopQuery(m, question); 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, + // the code below will make us try to connect to loopback, resulting in an immediate "port unreachable" failure. + // This helps us test to make sure we handle this case gracefully + // BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1 +#if 0 + zd->Addr.ip.v4.b[0] = 127; + zd->Addr.ip.v4.b[1] = 0; + zd->Addr.ip.v4.b[2] = 0; + zd->Addr.ip.v4.b[3] = 1; +#endif zd->ZoneDataCallback(m, mStatus_NoError, zd); mDNSPlatformMemFree(zd); } @@ -2509,7 +2571,7 @@ mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n) mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs) { - mDNSu8 *p = srs->RR_PTR.resrec.name->c; + 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; @@ -2528,29 +2590,29 @@ mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs) mDNSexport void ServiceRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData) { 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); 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; + if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr)) return; + // cache zone data AssignDomainName(&srs->zone, &zoneData->ZoneName); srs->SRSUpdateServer.type = mDNSAddrType_IPv4; srs->SRSUpdateServer = zoneData->Addr; - if (!mDNSIPPortIsZero(zoneData->Port)) - { - srs->SRSUpdatePort = zoneData->Port; - srs->Private = zoneData->ZonePrivate; - } - else - { - debugf("Update port not advertised via SRV - guessing port 53, no lease option"); - srs->SRSUpdatePort = UnicastDNSPort; - srs->srs_uselease = mDNSfalse; - } + srs->SRSUpdatePort = zoneData->Port; + srs->Private = zoneData->ZonePrivate; + + srs->RR_SRV.LastAPTime = m->timenow; + srs->RR_SRV.ThisAPInterval = 0; LogOperation("ServiceRegistrationGotZoneData My IPv4 %#a%s Server %#a:%d%s for %##s", &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC1918)" : "", @@ -2603,9 +2665,11 @@ mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs) srs->id = id; srs->state = regState_DeregPending; + srs->RR_SRV.expire = 0; // Indicate that we have no active registration any more if (srs->Private) { + LogOperation("SendServiceDeregistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV)); if (srs->tcp) LogOperation("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); @@ -2622,7 +2686,6 @@ mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs) return; exit: - if (err) { LogMsg("SendServiceDeregistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c); @@ -2729,6 +2792,9 @@ mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs) // Called with lock held mDNSlocal void UpdateSRVRecords(mDNS *m) { + LogOperation("UpdateSRVRecords%s", m->SleepState ? " (ignored due to SleepState)" : ""); + if (m->SleepState) return; + if (CurrentServiceRecordSet) LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set"); CurrentServiceRecordSet = m->ServiceRegistrations; @@ -2763,7 +2829,7 @@ mDNSlocal void hostnameGetPublicAddressCallback(mDNS *m, NATTraversalInfo *n) } else { - LogMsg("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &n->ExternalAddress); + LogOperation("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &n->ExternalAddress); h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique; h->arv4.resrec.rdata->u.ipv4 = n->ExternalAddress; mDNS_Register(m, &h->arv4); @@ -2794,7 +2860,7 @@ mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h) } else { - LogMsg("Advertising hostname %##s IPv4 %.4a", h->arv4.resrec.name->c, &m->AdvertisedV4.ip.v4); + LogOperation("Advertising hostname %##s IPv4 %.4a", h->arv4.resrec.name->c, &m->AdvertisedV4.ip.v4); h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique; mDNS_Register_internal(m, &h->arv4); } @@ -2806,7 +2872,7 @@ mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h) AssignDomainName(&h->arv6.namestorage, &h->fqdn); h->arv6.resrec.rdata->u.ipv6 = m->AdvertisedV6.ip.v6; h->arv6.state = regState_Unregistered; - LogMsg("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6); + LogOperation("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6); mDNS_Register_internal(m, &h->arv6); } } @@ -2868,9 +2934,9 @@ mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus res // Deliver success to client if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; } if (rr->resrec.rrtype == kDNSType_A) - LogMsg("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4); + LogOperation("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4); else - LogMsg("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6); + LogOperation("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6); rr->RecordContext = (void *)hi->StatusContext; if (hi->StatusCallback) @@ -2896,7 +2962,7 @@ mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const R h->arv6.state == regState_FetchingZoneData || 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)); + m->NextSRVUpdate = NonZeroTime(m->timenow + 5 * mDNSPlatformOneSecond); return; } h = h->next; @@ -3268,6 +3334,8 @@ mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mSt 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); + LogOperation("hndlServiceUpdateReply: err %d state %d %##s", err, srs->state, srs->RR_SRV.resrec.name->c); + SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError); switch (srs->state) @@ -3360,11 +3428,13 @@ mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mSt 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_NoTarget: case regState_ExtraQueued: case regState_NATError: LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.", @@ -3457,6 +3527,10 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err) 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); + LogOperation("hndlRecordUpdateReply: err %d state %d %s", err, rr->state, ARDisplayString(m, rr)); + + if (m->SleepState) return; // If we just sent a deregister on going to sleep, no further action required + SetRecordRetry(m, rr, mStatus_NoError); if (rr->state == regState_UpdatePending) @@ -3497,8 +3571,8 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err) { if (!err) { - rr->state = regState_Registered; if (rr->state == regState_Refresh) InvokeCallback = mDNSfalse; + rr->state = regState_Registered; } else { @@ -3594,6 +3668,9 @@ mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interfac natTraversalHandlePortMapReply(m, ptr, InterfaceID, PortMapReply->err, PortMapReply->extport, PortMapReply->NATRep_lease); } else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply->opcode); return; } + + // Don't need an SSDP socket if we get a NAT-PMP packet + if (m->SSDPSocket) { LogOperation("uDNS_ReceiveNATPMPPacket destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; } } // Shorten DNS-SD queries to avoid NAT bugs @@ -3647,16 +3724,16 @@ mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *c const mDNSAddr *const srcaddr, const mDNSIPPort srcport) { const mDNSu8 *ptr = msg->data; - DNSQuestion q; + DNSQuestion pktq; DNSServer *s; mDNSu32 result = 0; // 1. Find out if this is an answer to one of our test questions if (msg->h.numQuestions != 1) return(mDNSfalse); - ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q); + ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &pktq); if (!ptr) return(mDNSfalse); - if (q.qtype != kDNSType_PTR || q.qclass != kDNSClass_IN) return(mDNSfalse); - if (!SameDomainName(&q.qname, DNSRelayTestQuestion)) return(mDNSfalse); + if (pktq.qtype != kDNSType_PTR || pktq.qclass != kDNSClass_IN) return(mDNSfalse); + if (!SameDomainName(&pktq.qname, DNSRelayTestQuestion)) return(mDNSfalse); // 2. If the DNS relay gave us a positive response, then it's got buggy firmware // else, if the DNS relay gave us an error or no-answer response, it passed our test @@ -3783,45 +3860,48 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS #pragma mark - Query Routines #endif -mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease) +mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q) { mDNSu8 *end; LLQOptData llq; - mStatus err; - // If this is supposed to be a private question and the server dropped the TCP connection, - // we don't want to cancel it with a clear-text UDP packet, and and it's not worth the expense of - // setting up a new TLS session just to cancel the outstanding LLQ, so we just let it expire naturally - if (lease == 0 && q->AuthInfo && !q->tcp) return; + if (q->ReqLease) + if ((q->state == LLQ_Established && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0) + { + LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d minutes", q->qname.c, DNSTypeName(q->qtype), LLQ_POLL_INTERVAL/3600); + StartLLQPolling(m,q); + return; + } - if (q->AuthInfo && !q->tcp) + llq.vers = kLLQ_Vers; + llq.llqOp = kLLQOp_Refresh; + llq.err = q->tcp ? GetLLQEventPort(m, &q->servAddr) : LLQErr_NoError; // If using TCP tell server what UDP port to send notifications to + llq.id = q->id; + llq.llqlease = q->ReqLease; + + InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags); + end = putLLQ(&m->omsg, m->omsg.data, q, &llq, mDNStrue); + if (!end) { LogMsg("sendLLQRefresh: putLLQ failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; } + if (q->AuthInfo) { - //LogOperation("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); - q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL); - q->LastQTime = m->timenow; - SetNextQueryTime(m, q); - return; + 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->state == LLQ_Established && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0) + if (q->AuthInfo && !q->tcp) { - LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d minutes", q->qname.c, DNSTypeName(q->qtype), LLQ_POLL_INTERVAL/3600); - StartLLQPolling(m,q); - return; + LogOperation("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); + } + else + { + mStatus err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, mDNSNULL); + if (err) + { + LogMsg("sendLLQRefresh: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err); + if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; } + } } - - llq.vers = kLLQ_Vers; - llq.llqOp = kLLQOp_Refresh; - llq.err = q->tcp ? GetLLQEventPort(m, &q->servAddr) : LLQErr_NoError; // If using TCP tell server what UDP port to send notifications to - llq.id = q->id; - llq.llqlease = lease; - - InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags); - end = putLLQ(&m->omsg, m->omsg.data, q, &llq, mDNStrue); - if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; } - - err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo); - if (err) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err); q->ntries++; @@ -3844,7 +3924,7 @@ mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneI q->servAddr = zeroAddr; q->servPort = zeroIPPort; - if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port)) + if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr)) { q->servAddr = zoneInfo->Addr; q->servPort = zoneInfo->Port; @@ -3917,6 +3997,10 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const 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; } @@ -3959,6 +4043,8 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const return; } + newRR->ThisAPInterval = 5 * mDNSPlatformOneSecond; // After doubling, first retry will happen after ten seconds + mDNS_Lock(m); // SendRecordRegistration expects to be called with the lock held SendRecordRegistration(m, newRR); mDNS_Unlock(m); @@ -3988,6 +4074,7 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr) } else { + rr->expire = 0; // Indicate that we have no active registration any more if (rr->Private) { LogOperation("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr)); @@ -4201,7 +4288,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) { case LLQ_InitialRequest: startLLQHandshake(m, q); break; case LLQ_SecondaryRequest: sendChallengeResponse(m, q, mDNSNULL); break; - case LLQ_Established: sendLLQRefresh(m, q, q->origLease); break; + case LLQ_Established: sendLLQRefresh(m, q); break; case LLQ_Poll: break; // Do nothing (handled below) } } @@ -4311,6 +4398,7 @@ mDNSlocal void CheckNATMappings(mDNS *m) { if (m->NATMcastRecvskt) { mDNSPlatformUDPClose(m->NATMcastRecvskt); m->NATMcastRecvskt = mDNSNULL; } if (m->NATMcastRecvsk2) { mDNSPlatformUDPClose(m->NATMcastRecvsk2); m->NATMcastRecvsk2 = mDNSNULL; } + if (m->SSDPSocket) { LogOperation("CheckNATMappings destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; } } if (m->NATTraversals) @@ -4413,13 +4501,20 @@ mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m) for (rr = m->ResourceRecords; rr; rr = rr->next) { - if (rr->state == regState_Pending || rr->state == regState_DeregPending || rr->state == regState_UpdatePending || + 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 (rr->LastAPTime + rr->ThisAPInterval - m->timenow < 0) { if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } - if (rr->state == regState_DeregPending) SendRecordDeregistration(m, rr); + if (rr->state == regState_FetchingZoneData) + { + if (rr->nta) CancelGetZoneData(m, rr->nta); + rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr); + SetRecordRetry(m, rr, mStatus_NoError); + } + else if (rr->state == regState_DeregPending) SendRecordDeregistration(m, rr); else SendRecordRegistration(m, rr); } if (nextevent - (rr->LastAPTime + rr->ThisAPInterval) > 0) @@ -4442,13 +4537,20 @@ mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m) { ServiceRecordSet *srs = CurrentServiceRecordSet; CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next; - if (srs->state == regState_Pending || srs->state == regState_DeregPending || srs->state == regState_DeregDeferred || + 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) { if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - m->timenow <= 0) { if (srs->tcp) { DisposeTCPConn(srs->tcp); srs->tcp = mDNSNULL; } - if (srs->state == regState_DeregPending) SendServiceDeregistration(m, srs); + if (srs->state == regState_FetchingZoneData) + { + if (srs->nta) CancelGetZoneData(m, srs->nta); + 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); } if (nextevent - (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval) > 0) @@ -4491,36 +4593,17 @@ mDNSexport void uDNS_Execute(mDNS *const m) mDNSexport void SleepRecordRegistrations(mDNS *m) { - AuthRecord *rr = m->ResourceRecords; - - while (rr) - { - if (rr->state == regState_Registered || - rr->state == regState_Refresh) - { - SendRecordDeregistration(m, rr); - rr->state = regState_Refresh; - rr->LastAPTime = m->timenow; - rr->ThisAPInterval = 300 * mDNSPlatformOneSecond; - } - rr = rr->next; - } - } - -mDNSlocal void WakeRecordRegistrations(mDNS *m) - { - AuthRecord *rr = m->ResourceRecords; - - while (rr) - { - if (rr->state == regState_Refresh) - { - // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets) - rr->LastAPTime = m->timenow; - rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL; - } - rr = rr->next; - } + AuthRecord *rr; + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (AuthRecord_uDNS(rr)) + if (rr->state == regState_Registered || + rr->state == regState_Refresh) + { + SendRecordDeregistration(m, rr); + rr->state = regState_Refresh; + rr->LastAPTime = m->timenow; + rr->ThisAPInterval = 300 * mDNSPlatformOneSecond; + } } mDNSexport void SleepServiceRegistrations(mDNS *m) @@ -4528,6 +4611,7 @@ mDNSexport void SleepServiceRegistrations(mDNS *m) ServiceRecordSet *srs = m->ServiceRegistrations; while (srs) { + LogOperation("SleepServiceRegistrations: state %d %s", srs->state, ARDisplayString(m, &srs->RR_SRV)); if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; } if (srs->NATinfo.clientContext) @@ -4549,29 +4633,13 @@ mDNSexport void SleepServiceRegistrations(mDNS *m) } if (srs->state == regState_Registered || srs->state == regState_Refresh) - { - mDNSOpaque16 origid = srs->id; - srs->state = regState_DeregPending; // state expected by SendDereg() SendServiceDeregistration(m, srs); - srs->id = origid; - 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 = srs->uDNS_next; - } - } -mDNSlocal void WakeServiceRegistrations(mDNS *m) - { - ServiceRecordSet *srs = m->ServiceRegistrations; - while (srs) - { - if (srs->state == regState_Refresh) - { - // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets) - srs->RR_SRV.LastAPTime = m->timenow; - srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL; - } + 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; } } @@ -4777,12 +4845,6 @@ mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m) // 6) client calls to enumerate domains now go over LocalOnly interface // (!!!KRS may add outgoing interface in addition) -mDNSexport void uDNS_Wake(mDNS *const m) - { - WakeServiceRegistrations(m); - WakeRecordRegistrations(m); - } - struct CompileTimeAssertionChecks_uDNS { // Check our structures are reasonable sizes. Including overly-large buffers, or embedding diff --git a/mDNSCore/uDNS.h b/mDNSCore/uDNS.h index c61e05c..2676a2c 100755 --- a/mDNSCore/uDNS.h +++ b/mDNSCore/uDNS.h @@ -17,6 +17,12 @@ Change History (most recent first): $Log: uDNS.h,v $ +Revision 1.90 2007/12/22 02:25:30 cheshire + Records and Services sometimes not re-registering on wake from sleep + +Revision 1.89 2007/12/15 01:12:27 cheshire + 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 @@ -231,9 +237,7 @@ Revision 1.33 2006/07/05 22:53:28 cheshire 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, mDNSu32 lease); - -extern void uDNS_Wake(mDNS *const m); +extern void sendLLQRefresh(mDNS *m, DNSQuestion *q); extern void SleepServiceRegistrations(mDNS *m); extern void SleepRecordRegistrations(mDNS *m); diff --git a/mDNSMacOSX/LegacyNATTraversal.c b/mDNSMacOSX/LegacyNATTraversal.c index 2be3dd4..b1a23b6 100644 --- a/mDNSMacOSX/LegacyNATTraversal.c +++ b/mDNSMacOSX/LegacyNATTraversal.c @@ -17,6 +17,9 @@ Change History (most recent first): $Log: LegacyNATTraversal.c,v $ +Revision 1.45 2007/12/06 00:22:27 mcguire + BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp) + Revision 1.44 2007/11/02 20:45:40 cheshire Don't log "connection failed" in customer builds @@ -806,6 +809,9 @@ mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID Interface if (ptr == mDNSNULL || ptr == end) return; // not a valid message LogOperation("Router port %d, URL set to [%s]...", mDNSVal16(m->UPnPRouterPort), m->UPnPRouterURL); + + // Don't need the SSDP socket anymore + if (m->SSDPSocket) { LogOperation("LNT_ConfigureRouterInfo destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; } // now send message to get the device description GetDeviceDescription(m, &m->tcpDeviceInfo); @@ -823,7 +829,10 @@ mDNSexport void LNT_SendDiscoveryMsg(mDNS *m) LogOperation("LNT_SendDiscoveryMsg Router %.4a Current External Address %.4a", &m->Router.ip.v4, &m->ExternalAddress); if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSIPv4AddressIsZero(m->ExternalAddress)) + { + if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(m, zeroIPPort); LogOperation("LNT_SendDiscoveryMsg created SSDPSocket %p", &m->SSDPSocket); } mDNSPlatformSendUDP(m, msg, msg + sizeof(msg) - 1, 0, &m->Router, SSDPPort); + } } #endif /* _LEGACY_NAT_TRAVERSAL_ */ diff --git a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m index 8e66610..412da6d 100644 --- a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m +++ b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m @@ -43,6 +43,9 @@ Change History (most recent first): $Log: DNSServiceDiscoveryPref.m,v $ +Revision 1.11 2007/11/30 23:42:09 cheshire +Fixed compile warning: declaration of 'index' shadows a global declaration + Revision 1.10 2007/09/18 19:09:02 cheshire mDNSResponderHelper (and other binaries) missing SCCS version strings @@ -777,11 +780,11 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) } -- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)index +- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)ind { NSString *domain = nil; - if ([aComboBox isEqualTo:browseDomainsComboBox]) domain = [browseDataSource objectAtIndex:index]; - else if ([aComboBox isEqualTo:regDomainsComboBox]) domain = [registrationDataSource objectAtIndex:index]; + if ([aComboBox isEqualTo:browseDomainsComboBox]) domain = [browseDataSource objectAtIndex:ind]; + else if ([aComboBox isEqualTo:regDomainsComboBox]) domain = [registrationDataSource objectAtIndex:ind]; return domain; } diff --git a/mDNSMacOSX/PreferencePane/PrivilegedOperations.c b/mDNSMacOSX/PreferencePane/PrivilegedOperations.c index 13552f6..01f09c5 100644 --- a/mDNSMacOSX/PreferencePane/PrivilegedOperations.c +++ b/mDNSMacOSX/PreferencePane/PrivilegedOperations.c @@ -43,6 +43,9 @@ Change History (most recent first): $Log: PrivilegedOperations.c,v $ +Revision 1.8 2007/11/30 23:42:33 cheshire +Fixed compile warning: declaration of 'status' shadows a previous local + Revision 1.7 2007/02/09 00:39:06 cheshire Fix compile warnings @@ -146,7 +149,6 @@ OSStatus EnsureToolInstalled(void) char *installerargs[] = { toolSourcePath, NULL }; err = AuthorizationExecuteWithPrivileges(authRef, toolInstallerPath, 0, installerargs, (FILE**) NULL); if (err == noErr) { - int status; int pid = wait(&status); if (pid > 0 && WIFEXITED(status)) { err = WEXITSTATUS(status); diff --git a/mDNSMacOSX/PreferencePane/ddnswriteconfig.m b/mDNSMacOSX/PreferencePane/ddnswriteconfig.m index 3f2fbbf..f415180 100644 --- a/mDNSMacOSX/PreferencePane/ddnswriteconfig.m +++ b/mDNSMacOSX/PreferencePane/ddnswriteconfig.m @@ -45,6 +45,9 @@ Change History (most recent first): $Log: ddnswriteconfig.m,v $ +Revision 1.10 2007/11/30 23:43:04 cheshire +Fixed compile warning: declaration of 'access' shadows a global declaration + Revision 1.9 2007/09/18 19:09:02 cheshire mDNSResponderHelper (and other binaries) missing SCCS version strings @@ -313,14 +316,14 @@ MyMakeUidAccess(uid_t uid) 0 }; - SecAccessRef access = NULL; - (void) SecAccessCreateFromOwnerAndACL(&owner, 1, &acls, &access); - return access; + SecAccessRef a = NULL; + (void) SecAccessCreateFromOwnerAndACL(&owner, 1, &acls, &a); + return a; } static OSStatus -MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef access, UInt32 serviceNameLength, const char *serviceName, +MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef a, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData) { char * description = DYNDNS_KEYCHAIN_DESCRIPTION; @@ -340,7 +343,7 @@ MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef access, UInt32 ser { kSecCreatorItemAttr, creatorLength, (UInt32 *)&creator } }; SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs }; - err = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributes, passwordLength, passwordData, keychain, access, NULL); + err = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributes, passwordLength, passwordData, keychain, a, NULL); return err; } diff --git a/mDNSMacOSX/SamplemDNSClient.c b/mDNSMacOSX/SamplemDNSClient.c index c44edc8..6497498 100644 --- a/mDNSMacOSX/SamplemDNSClient.c +++ b/mDNSMacOSX/SamplemDNSClient.c @@ -30,6 +30,9 @@ Change History (most recent first): $Log: SamplemDNSClient.c,v $ +Revision 1.54 2007/11/30 23:39:55 cheshire +Fixed compile warning: declaration of 'client' shadows a global declaration + Revision 1.53 2007/09/18 19:09:02 cheshire mDNSResponderHelper (and other binaries) missing SCCS version strings @@ -111,9 +114,9 @@ static void MyHandleMachMessage(CFMachPortRef port, void *msg, CFIndex size, voi DNSServiceDiscovery_handleReply(msg); } -static int AddDNSServiceClientToRunLoop(dns_service_discovery_ref client) +static int AddDNSServiceClientToRunLoop(dns_service_discovery_ref c) { - mach_port_t port = DNSServiceDiscoveryMachPort(client); + mach_port_t port = DNSServiceDiscoveryMachPort(c); if (!port) return(-1); else @@ -316,7 +319,7 @@ static void reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *cont int main(int argc, char **argv) { const char *progname = strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0]; - char *dom; + char *d; setlinebuf(stdout); // Want to see lines as they appear, not block buffered if (argc < 2) goto Fail; // Minimum command line is the command name and one argument @@ -334,17 +337,17 @@ int main(int argc, char **argv) break; case 'B': if (argc < optind+1) goto Fail; - dom = (argc < optind+2) ? "" : argv[optind+1]; // Missing domain argument is the same as empty string i.e. use system default(s) - if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string - printf("Browsing for %s%s\n", argv[optind+0], dom); - client = DNSServiceBrowserCreate(argv[optind+0], dom, browse_reply, nil); + d = (argc < optind+2) ? "" : argv[optind+1]; // Missing domain argument is the same as empty string i.e. use system default(s) + if (d[0] == '.' && d[1] == 0) d[0] = 0; // We allow '.' on the command line as a synonym for empty string + printf("Browsing for %s%s\n", argv[optind+0], d); + client = DNSServiceBrowserCreate(argv[optind+0], d, browse_reply, nil); break; case 'L': if (argc < optind+2) goto Fail; - dom = (argc < optind+3) ? "" : argv[optind+2]; - if (dom[0] == '.' && dom[1] == 0) dom = "local"; // We allow '.' on the command line as a synonym for "local" - printf("Lookup %s.%s%s\n", argv[optind+0], argv[optind+1], dom); - client = DNSServiceResolverResolve(argv[optind+0], argv[optind+1], dom, resolve_reply, nil); + d = (argc < optind+3) ? "" : argv[optind+2]; + if (d[0] == '.' && d[1] == 0) d = "local"; // We allow '.' on the command line as a synonym for "local" + printf("Lookup %s.%s%s\n", argv[optind+0], argv[optind+1], d); + client = DNSServiceResolverResolve(argv[optind+0], argv[optind+1], d, resolve_reply, nil); break; case 'R': if (argc < optind+4) goto Fail; diff --git a/mDNSMacOSX/daemon.c b/mDNSMacOSX/daemon.c index e7b7b9d..8acaf29 100644 --- a/mDNSMacOSX/daemon.c +++ b/mDNSMacOSX/daemon.c @@ -30,6 +30,39 @@ Change History (most recent first): $Log: daemon.c,v $ +Revision 1.356 2007/12/18 00:28:56 cheshire + BTMM: Need to deregister records and services on shutdown/sleep +Error in ReadyForSleep() logic -- missing "not" in "!mDNSOpaque16IsZero(q->TargetQID)" + +Revision 1.355 2007/12/17 22:29:22 cheshire + BTMM: Need to deregister records and services on shutdown/sleep +Log message indicating when we make IOAllowPowerChange call; make sure nextTimerEvent is set appropriately + +Revision 1.354 2007/12/15 01:12:28 cheshire + Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown + +Revision 1.353 2007/12/14 19:14:02 cheshire +Added (commented out) code for testing sleep/wake + +Revision 1.352 2007/12/14 00:58:29 cheshire + BTMM: Need to deregister records and services on shutdown/sleep +Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep +until TLS/TCP deregistrations have completed (up to five seconds maximum) + +Revision 1.351 2007/12/12 21:34:18 cheshire +Now that "Not getting Keychain events" is apparently fixed, +it makes sense to reduce our workaround retry count from 5 to 2 retries. Once we've +confirmed that the bug is definitely fixed we'll remove the workaround altogether. + +Revision 1.350 2007/12/07 00:45:58 cheshire + BTMM: Need to clean up registrations on shutdown + +Revision 1.349 2007/12/04 22:00:54 cheshire +Fixed mistake in comment + +Revision 1.348 2007/12/01 00:27:43 cheshire +Fixed compile warning: declaration of 'r' shadows a previous local + Revision 1.347 2007/11/02 22:00:13 cheshire BTMM: Work around keychain notification bug Need to hold the lock while calling SetDomainSecrets @@ -709,9 +742,9 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m) } while (x->results) { - DNSServiceBrowserResult *r = x->results; + DNSServiceBrowserResult *t = x->results; x->results = x->results->next; - freeL("DNSServiceBrowserResult", r); + freeL("DNSServiceBrowserResult", t); } freeL("DNSServiceBrowser", x); return; @@ -999,10 +1032,10 @@ mDNSexport void machserver_automatic_browse_domain_changed(const domainname *d, { if (SameDomainName(&(*q)->domain, d)) { - DNSServiceBrowserQuestion *remove = *q; + DNSServiceBrowserQuestion *rem = *q; *q = (*q)->next; - mDNS_StopQueryWithRemoves(&mDNSStorage, &remove->q); - freeL("DNSServiceBrowserQuestion", remove ); + mDNS_StopQueryWithRemoves(&mDNSStorage, &rem->q); + freeL("DNSServiceBrowserQuestion", rem); return; } q = &(*q)->next; @@ -1111,11 +1144,11 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query) if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv4) { - struct sockaddr_in *sin = (struct sockaddr_in*)&interface; - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_port = 0; - sin->sin_addr.s_addr = ifx->ifinfo.ip.ip.v4.NotAnInteger; + struct sockaddr_in *s = (struct sockaddr_in*)&interface; + s->sin_len = sizeof(*s); + s->sin_family = AF_INET; + s->sin_port = 0; + s->sin_addr.s_addr = ifx->ifinfo.ip.ip.v4.NotAnInteger; } else if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv6) { @@ -1130,11 +1163,11 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query) if (query->info->ip.type == mDNSAddrType_IPv4) { - struct sockaddr_in *sin = (struct sockaddr_in*)&address; - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_port = query->info->port.NotAnInteger; - sin->sin_addr.s_addr = query->info->ip.ip.v4.NotAnInteger; + struct sockaddr_in *s = (struct sockaddr_in*)&address; + s->sin_len = sizeof(*s); + s->sin_family = AF_INET; + s->sin_port = query->info->port.NotAnInteger; + s->sin_addr.s_addr = query->info->ip.ip.v4.NotAnInteger; } else { @@ -1474,9 +1507,9 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t un if (x->DefaultDomain) { - DNameListElem *ptr; - for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next) - AddServiceInstance(x, &ptr->name); + DNameListElem *p; + for (p = AutoRegistrationDomains; p; p = p->next) + AddServiceInstance(x, &p->name); } // Succeeded: Wrap up and return @@ -1909,9 +1942,9 @@ mDNSlocal kern_return_t destroyBootstrapService() return bootstrap_register(server_priv_port, (char*)kmDNSBootstrapName, MACH_PORT_NULL); } -mDNSlocal void ExitCallback(int signal) +mDNSlocal void ExitCallback(int sig) { - (void)signal; // Unused + (void)sig; // Unused LogMsgIdent(mDNSResponderVersionString, "stopping"); debugf("ExitCallback"); @@ -1928,27 +1961,27 @@ mDNSlocal void ExitCallback(int signal) while (DNSServiceRegistrationList) AbortClient(DNSServiceRegistrationList ->ClientMachPort, DNSServiceRegistrationList); - debugf("ExitCallback: mDNS_Close"); - mDNS_Close(&mDNSStorage); if (udsserver_exit(launchd_fd) < 0) LogMsg("ExitCallback: udsserver_exit failed"); - exit(0); + + debugf("ExitCallback: mDNS_StartExit"); + mDNS_StartExit(&mDNSStorage); } // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit -mDNSlocal void HandleSIG(int signal) +mDNSlocal void HandleSIG(int sig) { debugf(" "); - debugf("HandleSIG %d", signal); + debugf("HandleSIG %d", sig); mach_msg_header_t header; header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); header.msgh_remote_port = signal_port; header.msgh_local_port = MACH_PORT_NULL; header.msgh_size = sizeof(header); - header.msgh_id = signal; + header.msgh_id = sig; if (mach_msg_send(&header) != MACH_MSG_SUCCESS) { - LogMsg("HandleSIG %d: mach_msg_send failed", signal); - if (signal == SIGTERM || signal == SIGINT) exit(-1); + LogMsg("HandleSIG %d: mach_msg_send failed", sig); + if (sig == SIGTERM || sig == SIGINT) exit(-1); } } @@ -2068,7 +2101,8 @@ mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void case SIGINT: case SIGTERM: ExitCallback(msg_header->msgh_id); break; case SIGINFO: INFOCallback(); break; - case SIGUSR1: LogMsg("SIGUSR1: Simulate Network Configuration Change Event"); + case SIGUSR1: // mDNSCoreMachineSleep(m, !m->SleepState); break; + LogMsg("SIGUSR1: Simulate Network Configuration Change Event"); mDNSMacOSXNetworkChanged(m); // Simulate KeychainChanged @@ -2156,9 +2190,9 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m) // See Not getting Keychain Changed events when enabling BTMM if (m->p->KeyChainBugTimer && now - m->p->KeyChainBugTimer >= 0) { - m->p->KeyChainBugTimer = NonZeroTime(now + m->p->KeyChainBugInterval); m->p->KeyChainBugInterval *= 2; - if (m->p->KeyChainBugInterval > 16 * mDNSPlatformOneSecond) m->p->KeyChainBugTimer = 0; + m->p->KeyChainBugTimer = NonZeroTime(now + m->p->KeyChainBugInterval); + if (m->p->KeyChainBugInterval > 2 * mDNSPlatformOneSecond) m->p->KeyChainBugTimer = 0; mDNS_Lock(m); SetDomainSecrets(m); mDNS_Unlock(m); @@ -2263,7 +2297,7 @@ mDNSlocal void ShowTaskSchedulingError(mDNS *const m) LogMsg("Task Scheduling Error: Continuously busy for more than a second"); - // NOTE: To accurately diagnose *why* we're busy, the debugging code here to show needs to mirror the logic in GetNextScheduledEvent + // NOTE: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0)) LogMsg("Task Scheduling Error: NewQuestion %##s (%s)", @@ -2293,12 +2327,33 @@ mDNSlocal void ShowTaskSchedulingError(mDNS *const m) mDNS_Unlock(&mDNSStorage); } +mDNSlocal mDNSBool ReadyForSleep(mDNS *m) + { + (void)m; + + // 1. Scan list of private LLQs, and make sure they've all completed their handshake with the server + DNSQuestion *q; + for (q = m->Questions; q; q = q->next) + if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp) return(mDNSfalse); + + // 2. Scan list of registered records + AuthRecord *rr; + for (rr = m->ResourceRecords; rr; rr = rr->next) + if (rr->state == regState_Refresh && rr->tcp) return(mDNSfalse); + + // 2. Scan list of registered services + ServiceRecordSet *srs; + for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next) + if (srs->state == regState_NoTarget && srs->tcp) return(mDNSfalse); + + return(mDNStrue); + } + mDNSlocal void KQWokenFlushBytes(int fd, __unused short filter, __unused void *context) { // Read all of the bytes so we won't wake again. char buffer[100]; - ssize_t read = sizeof(buffer); - while (read > 0) read = recv(fd, buffer, sizeof(buffer), MSG_DONTWAIT); + while (recv(fd, buffer, sizeof(buffer), MSG_DONTWAIT) > 0) continue; } mDNSlocal void * KQueueLoop(void *m_param) @@ -2334,9 +2389,39 @@ mDNSlocal void * KQueueLoop(void *m_param) mDNSs32 end = mDNSPlatformRawTime(); if (end - start >= WatchDogReportingThreshold) LogOperation("WARNING: Idle task took %dms to complete", end - start); - + + mDNSs32 now = mDNS_TimeNow(m); + + if (m->ShutdownTime) + { + if (mDNS_ExitNow(m, now)) + { + LogOperation("mDNS_FinalExit"); + mDNS_FinalExit(&mDNSStorage); + usleep(1000); // Little 1ms pause before exiting, so we don't lose our final syslog messages + exit(0); + } + if (nextTimerEvent - m->ShutdownTime >= 0) + nextTimerEvent = m->ShutdownTime; + } + + if (m->p->SleepLimit) + { + mDNSBool ready = ReadyForSleep(m); + if (ready || now - m->p->SleepLimit >= 0) + { + LogOperation("IOAllowPowerChange(%lX) %s at %ld (%d ticks remaining)", m->p->SleepCookie, + ready ? "ready for sleep" : "giving up", now, m->p->SleepLimit - now); + m->p->SleepLimit = 0; + IOAllowPowerChange(m->p->PowerConnection, m->p->SleepCookie); + } + else + if (nextTimerEvent - m->p->SleepLimit >= 0) + nextTimerEvent = m->p->SleepLimit; + } + // Convert absolute wakeup time to a relative time from now - mDNSs32 ticks = nextTimerEvent - mDNS_TimeNow(m); + mDNSs32 ticks = nextTimerEvent - now; if (ticks < 1) ticks = 1; static mDNSs32 RepeatedBusy = 0; // Debugging sanity check, to guard against CPU spins @@ -2401,14 +2486,14 @@ mDNSlocal void * KQueueLoop(void *m_param) for (i = 0; i < events_found; i++) { const KQueueEntry *const kqentry = new_events[i].udata; - mDNSs32 start = mDNSPlatformRawTime(); + mDNSs32 stime = mDNSPlatformRawTime(); #if LogAllOperations || MDNS_DEBUGMSGS const char *const KQtask = kqentry->KQtask; // Grab a copy in case KQcallback deletes the task #endif kqentry->KQcallback(new_events[i].ident, new_events[i].filter, kqentry->KQcontext); - mDNSs32 end = mDNSPlatformRawTime(); - if (end - start >= WatchDogReportingThreshold) - LogOperation("WARNING: %s took %dms to complete", KQtask, end - start); + mDNSs32 etime = mDNSPlatformRawTime(); + if (etime - stime >= WatchDogReportingThreshold) + LogOperation("WARNING: %s took %dms to complete", KQtask, etime - stime); } } } diff --git a/mDNSMacOSX/helper-error.h b/mDNSMacOSX/helper-error.h index 767b167..3552c8a 100644 --- a/mDNSMacOSX/helper-error.h +++ b/mDNSMacOSX/helper-error.h @@ -17,6 +17,10 @@ Change History (most recent first): $Log: helper-error.h,v $ +Revision 1.8 2007/11/07 00:22:30 jgraessley +Bug #: mDNSResponder doesn't build without IPSec +Reviewed by: Stuart Cheshire + Revision 1.7 2007/09/12 00:42:47 mcguire BTMM: Need to clean up security associations @@ -73,3 +77,4 @@ ERROR(kmDNSHelperIPsecPolicyCreationFailed, "Could not create IPsec policy ERROR(kmDNSHelperIPsecPolicySetFailed, "Could not set IPsec policy") ERROR(kmDNSHelperIPsecRemoveSAFailed, "Could not remove IPsec SA") ERROR(kmDNSHelperIPsecPolicySocketCreationFailed, "Could not create IPsec policy socket") +ERROR(kmDNSHelperIPsecDisabled, "IPSec support was not compiled in to the helper") diff --git a/mDNSMacOSX/helper-stubs.c b/mDNSMacOSX/helper-stubs.c index 3d625ca..e2084e0 100644 --- a/mDNSMacOSX/helper-stubs.c +++ b/mDNSMacOSX/helper-stubs.c @@ -16,6 +16,9 @@ Change History (most recent first): $Log: helper-stubs.c,v $ +Revision 1.6 2007/12/10 23:23:48 cheshire +Removed unnecessary log message ("mDNSKeychainGetSecrets failed 0 00000000" because mDNSKeychainGetSecrets was failing to return a valid array) + Revision 1.5 2007/09/07 22:44:03 mcguire Move CFUserNotification code to mDNSResponderHelper @@ -72,7 +75,6 @@ mDNSHelperError(int err) return p; } - /* Ugly but handy. */ #define MACHRETRYLOOP_BEGIN(kr, retry, err, fin) for (;;) { @@ -171,13 +173,11 @@ mDNSKeychainGetSecrets(CFArrayRef *result) int retry = 0; int err = 0; - MACHRETRYLOOP_BEGIN(kr, retry, err, fin); kr = proxy_mDNSKeychainGetSecrets(getHelperPort(retry), &numsecrets, (vm_offset_t *)&secrets, &secretsCnt, &err); MACHRETRYLOOP_END(kr, retry, err, fin); - if (0 == numsecrets) - goto fin; + if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, secrets, secretsCnt, kCFAllocatorNull))) { diff --git a/mDNSMacOSX/helper.c b/mDNSMacOSX/helper.c index 7225742..8f4b8f8 100644 --- a/mDNSMacOSX/helper.c +++ b/mDNSMacOSX/helper.c @@ -17,6 +17,16 @@ Change History (most recent first): $Log: helper.c,v $ +Revision 1.23 2007/11/30 23:21:51 cheshire +Rename variables to eliminate "declaration of 'sin_loc' shadows a previous local" warning + +Revision 1.22 2007/11/27 00:08:49 jgraessley + Interface specific resolvers not setup correctly + +Revision 1.21 2007/11/07 00:22:30 jgraessley +Bug #: mDNSResponder doesn't build without IPSec +Reviewed by: Stuart Cheshire + Revision 1.20 2007/09/12 18:07:44 cheshire Fix compile errors ("passing argument from incompatible pointer type") @@ -103,6 +113,7 @@ Revision 1.1 2007/08/08 22:34:58 mcguire #include #include #include +#include #include "mDNSEmbeddedAPI.h" #include "dns_sd.h" #include "dnssd_ipc.h" @@ -110,8 +121,10 @@ Revision 1.1 2007/08/08 22:34:58 mcguire #include "helper.h" #include "helpermsgServer.h" #include "helper-server.h" +#include "ipsec_options.h" #if TARGET_OS_EMBEDDED +#define NO_CFUSERNOTIFICATION 1 #define NO_SECURITYFRAMEWORK 1 #endif @@ -153,6 +166,7 @@ authorized(audit_token_t *token) return ok; } +#ifndef MDNS_NO_IPSEC static void closefds(int from) { @@ -175,6 +189,7 @@ closefds(int from) } closedir(dirp); } +#endif kern_return_t do_mDNSIdleExit(__unused mach_port_t port, audit_token_t token) @@ -272,6 +287,7 @@ char userhostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name the use char lastcompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name saved to preferences char lasthostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name saved to preferences +#ifndef NO_CFUSERNOTIFICATION static CFStringRef CFS_OQ = NULL; static CFStringRef CFS_CQ = NULL; static CFStringRef CFS_Format = NULL; @@ -400,9 +416,11 @@ static CFMutableArrayRef GetHeader(const char* oldname, const char* newname, con return alertHeader; } +#endif /* ndef NO_CFUSERNOTIFICATION */ static void update_notification(void) { +#ifndef NO_CFUSERNOTIFICATION debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname); if (!CFS_OQ) { @@ -453,6 +471,7 @@ static void update_notification(void) ShowNameConflictNotification(header, *subtext); CFRelease(header); } +#endif } kern_return_t @@ -874,6 +893,7 @@ fin: #endif } +#ifndef MDNS_NO_IPSEC typedef enum _mDNSTunnelPolicyWhich { kmDNSTunnelPolicySetup, @@ -981,11 +1001,13 @@ fin: close(s); return err; } +#endif /* ifndef MDNS_NO_IPSEC */ int do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port, int updown, v6addr_t address, int *err, audit_token_t token) { +#ifndef MDNS_NO_IPSEC debug("entry"); *err = 0; if (!authorized(&token)) @@ -1008,10 +1030,15 @@ do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port, int updown, debug("succeeded"); fin: +#else + (void)port; (void)updown; (void)address; (void)token; + *err = kmDNSHelperIPsecDisabled; +#endif update_idle_timer(); return KERN_SUCCESS; } +#ifndef MDNS_NO_IPSEC static const char racoon_config_path[] = "/etc/racoon/remote/anonymous.conf"; static const char racoon_config_path_orig[] = "/etc/racoon/remote/anonymous.conf.orig"; @@ -1237,9 +1264,12 @@ kickRacoon(void) return startRacoon(); } +#endif /* ndef MDNS_NO_IPSEC */ + int do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *keydata, int *err, audit_token_t token) { +#ifndef MDNS_NO_IPSEC debug("entry"); *err = 0; @@ -1271,10 +1301,16 @@ do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *keydat debug("succeeded"); fin: +#else + (void)port; (void)updown; (void)keydata; (void)token; + *err = kmDNSHelperIPsecDisabled; +#endif update_idle_timer(); return KERN_SUCCESS; } +#ifndef MDNS_NO_IPSEC + static unsigned int routeSeq = 1; static int @@ -1532,8 +1568,8 @@ doTunnelPolicy(mDNSTunnelPolicyWhich which, v6addr_t rmt_inner, uint8_t rmt_bits, v4addr_t rmt_outer, uint16_t rmt_port) { - struct sockaddr_in6 sin_loc; - struct sockaddr_in6 sin_rmt; + struct sockaddr_in6 sin6_loc; + struct sockaddr_in6 sin6_rmt; ipsec_policy_t policy = NULL; size_t len = 0; int s = -1; @@ -1549,17 +1585,17 @@ doTunnelPolicy(mDNSTunnelPolicyWhich which, goto fin; } - memset(&sin_loc, 0, sizeof(sin_loc)); - sin_loc.sin6_len = sizeof(sin_loc); - sin_loc.sin6_family = AF_INET6; - sin_loc.sin6_port = htons(0); - memcpy(&sin_loc.sin6_addr, loc_inner, sizeof(sin_loc.sin6_addr)); + memset(&sin6_loc, 0, sizeof(sin6_loc)); + sin6_loc.sin6_len = sizeof(sin6_loc); + sin6_loc.sin6_family = AF_INET6; + sin6_loc.sin6_port = htons(0); + memcpy(&sin6_loc.sin6_addr, loc_inner, sizeof(sin6_loc.sin6_addr)); - memset(&sin_rmt, 0, sizeof(sin_rmt)); - sin_rmt.sin6_len = sizeof(sin_rmt); - sin_rmt.sin6_family = AF_INET6; - sin_rmt.sin6_port = htons(0); - memcpy(&sin_rmt.sin6_addr, rmt_inner, sizeof(sin_rmt.sin6_addr)); + memset(&sin6_rmt, 0, sizeof(sin6_rmt)); + sin6_rmt.sin6_len = sizeof(sin6_rmt); + sin6_rmt.sin6_family = AF_INET6; + sin6_rmt.sin6_port = htons(0); + memcpy(&sin6_rmt.sin6_addr, rmt_inner, sizeof(sin6_rmt.sin6_addr)); int setup = which != kmDNSTunnelPolicyTeardown; @@ -1569,8 +1605,8 @@ doTunnelPolicy(mDNSTunnelPolicyWhich which, &policy, &len))) goto fin; if (0 != (err = sendPolicy(s, setup, - (struct sockaddr *)&sin_rmt, rmt_bits, - (struct sockaddr *)&sin_loc, loc_bits, + (struct sockaddr *)&sin6_rmt, rmt_bits, + (struct sockaddr *)&sin6_loc, loc_bits, policy, len))) goto fin; if (NULL != policy) @@ -1584,8 +1620,8 @@ doTunnelPolicy(mDNSTunnelPolicyWhich which, &policy, &len))) goto fin; if (0 != (err = sendPolicy(s, setup, - (struct sockaddr *)&sin_loc, loc_bits, - (struct sockaddr *)&sin_rmt, rmt_bits, + (struct sockaddr *)&sin6_loc, loc_bits, + (struct sockaddr *)&sin6_rmt, rmt_bits, policy, len))) goto fin; @@ -1620,12 +1656,15 @@ fin: return err; } +#endif /* ndef MDNS_NO_IPSEC */ + int do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete, v6addr_t loc_inner, v4addr_t loc_outer, uint16_t loc_port, v6addr_t rmt_inner, v4addr_t rmt_outer, uint16_t rmt_port, const char *keydata, int *err, audit_token_t token) { +#ifndef MDNS_NO_IPSEC static const char config[] = "%s" "remote %s [%u] {\n" @@ -1773,6 +1812,12 @@ fin: if (0 <= fd) close(fd); unlink(tmp_path); +#else + (void)replacedelete; (void)loc_inner; (void)loc_outer; (void)loc_port; (void)rmt_inner; + (void)rmt_outer; (void)rmt_port; (void)keydata; (void)token; + + *err = kmDNSHelperIPsecDisabled; +#endif /* MDNS_NO_IPSEC */ update_idle_timer(); return KERN_SUCCESS; } diff --git a/mDNSMacOSX/mDNSMacOSX.c b/mDNSMacOSX/mDNSMacOSX.c index 5cba5ef..a198741 100644 --- a/mDNSMacOSX/mDNSMacOSX.c +++ b/mDNSMacOSX/mDNSMacOSX.c @@ -17,6 +17,49 @@ Change History (most recent first): $Log: mDNSMacOSX.c,v $ +Revision 1.521 2007/12/14 00:58:28 cheshire + BTMM: Need to deregister records and services on shutdown/sleep +Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep +until TLS/TCP deregistrations have completed (up to five seconds maximum) + +Revision 1.520 2007/12/10 23:01:01 cheshire +Remove some unnecessary log messages + +Revision 1.519 2007/12/06 00:22:27 mcguire + BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp) + +Revision 1.518 2007/12/05 01:52:30 cheshire + BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname +Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to) + +Revision 1.517 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.516 2007/12/01 01:21:27 jgraessley + mDNSResponder unicast DNS improvements + +Revision 1.515 2007/12/01 00:40:00 cheshire +Add mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg abstractions, to facilitate EFI conversion + +Revision 1.514 2007/12/01 00:38:32 cheshire +Fixed compile warning: declaration of 'index' shadows a global declaration + +Revision 1.513 2007/11/27 00:08:49 jgraessley + Interface-specific resolvers not setup correctly + +Revision 1.512 2007/11/16 22:09:26 cheshire +Added missing type information in mDNSPlatformTCPCloseConnection debugging log message + +Revision 1.511 2007/11/14 23:06:13 cheshire + IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces + +Revision 1.510 2007/11/14 22:29:19 cheshire +Updated comments and debugging log messages + +Revision 1.509 2007/11/14 01:07:53 cheshire +Updated comments + Revision 1.508 2007/11/02 21:59:37 cheshire Added comment about locking @@ -62,7 +105,7 @@ Revision 1.496 2007/10/04 20:33:05 mcguire BTMM: Racoon configuration removed when network changes Revision 1.495 2007/10/02 05:03:38 cheshire -Fix bugus indentation in mDNSPlatformDynDNSHostNameStatusChanged +Fix bogus indentation in mDNSPlatformDynDNSHostNameStatusChanged Revision 1.494 2007/09/29 20:40:19 cheshire Crash in ReissueBlockedQuestions @@ -670,7 +713,6 @@ Add (commented out) trigger value for testing "mach_absolute_time went backwards #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon #include "PlatformCommon.h" - #include #include // For va_list support #include @@ -699,6 +741,7 @@ Add (commented out) trigger value for testing "mach_absolute_time went backwards #if TARGET_OS_EMBEDDED #define NO_SECURITYFRAMEWORK 1 +#define NO_CFUSERNOTIFICATION 1 #endif #ifndef NO_SECURITYFRAMEWORK @@ -821,42 +864,43 @@ mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh) return ifa; } +// To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type) { NetworkInterfaceInfoOSX *i; for (i = m->p->InterfaceList; i; i = i->next) if (i->Exists && !strcmp(i->ifa_name, ifname) && - ((AAAA_OVER_V4 ) || + ((type == AF_UNSPEC ) || (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) || (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i); return(NULL); } -mDNSlocal int myIfIndexToName(u_short index, char *name) +mDNSlocal int myIfIndexToName(u_short ifindex, char *name) { struct ifaddrs *ifa; for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next) if (ifa->ifa_addr->sa_family == AF_LINK) - if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == index) + if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex) { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; } return -1; } -mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index) +mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex) { NetworkInterfaceInfoOSX *i; - if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly); - if (index == kDNSServiceInterfaceIndexAny ) return(mDNSNULL); + if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly); + if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL); // Don't get tricked by inactive interfaces with no InterfaceID set for (i = m->p->InterfaceList; i; i = i->next) - if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID); + if (i->ifinfo.InterfaceID && i->scope_id == ifindex) return(i->ifinfo.InterfaceID); // Not found. Make sure our interface list is up to date, then try again. - LogOperation("InterfaceID for interface index %d not found; Updating interface list", index); + LogOperation("InterfaceID for interface index %d not found; Updating interface list", ifindex); mDNSMacOSXNetworkChanged(m); for (i = m->p->InterfaceList; i; i = i->next) - if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID); + if (i->ifinfo.InterfaceID && i->scope_id == ifindex) return(i->ifinfo.InterfaceID); return(mDNSNULL); } @@ -901,6 +945,12 @@ mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr) return result; } +struct UDPSocket_struct + { + mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCore expects every UDPSocket_struct to begin with mDNSIPPort port + KQSocketSet ss; + }; + // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket" // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface" // OR send via our primary v4 unicast socket @@ -920,11 +970,8 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms // anonymous socket created for this purpose, so that we'll receive the response. // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably. if (InterfaceID && !mDNSAddrIsDNSMulticast(dst)) - { - const DNSMessage *const m = (DNSMessage *)msg; - if ((m->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Query) + if ((((DNSMessage *)msg)->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Query) LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst, mDNSVal16(dstPort)); - } if (dst->type == mDNSAddrType_IPv4) { @@ -934,6 +981,12 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms sin_to->sin_port = dstPort.NotAnInteger; sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger; s = m->p->permanentsockets.sktv4; + +#ifdef _LEGACY_NAT_TRAVERSAL_ + if (m->SSDPSocket && mDNSSameIPPort(dstPort, SSDPPort)) + s = m->SSDPSocket->ss.sktv4; +#endif _LEGACY_NAT_TRAVERSAL_ + if (info) // Specify outgoing interface { if (!mDNSAddrIsDNSMulticast(dst)) @@ -1083,6 +1136,7 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max, { dstaddr->type = mDNSAddrType_IPv4; dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr); + //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4); } if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF) { @@ -1129,7 +1183,7 @@ mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context) while (1) { mDNSAddr senderAddr, destAddr; - mDNSIPPort senderPort, destPort = MulticastDNSPort; + mDNSIPPort senderPort, destPort = (m->SSDPSocket && ss == &m->SSDPSocket->ss ? m->SSDPSocket->port : MulticastDNSPort); struct sockaddr_storage from; size_t fromlen = sizeof(from); char packetifname[IF_NAMESIZE] = ""; @@ -1140,10 +1194,10 @@ mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context) count++; if (from.ss_family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in*)&from; + struct sockaddr_in *s = (struct sockaddr_in*)&from; senderAddr.type = mDNSAddrType_IPv4; - senderAddr.ip.v4.NotAnInteger = sin->sin_addr.s_addr; - senderPort.NotAnInteger = sin->sin_port; + senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr; + senderPort.NotAnInteger = s->sin_port; //LogOperation("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname); } else if (from.ss_family == AF_INET6) @@ -1318,9 +1372,9 @@ mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context) #endif /* NO_SECURITYFRAMEWORK */ } - mDNSBool connect = !sock->connected; + mDNSBool c = !sock->connected; sock->connected = mDNStrue; - sock->callback(sock, sock->context, connect, err); + sock->callback(sock, sock->context, c, err); // NOTE: the callback may call CloseConnection here, which frees the context structure! } @@ -1532,7 +1586,7 @@ mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock) sock->fd = -1; } - freeL("mDNSPlatformTCPCloseConnection", sock); + freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock); } } @@ -1627,7 +1681,7 @@ mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock) // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries -mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family) +mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport) { const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6; @@ -1677,6 +1731,7 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa listening_sockaddr.sin_addr.s_addr = 0; // Want to receive multicasts AND unicasts on this socket err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr)); if (err) { errstr = "bind"; goto fail; } + if (outport) outport->NotAnInteger = listening_sockaddr.sin_port; } else if (sa_family == AF_INET6) { @@ -1724,6 +1779,7 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa listening_sockaddr6.sin6_scope_id = 0; err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6)); if (err) { errstr = "bind"; goto fail; } + if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port; } fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking @@ -1753,11 +1809,6 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa return(err); } -struct UDPSocket_struct - { - KQSocketSet ss; - }; - mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort port) { mStatus err; @@ -1767,7 +1818,8 @@ mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort port p->ss.m = m; p->ss.sktv4 = -1; p->ss.sktv6 = -1; - err = SetupSocket(&p->ss, port, AF_INET); + p->port = zeroIPPort; + err = SetupSocket(&p->ss, port, AF_INET, &p->port); if (err) { // In customer builds we don't want to log failures with port 5351, because this is a known issue @@ -2148,7 +2200,7 @@ mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info) err = mDNS_Register(m, &info->AutoTunnelService); if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c); - LogMsg("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]", + LogOperation("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]", info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(info->AutoTunnelNAT.IntPort), info->AutoTunnelHostRecord.namestorage.c, &m->AutoTunnelHostAddr); } @@ -2208,7 +2260,7 @@ mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n) LogOperation("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s", n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), m->hostlabel.c, info->domain.c); - m->NextSRVUpdate = m->timenow; + m->NextSRVUpdate = NonZeroTime(m->timenow); DeregisterAutoTunnelRecords(m,info); RegisterAutoTunnelRecords(m,info); @@ -2247,7 +2299,7 @@ mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m) if (!m->AutoTunnelHostAddrActive) { m->AutoTunnelHostAddrActive = mDNStrue; - LogMsg("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr); + LogOperation("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr); (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp, m->AutoTunnelHostAddr.b); } @@ -2291,14 +2343,14 @@ mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew) // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3]) -mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success) +mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype) { DNSQuestion *q = m->Questions; while (q) { - if (q->NoAnswer == NoAnswer_Suspended && q->qtype == kDNSType_AAAA && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d)) + if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d)) { - LogOperation("Restart %##s", q->qname.c); + LogOperation("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); mDNSQuestionCallback *tmp = q->QuestionCallback; q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel mDNS_StopQuery(m, q); @@ -2318,12 +2370,24 @@ mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool su } } +mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success) + { + // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has + // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN. + // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller -- + // even if the name does have a valid AAAA record, we don't want clients trying to connect to it without a properly encrypted tunnel. + // 3. For A queries we never fabricate failures -- if a BTTM service is really using raw IPv4, then it doesn't need the IPv6 tunnel. + ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA); + ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A); + } + mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success) { ClientTunnel **p = &m->TunnelClients; while (*p != tun && *p) p = &(*p)->next; if (*p) *p = tun->next; ReissueBlockedQuestions(m, &tun->dstname, success); + LogOperation("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun); freeL("ClientTunnel", tun); } @@ -2337,7 +2401,7 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R if (!answer->rdlength) { - LogOperation("AutoTunnelCallback NXDOMAIN %##s", question->qname.c); + LogOperation("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse); return; } @@ -2346,7 +2410,7 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R { if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr)) { - LogOperation("AutoTunnelCallback: supressing tunnel to self %.16a", &answer->rdata->u.ipv6); + LogOperation("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6); UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue); return; } @@ -2402,6 +2466,7 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R } else needSetKeys = mDNSfalse; + LogOperation("AutoTunnelCallback: Disposing ClientTunnel %p", tun); freeL("ClientTunnel", old); } } @@ -2424,7 +2489,7 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q) ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel)); if (!p) return; AssignDomainName(&p->dstname, &q->qname); - p->markedForDeletion = mDNSfalse; + p->MarkedForDeletion = mDNSfalse; p->loc_inner = zerov6Addr; p->loc_outer = zerov4Addr; p->rmt_inner = zerov6Addr; @@ -2432,7 +2497,7 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q) p->rmt_outer_port = zeroIPPort; mDNS_snprintf(p->b64keydata, sizeof(p->b64keydata), "%s", q->AuthInfo->b64keydata); p->next = m->TunnelClients; - m->TunnelClients = p; // Intentionally build list in reverse order + m->TunnelClients = p; // We intentionally build list in reverse order p->q.InterfaceID = mDNSInterface_Any; p->q.Target = zeroAddr; @@ -2446,7 +2511,7 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q) p->q.QuestionCallback = AutoTunnelCallback; p->q.QuestionContext = p; - LogOperation("AddNewClientTunnel start %##s (%s)%s", &p->q.qname.c, DNSTypeName(p->q.qtype), q->LongLived ? " LongLived" : ""); + LogOperation("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : ""); mDNS_StartQuery_internal(m, &p->q); } @@ -2701,8 +2766,8 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) for (i = m->p->InterfaceList; i; i = i->next) if (i->Exists) { - NetworkInterfaceInfo *n = &i->ifinfo; - NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family); + NetworkInterfaceInfo *const n = &i->ifinfo; + NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family); if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifa_name); if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary) // Sanity check @@ -2717,10 +2782,12 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) // so we need to make sure we call mDNS_DeregisterInterface() before disposing it. // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it n->InterfaceID = (mDNSInterfaceID)primary; + // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away. // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds. // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario. i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60); + mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting); if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++; LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s", @@ -2728,35 +2795,65 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) i->Flashing ? " (Flashing)" : "", i->Occulting ? " (Occulting)" : "", n->InterfaceActive ? " (Primary)" : ""); - } - if (!n->McastTxRx) - debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip); - else - { - if (i->sa_family == AF_INET) + if (!n->McastTxRx) + debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip); + else { - struct ip_mreq imr; - primary->ifa_v4addr.s_addr = i->ifinfo.ip.ip.v4.NotAnInteger; - imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger; - imr.imr_interface = primary->ifa_v4addr; - mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)); - // Joining same group twice can give "Address already in use" error -- no need to report that - if (err < 0 && errno != EADDRINUSE) - LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno)); - } + if (i->sa_family == AF_INET) + { + struct ip_mreq imr; + primary->ifa_v4addr.s_addr = i->ifinfo.ip.ip.v4.NotAnInteger; + imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger; + imr.imr_interface = primary->ifa_v4addr; + + // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first, + // before trying to join the group, to clear out stale kernel state which may be lingering. + // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state + // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group + // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't + // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state. + // Also, trying to make the code leave the group when the adapter is removed doesn't work either, + // because by the time we get the configuration change notification, the interface is already gone, + // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address"). + // IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces + if (SearchForInterfaceByName(m, i->ifa_name, AF_INET) == i) + { + LogOperation("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifa_name, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface); + mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr)); + if (err < 0 && (errno != EADDRNOTAVAIL || LogAllOperations)) + LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno)); + } + + LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifa_name, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface); + mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)); + // Joining same group twice can give "Address already in use" error -- no need to report that + if (err < 0 && (errno != EADDRINUSE || LogAllOperations)) + LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface); + } #ifndef NO_IPV6 - if (i->sa_family == AF_INET6) - { - struct ipv6_mreq i6mr; - i6mr.ipv6mr_interface = primary->scope_id; - i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6; - mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr)); - // Joining same group twice can give "Address already in use" error -- no need to report that - if (err < 0 && errno != EADDRINUSE) - LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err, errno, strerror(errno)); - } + if (i->sa_family == AF_INET6) + { + struct ipv6_mreq i6mr; + i6mr.ipv6mr_interface = primary->scope_id; + i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6; + + if (SearchForInterfaceByName(m, i->ifa_name, AF_INET6) == i) + { + LogOperation("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i->ifa_name, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); + mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr)); + if (err < 0 && (errno != EADDRNOTAVAIL || LogAllOperations)) + LogMsg("setsockopt - IPV6_LEAVE_GROUP error %ld errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); + } + + LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifa_name, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); + mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr)); + // Joining same group twice can give "Address already in use" error -- no need to report that + if (err < 0 && (errno != EADDRINUSE || LogAllOperations)) + LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); + } #endif + } } } return count; @@ -2780,14 +2877,12 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc) // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away. // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory // it refers to has gone away we'll crash. - // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away - // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.) NetworkInterfaceInfoOSX *i; int count = 0; for (i = m->p->InterfaceList; i; i = i->next) { // If this interface is no longer active, or its InterfaceID is changing, deregister it - NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family); + NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family); if (i->ifinfo.InterfaceID) if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary) { @@ -2801,14 +2896,17 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc) mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting); if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++; i->ifinfo.InterfaceID = mDNSNULL; - // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface, + // NOTE: If i->ifinfo.InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface, // so we need to make sure we call mDNS_DeregisterInterface() before disposing it. - // If n->InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it. + // If i->ifinfo.InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it. + + // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this + // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely. } } // Second pass: - // Now that everything that's going to deregister has done so, we can close sockets and free the memory + // Now that everything that's going to deregister has done so, we can clean up and free the memory NetworkInterfaceInfoOSX **p = &m->p->InterfaceList; while (*p) { @@ -2953,7 +3051,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN // The option may be in the form of interface=xxx where xxx is an interface name. if (strncmp(currentOption, kInterfaceSpecificOption, sizeof(kInterfaceSpecificOption) - 1) == 0) { - NetworkInterfaceInfoOSX *i; + NetworkInterfaceInfoOSX *ni; char ifname[IF_NAMESIZE+1]; mDNSu32 ifindex = 0; // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled. @@ -2961,12 +3059,12 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN strlcpy(ifname, currentOption + sizeof(kInterfaceSpecificOption)-1, sizeof(ifname)); ifindex = if_nametoindex(ifname); if (ifindex == 0) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - interface %s not found", ifname); continue; } - LogOperation("%s: Interface specific entry: %s on %s (%d)", __FUNCTION__, r->domain, ifname, ifindex); + LogOperation("%s: Interface-specific entry: %s on %s (%d)", __FUNCTION__, r->domain, ifname, ifindex); // Find the interface, can't use mDNSPlatformInterfaceIDFromInterfaceIndex // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist - for (i = m->p->InterfaceList; i; i = i->next) - if (i->ifinfo.InterfaceID && i->scope_id == ifindex) break; - if (i != NULL) interface = i->ifinfo.InterfaceID; + for (ni = m->p->InterfaceList; ni; ni = ni->next) + if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex) break; + if (ni != NULL) interface = ni->ifinfo.InterfaceID; if (interface == mDNSNULL) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex, ifname); continue; } } } @@ -2980,7 +3078,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN if (SetupAddr(&saddr, r->nameserver[n])) LogMsg("RegisterSplitDNS: bad IP address"); else { - DNSServer *s = mDNS_AddDNSServer(m, &d, mDNSInterface_Any, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort); + DNSServer *s = mDNS_AddDNSServer(m, &d, interface, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort); if (s && disabled) s->teststate = DNSServer_Disabled; } } @@ -3009,12 +3107,12 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL); if (store) { - CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS); - if (dict) + CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS); + if (ddnsdict) { if (fqdn) { - CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("HostNames")); + CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames")); if (fqdnArray && CFArrayGetCount(fqdnArray) > 0) { // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list @@ -3035,7 +3133,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN if (RegDomains) { - CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("RegistrationDomains")); + CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains")); if (regArray && CFArrayGetCount(regArray) > 0) { CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0); @@ -3059,7 +3157,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN if (BrowseDomains) { - CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("BrowseDomains")); + CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains")); if (browseArray) { for (i = 0; i < CFArrayGetCount(browseArray); i++) @@ -3083,7 +3181,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN } } } - CFRelease(dict); + CFRelease(ddnsdict); } if (RegDomains) @@ -3118,56 +3216,50 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN if (setservers || setsearch) { - CFStringRef key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS); - if (key) + CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DNS); + if (dict) { - CFDictionaryRef dict = SCDynamicStoreCopyValue(store, key); - if (dict) + if (setservers) { - if (setservers) + CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses); + if (values) { - CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses); - if (values) + for (i = 0; i < CFArrayGetCount(values); i++) { - for (i = 0; i < CFArrayGetCount(values); i++) - { - CFStringRef s = CFArrayGetValueAtIndex(values, i); - char buf[256]; - mDNSAddr addr = { mDNSAddrType_IPv4, { { { 0 } } } }; - if (s && CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8) && - inet_aton(buf, (struct in_addr *) &addr.ip.v4)) - mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort); - } + CFStringRef s = CFArrayGetValueAtIndex(values, i); + mDNSAddr addr = { mDNSAddrType_IPv4, { { { 0 } } } }; + if (s && CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8) && + inet_aton(buf, (struct in_addr *) &addr.ip.v4)) + mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort); } } - if (setsearch) + } + if (setsearch) + { + // Add the manual and/or DHCP-dicovered search domains + CFArrayRef searchDomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains); + if (searchDomains) { - // Add the manual and/or DHCP-dicovered search domains - CFArrayRef searchDomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains); - if (searchDomains) + for (i = 0; i < CFArrayGetCount(searchDomains); i++) { - for (i = 0; i < CFArrayGetCount(searchDomains); i++) - { - CFStringRef s = CFArrayGetValueAtIndex(searchDomains, i); - if (s && CFStringGetCString(s, buf, sizeof(buf), kCFStringEncodingUTF8)) - mDNS_AddSearchDomain_CString(buf); - } - } - else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName - { - // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains - // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if - // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and - // instead use the search domain list as the sole authority for what domains to search and in what order - // (and the domain from the "domain" field will also appear somewhere in that list). - CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName); - if (string && CFStringGetCString(string, buf, sizeof(buf), kCFStringEncodingUTF8)) + CFStringRef s = CFArrayGetValueAtIndex(searchDomains, i); + if (s && CFStringGetCString(s, buf, sizeof(buf), kCFStringEncodingUTF8)) mDNS_AddSearchDomain_CString(buf); } } - CFRelease(dict); + else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName + { + // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains + // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if + // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and + // instead use the search domain list as the sole authority for what domains to search and in what order + // (and the domain from the "domain" field will also appear somewhere in that list). + CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName); + if (string && CFStringGetCString(string, buf, sizeof(buf), kCFStringEncodingUTF8)) + mDNS_AddSearchDomain_CString(buf); + } } - CFRelease(key); + CFRelease(dict); } } CFRelease(store); @@ -3176,103 +3268,85 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r) { - SCDynamicStoreRef store = NULL; - CFDictionaryRef dict = NULL; - CFStringRef key = NULL; - CFStringRef string = NULL; - int nAdditions = 0; - int nDeletions = 0; char buf[256]; mStatus err = 0; + (void)m; // Unused - // get IPv4 settings - - store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL); - require_action(store, exit, err = mStatus_UnknownErr); - - key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4); - require_action(key, exit, err = mStatus_UnknownErr); - - dict = SCDynamicStoreCopyValue(store, key); - require_action(dict, exit, err = mStatus_UnknownErr); - - // handle router changes - - r->type = mDNSAddrType_IPv4; - r->ip.v4 = zerov4Addr; - - string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router); - - if (string) - { - struct sockaddr_in saddr; - - if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) - LogMsg("Could not convert router to CString"); - else - { - saddr.sin_len = sizeof(saddr); - saddr.sin_family = AF_INET; - saddr.sin_port = 0; - inet_aton(buf, &saddr.sin_addr); - - if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) debugf("Ignoring router %s (requires PPP connection)", buf); - else *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr; - } - } - - // handle primary interface changes - // if we gained or lost DNS servers (e.g. logged into VPN) "toggle" primary address so it gets re-registered even if it is unchanged - if (nAdditions || nDeletions) mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL); - - string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface); - - if (string) + SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL); + if (!store) LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed"); + else { - mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address? - struct ifaddrs *ifa = myGetIfAddrs(1); - - *v4 = *v6 = zeroAddr; - - if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; } - - // find primary interface in list - while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6)) + CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_IPv4); + if (dict) { - mDNSAddr tmp6 = zeroAddr; - if (!strcmp(buf, ifa->ifa_name)) + r->type = mDNSAddrType_IPv4; + r->ip.v4 = zerov4Addr; + CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router); + if (string) { - if (ifa->ifa_addr->sa_family == AF_INET) - { - if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr); - } - else if (ifa->ifa_addr->sa_family == AF_INET6) + if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) + LogMsg("Could not convert router to CString"); + else { - SetupAddr(&tmp6, ifa->ifa_addr); - if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001 - { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; } + struct sockaddr_in saddr; + saddr.sin_len = sizeof(saddr); + saddr.sin_family = AF_INET; + saddr.sin_port = 0; + inet_aton(buf, &saddr.sin_addr); + + if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) debugf("Ignoring router %s (requires PPP connection)", buf); + else *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr; } } - else + + string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface); + if (string) { - // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address - if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0]) + mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address? + struct ifaddrs *ifa = myGetIfAddrs(1); + + *v4 = *v6 = zeroAddr; + + if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; } + + // find primary interface in list + while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6)) { - SetupAddr(&tmp6, ifa->ifa_addr); - if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6; + mDNSAddr tmp6 = zeroAddr; + if (!strcmp(buf, ifa->ifa_name)) + { + if (ifa->ifa_addr->sa_family == AF_INET) + { + if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr); + } + else if (ifa->ifa_addr->sa_family == AF_INET6) + { + SetupAddr(&tmp6, ifa->ifa_addr); + if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001 + { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; } + } + } + else + { + // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address + if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0]) + { + SetupAddr(&tmp6, ifa->ifa_addr); + if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6; + } + } + ifa = ifa->ifa_next; } + + // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use + // V4 to communicate w/ our DNS server } - ifa = ifa->ifa_next; + + exit: + CFRelease(dict); } - - // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use - // V4 to communicate w/ our DNS server + CFRelease(store); } - - exit: - if (dict) CFRelease(dict); - if (key) CFRelease(key); - if (store) CFRelease(store); return err; } @@ -3357,7 +3431,7 @@ mDNSexport void SetDomainSecrets(mDNS *m) for (client = m->TunnelClients; client; client = client->next) { LogOperation("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c); - client->markedForDeletion = mDNStrue; + client->MarkedForDeletion = mDNStrue; } } #endif APPLE_OSX_mDNSResponder @@ -3429,7 +3503,7 @@ mDNSexport void SetDomainSecrets(mDNS *m) if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname)) { LogOperation("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c); - client->markedForDeletion = mDNSfalse; + client->MarkedForDeletion = mDNSfalse; // If the key has changed, reconfigure the tunnel if (strncmp(stringbuf, client->b64keydata, sizeof(client->b64keydata))) { @@ -3486,20 +3560,20 @@ mDNSexport void SetDomainSecrets(mDNS *m) #if APPLE_OSX_mDNSResponder { // clean up ClientTunnels - ClientTunnel **ptr = &m->TunnelClients; - while (*ptr) + ClientTunnel **pp = &m->TunnelClients; + while (*pp) { - if ((*ptr)->markedForDeletion) + if ((*pp)->MarkedForDeletion) { - ClientTunnel *cur = *ptr; - LogOperation("SetDomainSecrets: removing client %##s from list", cur->dstname.c); + ClientTunnel *cur = *pp; + LogOperation("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c); if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q); AutoTunnelSetKeys(cur, mDNSfalse); - *ptr = cur->next; + *pp = cur->next; freeL("ClientTunnel", cur); } else - ptr = &(*ptr)->next; + pp = &(*pp)->next; } DomainAuthInfo *info = m->AuthInfoList; @@ -3632,7 +3706,7 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0); int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0); if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/20; // If these were the only changes, shorten delay - + #if LogAllOperations int i; for (i=0; ip->NetworkChanged - NonZeroTime(m->timenow + delay) < 0) m->p->NetworkChanged = NonZeroTime(m->timenow + delay); + // If we have a global DNS change, then disregard delay and reconfigure immediately + if (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS) != 0) m->p->NetworkChanged = NonZeroTime(m->timenow); + // KeyChain frequently fails to notify clients of change events. To work around this // we set a timer and periodically poll to detect if any changes have occurred. // Without this Back To My Mac just does't work for a large number of users. @@ -3772,6 +3849,7 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag mDNS *const m = (mDNS *const)refcon; KQueueLock(m); (void)service; // Parameter not used + LogOperation("PowerChanged %X %lX", messageType, messageArgument); switch(messageType) { case kIOMessageCanSystemPowerOff: debugf ("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240 @@ -3795,7 +3873,15 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag mDNSMacOSXNetworkChanged(m); mDNSCoreMachineSleep(m, false); break; // E0000320 default: LogOperation("PowerChanged unknown message %X", messageType); break; } - IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument); + + if (!m->p->SleepLimit && messageType == kIOMessageSystemWillSleep) + { + m->p->SleepLimit = NonZeroTime(mDNS_TimeNow(m) + mDNSPlatformOneSecond * 5); + m->p->SleepCookie = (long)messageArgument; + } + else + IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument); + KQueueUnlock(m, "Sleep/Wake"); } #endif /* NO_IOPOWER */ @@ -3913,9 +3999,9 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) m->p->permanentsockets.kqsv4.KQcontext = m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets; m->p->permanentsockets.kqsv4.KQtask = m->p->permanentsockets.kqsv6.KQtask = "UDP packet reception"; - err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET); + err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL); #ifndef NO_IPV6 - err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6); + err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL); #endif struct sockaddr_in s4; @@ -3937,6 +4023,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) m->p->usernicelabel.c[0] = 0; m->p->NotifyUser = 0; m->p->KeyChainBugTimer = 0; + m->p->SleepLimit = 0; m->AutoTunnelHostAddr.b[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up diff --git a/mDNSMacOSX/mDNSMacOSX.h b/mDNSMacOSX/mDNSMacOSX.h index 25fe6a4..a721c11 100644 --- a/mDNSMacOSX/mDNSMacOSX.h +++ b/mDNSMacOSX/mDNSMacOSX.h @@ -17,6 +17,9 @@ Change History (most recent first): $Log: mDNSMacOSX.h,v $ +Revision 1.75 2007/12/14 00:45:21 cheshire +Add SleepLimit and SleepCookie, for when we need to delay sleep until TLS/TCP record deregistration completes + Revision 1.74 2007/11/02 20:18:13 cheshire BTMM: Work around keychain notification bug @@ -171,6 +174,8 @@ struct mDNS_PlatformSupport_struct IONotificationPortRef PowerPortRef; io_connect_t PowerConnection; io_object_t PowerNotifier; + mDNSs32 SleepLimit; // Set when we get kIOMessageSystemWillSleep notification + long SleepCookie; // Cookie we need to pass to IOAllowPowerChange() pthread_mutex_t BigMutex; mDNSs32 BigMutexStartTime; int WakeKQueueLoopFD; @@ -218,7 +223,7 @@ struct CompileTimeAssertionChecks_mDNSMacOSX // 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_NetworkInterfaceInfoOSX[(sizeof(NetworkInterfaceInfoOSX) <= 4100) ? 1 : -1]; - char sizecheck_mDNS_PlatformSupport [(sizeof(mDNS_PlatformSupport) <= 260) ? 1 : -1]; + char sizecheck_mDNS_PlatformSupport [(sizeof(mDNS_PlatformSupport) <= 268) ? 1 : -1]; }; #ifdef __cplusplus diff --git a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj index 0454e3e..904efc0 100644 --- a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj +++ b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj @@ -67,7 +67,7 @@ /* Begin PBXBuildFile section */ 2E0405F50C3195F700F13B59 /* helper.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405F40C3195F700F13B59 /* helper.c */; }; - 2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; settings = {ATTRIBUTES = (Server, Client, ); }; }; + 2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; settings = {ATTRIBUTES = (Server, Client, ); COMPILER_FLAGS = "-Wno-error"; }; }; 2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E0406140C3197CB00F13B59 /* libbsm.dylib */; }; 2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; }; 2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; }; @@ -83,7 +83,6 @@ 2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202520C56C36500DDFD48 /* libpfkey.h */; }; 2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A8202530C56C36600DDFD48 /* pfkey.c */; }; 2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */; }; - 2E8165F70C59835F00485EB2 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8165F60C59835F00485EB2 /* libipsec.dylib */; }; 2E8165F90C59838100485EB2 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8165F60C59835F00485EB2 /* libipsec.dylib */; }; 2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0406CA0C31E9AD00F13B59 /* helper-main.c */; }; 2E96A5260C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; }; @@ -256,35 +255,35 @@ isa = PBXContainerItemProxy; containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; proxyType = 1; - remoteGlobalIDString = D284BE500ADD80740027CCDF /* mDNSResponder */; + remoteGlobalIDString = D284BE500ADD80740027CCDF; remoteInfo = mDNSResponder; }; 03067D690C83A3890022BE1F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; proxyType = 1; - remoteGlobalIDString = D284BE750ADD80800027CCDF /* mDNSResponder debug */; + remoteGlobalIDString = D284BE750ADD80800027CCDF; remoteInfo = "mDNSResponder debug"; }; 03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; proxyType = 1; - remoteGlobalIDString = D284BEA50ADD80920027CCDF /* dns-sd tool */; + remoteGlobalIDString = D284BEA50ADD80920027CCDF; remoteInfo = "dns-sd tool"; }; 03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; proxyType = 1; - remoteGlobalIDString = 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */; + remoteGlobalIDString = 2E0405EF0C31955500F13B59; remoteInfo = mDNSResponderHelper; }; 03067D850C849CC30022BE1F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; proxyType = 1; - remoteGlobalIDString = 03067D640C83A3700022BE1F /* Build Some */; + remoteGlobalIDString = 03067D640C83A3700022BE1F; remoteInfo = "Build Some"; }; D284BDEA0ADD77F60027CCDF /* PBXContainerItemProxy */ = { @@ -574,7 +573,6 @@ 2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */, 2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */, 2E4D9B050C38C19500480551 /* Security.framework in Frameworks */, - 2E8165F70C59835F00485EB2 /* libipsec.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1014,6 +1012,7 @@ isa = PBXNativeTarget; buildConfigurationList = 2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */; buildPhases = ( + 030BBED60CE11EEC00472F0C /* ShellScript */, 2EC8F8ED0C39CCCA003C9C48 /* Headers */, 2E0405ED0C31955500F13B59 /* Sources */, 2E0405EE0C31955500F13B59 /* Frameworks */, @@ -1135,6 +1134,7 @@ isa = PBXNativeTarget; buildConfigurationList = D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */; buildPhases = ( + 030BBF010CE13A2800472F0C /* ShellScript */, D284BEC20ADD80A20027CCDF /* Headers */, D284BEC40ADD80A20027CCDF /* Sources */, D284BECE0ADD80A20027CCDF /* Frameworks */, @@ -1253,6 +1253,7 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */; + compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 08FB7794FE84155DC02AAC07 /* mDNSResponder */; projectDirPath = ""; @@ -1363,6 +1364,33 @@ /* End PBXRezBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 030BBED60CE11EEC00472F0C /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [ -e \"${SDKROOT}/usr/lib/libipsec.dylib\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nelse\necho \"#define MDNS_NO_IPSEC 1\" > ${CONFIGURATION_TEMP_DIR}/ipsec_options.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n"; + }; + 030BBF010CE13A2800472F0C /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "rm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\n"; + showEnvVarsInLog = 0; + }; D284BE510ADD80740027CCDF /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1370,7 +1398,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch ${CONFIGURATION_TEMP_DIR}/empty.c\ncc -arch i386 -arch ppc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi\n\nif [ -e /usr/include/sandbox.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > ${CONFIGURATION_TEMP_DIR}/sandbox.h\nfi\n"; + shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n"; }; D284BE6C0ADD80740027CCDF /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -1388,7 +1416,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch ${CONFIGURATION_TEMP_DIR}/empty.c\ncc -arch i386 -arch ppc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi\n\nif [ -e /usr/include/sandbox.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > ${CONFIGURATION_TEMP_DIR}/sandbox.h\nfi\n"; + shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\ncc -arch i386 -arch ppc \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n"; }; DB2CC4550662DE1700335AB3 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -1744,7 +1772,12 @@ HEADER_SEARCH_PATHS = "${CONFIGURATION_TEMP_DIR}"; INSTALL_PATH = /usr/sbin; LD_MAP_FILE_PATH = "$(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt"; + LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\""; MACOSX_DEPLOYMENT_TARGET = 10.4; + OTHER_LDFLAGS = ( + "$(inherited)", + "-lipsec", + ); PREBINDING = NO; PRODUCT_NAME = mDNSResponderHelper; }; @@ -1815,6 +1848,7 @@ "-Wmissing-prototypes", "-Wno-four-char-constants", "-Wno-unknown-pragmas", + "-Wshadow", ); YACC_GENERATED_FILE_STEM = Standard; }; @@ -1903,7 +1937,7 @@ GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; INSTALL_PATH = /usr/bin; - MACOSX_DEPLOYMENT_TARGET = 10.2; + MACOSX_DEPLOYMENT_TARGET = 10.4; OTHER_CFLAGS = "-no-cpp-precomp"; OTHER_LDFLAGS = ""; OTHER_REZFLAGS = ""; @@ -2008,7 +2042,7 @@ GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; INSTALL_PATH = "/Library/Application Support/Bonjour"; - MACOSX_DEPLOYMENT_TARGET = 10.3; + MACOSX_DEPLOYMENT_TARGET = 10.4; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ""; OTHER_REZFLAGS = ""; @@ -2031,7 +2065,7 @@ GCC_SYMBOLS_PRIVATE_EXTERN = NO; INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist"; INSTALL_PATH = /AppleInternal/Library/PreferencePanes; - MACOSX_DEPLOYMENT_TARGET = 10.3; + MACOSX_DEPLOYMENT_TARGET = 10.4; OTHER_CFLAGS = ""; OTHER_LDFLAGS = "-twolevel_namespace"; OTHER_REZFLAGS = ""; diff --git a/mDNSMacOSX/pfkey.c b/mDNSMacOSX/pfkey.c index b2a4d9d..0944810 100644 --- a/mDNSMacOSX/pfkey.c +++ b/mDNSMacOSX/pfkey.c @@ -60,6 +60,9 @@ #include "ipsec_strerror.h" #include "libpfkey.h" +#include "ipsec_options.h" + +#ifndef MDNS_NO_IPSEC #define CALLOC(size, cast) (cast)calloc(1, (size)) @@ -2124,3 +2127,5 @@ pfkey_setsadbxsa2(buf, lim, mode0, reqid) return(buf + len); } + +#endif /* ndef MDNS_NO_IPSEC */ diff --git a/mDNSPosix/mDNSUNP.c b/mDNSPosix/mDNSUNP.c index ad1821c..2c9f32f 100755 --- a/mDNSPosix/mDNSUNP.c +++ b/mDNSPosix/mDNSUNP.c @@ -17,6 +17,9 @@ Change History (most recent first): $Log: mDNSUNP.c,v $ +Revision 1.35 2007/11/15 21:36:19 cheshire + POSIX: Off by one overflow in get_ifi_info_linuxv6() + Revision 1.34 2006/08/14 23:24:47 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -200,7 +203,7 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) FILE *fp; char addr[8][5]; int flags, myflags, index, plen, scope; - char ifname[8], lastname[IFNAMSIZ]; + char ifname[9], lastname[IFNAMSIZ]; char addr6[32+7+1]; /* don't forget the seven ':' */ struct addrinfo hints, *res0; struct sockaddr_in6 *sin6; diff --git a/mDNSShared/Java/JNISupport.c b/mDNSShared/Java/JNISupport.c index d321b50..c1d3b66 100644 --- a/mDNSShared/Java/JNISupport.c +++ b/mDNSShared/Java/JNISupport.c @@ -17,6 +17,10 @@ Change History (most recent first): $Log: JNISupport.c,v $ +Revision 1.22 2007/11/30 23:38:53 cheshire +Fix compiler warning: +/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/jni.h:609: warning: declaration of 'index' shadows a global declaration + Revision 1.21 2007/09/18 19:09:02 cheshire mDNSResponderHelper (and other binaries) missing SCCS version strings @@ -122,9 +126,14 @@ static DWORD if_nametoindex( const char * nameStr ); #include #include #endif // _WIN32 -#include +// When compiling with "-Wshadow" set, including jni.h produces the following error: +// /System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/jni.h:609: warning: declaration of 'index' shadows a global declaration +// To work around this, we use the preprocessor to map the identifier 'index', which appears harmlessly in function prototype declarations, +// to something 'jni_index', which doesn't conflict +#define index jni_index #include "DNSSD.java.h" +#undef index //#include diff --git a/mDNSShared/PlatformCommon.c b/mDNSShared/PlatformCommon.c index 08b4945..61c5361 100644 --- a/mDNSShared/PlatformCommon.c +++ b/mDNSShared/PlatformCommon.c @@ -17,6 +17,10 @@ Change History (most recent first): $Log: PlatformCommon.c,v $ +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) @@ -69,6 +73,7 @@ Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c #include // Needed for errno etc. #include // Needed for socket() etc. #include // Needed for sockaddr_in +#include #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above #include "DNSCommon.h" @@ -179,3 +184,26 @@ mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const fi LogMsg("ERROR: malformatted config file"); if (f) fclose(f); } + +#if MDNS_DEBUGMSGS +mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg) + { + fprintf(stderr,"%s\n", msg); + fflush(stderr); + } +#endif + +mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, int logoptflags) + { + if (mDNS_DebugMode) // In debug mode we write to stderr + { + fprintf(stderr,"%s\n", buffer); + fflush(stderr); + } + else // else, in production mode, we write to syslog + { + openlog(ident, LOG_CONS | logoptflags, LOG_DAEMON); + syslog(LOG_ERR, "%s", buffer); + closelog(); + } + } diff --git a/mDNSShared/dns_sd.h b/mDNSShared/dns_sd.h index de55277..da571b2 100644 --- a/mDNSShared/dns_sd.h +++ b/mDNSShared/dns_sd.h @@ -77,7 +77,7 @@ */ #ifndef _DNS_SD_H -#define _DNS_SD_H 1640000 +#define _DNS_SD_H 1700000 #ifdef __cplusplus extern "C" { @@ -101,14 +101,16 @@ #include /* EFI does not have stdint.h, or anything else equivalent */ -#elif defined(EFI32) || defined(EFI64) +#elif defined(EFI32) || defined(EFI64) || defined(EFIX64) +#include "Tiano.h" +#if !defined(_STDINT_H_) typedef UINT8 uint8_t; typedef INT8 int8_t; typedef UINT16 uint16_t; typedef INT16 int16_t; typedef UINT32 uint32_t; typedef INT32 int32_t; - +#endif /* Windows has its own differences */ #elif defined(_WIN32) #include @@ -299,7 +301,7 @@ enum * DNSServiceRef's created by other calls like DNSServiceBrowse() or DNSServiceResolve() * cannot be shared by copying them and using kDNSServiceFlagsShareConnection. * - * 3. Don't double-deallocate + * 3. Don't Double-Deallocate * Calling DNSServiceRefDeallocate(ref) for a particular operation's DNSServiceRef terminates * just that operation. Calling DNSServiceRefDeallocate(ref) for the main shared DNSServiceRef * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&ref)) @@ -308,6 +310,13 @@ enum * The memory used by those subordinate DNSServiceRef's has already been freed, so any attempt * to do a DNSServiceRefDeallocate (or any other operation) on them will result in accesses * to freed memory, leading to crashes or other equally undesirable results. + * + * 4. Thread Safety + * The dns_sd.h API does not presuppose any particular threading model, and consequently + * does no locking of its own (which would require linking some specific threading library). + * If client code calls API routines on the same DNSServiceRef concurrently + * from multiple threads, it is the client's responsibility to use a mutext + * lock or take similar appropriate precautions to serialize those calls. */ }; @@ -735,7 +744,6 @@ typedef void (DNSSD_API *DNSServiceDomainEnumReply) /* DNSServiceEnumerateDomains() Parameters: - * * * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError, @@ -781,7 +789,6 @@ DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains *********************************************************************************************/ /* Register a service that is discovered via Browse() and Resolve() calls. - * * * DNSServiceRegisterReply() Callback Parameters: * @@ -953,7 +960,6 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister * DNSServiceRef, then it's the caller's responsibility to use a mutext lock * or take similar appropriate precautions to serialize those calls. * - * * Parameters; * * sdRef: A DNSServiceRef initialized by DNSServiceRegister(). @@ -996,7 +1002,6 @@ DNSServiceErrorType DNSSD_API DNSServiceAddRecord * - A record added to a registered service via DNSServiceAddRecord() * - An individual record registered by DNSServiceRegisterRecord() * - * * Parameters: * * sdRef: A DNSServiceRef that was initialized by DNSServiceRegister() @@ -1064,7 +1069,6 @@ DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord *********************************************************************************************/ /* Browse for instances of a service. - * * * DNSServiceBrowseReply() Parameters: * @@ -1303,7 +1307,6 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve * * Query for an arbitrary DNS record. * - * * DNSServiceQueryRecordReply() Callback Parameters: * * sdRef: The DNSServiceRef initialized by DNSServiceQueryRecord(). @@ -1346,7 +1349,7 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve typedef void (DNSSD_API *DNSServiceQueryRecordReply) ( - DNSServiceRef DNSServiceRef, + DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, @@ -1422,7 +1425,6 @@ DNSServiceErrorType DNSSD_API DNSServiceQueryRecord * * Queries for the IP address of a hostname by using either Multicast or Unicast DNS. * - * * DNSServiceGetAddrInfoReply() parameters: * * sdRef: The DNSServiceRef initialized by DNSServiceGetAddrInfo(). @@ -1538,7 +1540,6 @@ DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo * Create a connection to the daemon allowing efficient registration of * multiple individual records. * - * * Parameters: * * sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating @@ -1560,7 +1561,6 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef); * Note that name conflicts occurring for records registered via this call must be handled * by the client in the callback. * - * * DNSServiceRegisterRecordReply() parameters: * * sdRef: The connected DNSServiceRef initialized by @@ -1721,7 +1721,6 @@ DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord * port mapping, the client should be prepared to handle these notifications of changes * in the environment, and should update its recorded address and/or port as appropriate. * - * * DNSServiceNATPortMappingReply() parameters: * * sdRef: The DNSServiceRef initialized by DNSServiceNATPortMappingCreate(). @@ -2193,7 +2192,7 @@ uint16_t DNSSD_API TXTRecordGetCount * * txtRecord: Pointer to the received TXT Record bytes. * - * index: An index into the TXT Record. + * itemIndex: An index into the TXT Record. * * keyBufLen: The size of the string buffer being supplied. * @@ -2218,7 +2217,7 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex ( uint16_t txtLen, const void *txtRecord, - uint16_t index, + uint16_t itemIndex, uint16_t keyBufLen, char *key, uint8_t *valueLen, @@ -2239,7 +2238,6 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex * register in this wide-area domain in addition to .local. In addition, this * domain will be returned as a Browse domain via domain enumeration calls. * - * * Parameters: * * flags: Pass kDNSServiceFlagsAdd to add a domain for a user. Call without diff --git a/mDNSShared/dnsextd.c b/mDNSShared/dnsextd.c index a3860f2..5a6541c 100644 --- a/mDNSShared/dnsextd.c +++ b/mDNSShared/dnsextd.c @@ -17,6 +17,16 @@ Change History (most recent first): $Log: dnsextd.c,v $ +Revision 1.87 2007/12/17 23:34:50 cheshire +Don't need to set ptr to result of DNSDigest_SignMessage -- ptr is updated anyway (it's passed by reference) + +Revision 1.86 2007/12/13 20:22:34 cheshire +Got rid of redundant SameResourceRecord() routine; replaced calls to this +with calls to IdenticalResourceRecord() which does exactly the same thing. + +Revision 1.85 2007/12/01 00:30:36 cheshire +Fixed compile warning: declaration of 'time' shadows a global declaration + Revision 1.84 2007/10/24 18:19:37 cheshire Fixed header byte order bug sending update responses @@ -1094,7 +1104,7 @@ mDNSlocal int UpdateSRV(DaemonInfo *d, mDNSBool registration) if ( zone->updateKeys ) { - ptr = DNSDigest_SignMessage( &pkt.msg, &ptr, zone->updateKeys, 0 ); + DNSDigest_SignMessage( &pkt.msg, &ptr, zone->updateKeys, 0 ); require_action( ptr, exit, Log("UpdateSRV: Error constructing lease expiration update" ) ); } @@ -1429,7 +1439,7 @@ mDNSlocal void DeleteOneRecord(DaemonInfo *d, CacheRecord *rr, domainname *zname if ( zone && zone->updateKeys) { - ptr = DNSDigest_SignMessage(&pkt.msg, &ptr, zone->updateKeys, 0 ); + DNSDigest_SignMessage(&pkt.msg, &ptr, zone->updateKeys, 0 ); if (!ptr) goto end; } @@ -1493,7 +1503,7 @@ mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease) LargeCacheRecord lcr; ResourceRecord *rr = &lcr.r.resrec; const mDNSu8 *ptr, *end; - struct timeval time; + struct timeval tv; DNSQuestion zone; char buf[MaxMsg]; @@ -1530,7 +1540,7 @@ mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease) if (SameDomainName((*rptr)->rr.resrec.name, rr->name) && (DeleteAllRRSets || (DeleteOneRRSet && (*rptr)->rr.resrec.rrtype == rr->rrtype) || - (DeleteOneRR && SameResourceRecord(&(*rptr)->rr.resrec, rr)))) + (DeleteOneRR && IdenticalResourceRecord(&(*rptr)->rr.resrec, rr)))) { tmp = *rptr; VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp->rr.resrec, &tmp->rr.resrec.rdata->u, buf)); @@ -1544,12 +1554,12 @@ mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease) else if (lease > 0) { // see if add or refresh - while (*rptr && !SameResourceRecord(&(*rptr)->rr.resrec, rr)) rptr = &(*rptr)->next; + while (*rptr && !IdenticalResourceRecord(&(*rptr)->rr.resrec, rr)) rptr = &(*rptr)->next; if (*rptr) { // refresh - if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; } - (*rptr)->expire = time.tv_sec + (unsigned)lease; + if (gettimeofday(&tv, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; } + (*rptr)->expire = tv.tv_sec + (unsigned)lease; VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf)); } else @@ -1561,7 +1571,7 @@ mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease) bucket = rr->namehash % d->nbuckets; rptr = &d->table[bucket]; } - if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; } + if (gettimeofday(&tv, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; } allocsize = sizeof(RRTableElem); if (rr->rdlength > InlineCacheRDSize) allocsize += (rr->rdlength - InlineCacheRDSize); tmp = malloc(allocsize); @@ -1570,7 +1580,7 @@ mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease) tmp->rr.resrec.rdata = (RData *)&tmp->rr.rdatastorage; AssignDomainName(&tmp->name, rr->name); tmp->rr.resrec.name = &tmp->name; - tmp->expire = time.tv_sec + (unsigned)lease; + tmp->expire = tv.tv_sec + (unsigned)lease; tmp->cli.sin_addr = pkt->src.sin_addr; AssignDomainName(&tmp->zone, &zone.qname); tmp->next = d->table[bucket]; @@ -1953,7 +1963,7 @@ mDNSlocal void *UpdateAnswerList(void *args) { for (na = &NewAnswers; *na; na = &(*na)->next) { - if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec)) + if (IdenticalResourceRecord(&(*ka)->resrec, &(*na)->resrec)) { (*ka)->resrec.rroriginalttl = 0; break; } // 0 means no change } } @@ -1963,7 +1973,7 @@ mDNSlocal void *UpdateAnswerList(void *args) while (*na) { for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next) - if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec)) break; + if (IdenticalResourceRecord(&(*ka)->resrec, &(*na)->resrec)) break; if (!*ka) { // answer is not in list - splice from NewAnswers list, add to Event list @@ -2708,19 +2718,18 @@ RecvUDPMessage if ( IsNotify( &context->pkt ) ) { - int err = RecvNotify( self, &context->pkt ); + int e = RecvNotify( self, &context->pkt ); free(context); - return err; + return e; } else if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) ) { if ( IsLLQRequest( &context->pkt ) ) { // LLQ messages handled by main thread - - int err = RecvLLQ( self, &context->pkt, NULL ); + int e = RecvLLQ( self, &context->pkt, NULL ); free(context); - return err; + return e; } if ( IsLLQAck(&context->pkt ) ) @@ -2739,15 +2748,15 @@ RecvUDPMessage else { PktMsg reply; - int res; + int e; memcpy( &reply, &context->pkt, sizeof( PktMsg ) ); reply.msg.h.flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD; reply.msg.h.flags.b[1] = kDNSFlag1_RA | kDNSFlag1_RC_NXDomain; - res = sendto( sd, &reply.msg, reply.len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) ); - require_action_quiet( res == ( int ) reply.len, exit, LogErr( "RecvUDPMessage", "sendto" ) ); + e = sendto( sd, &reply.msg, reply.len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) ); + require_action_quiet( e == ( int ) reply.len, exit, LogErr( "RecvUDPMessage", "sendto" ) ); err = mStatus_NoAuth; } diff --git a/mDNSShared/dnssd_clientlib.c b/mDNSShared/dnssd_clientlib.c index f32351f..01ffaff 100644 --- a/mDNSShared/dnssd_clientlib.c +++ b/mDNSShared/dnssd_clientlib.c @@ -28,6 +28,9 @@ Change History (most recent first): $Log: dnssd_clientlib.c,v $ +Revision 1.18 2007/11/30 23:06:10 cheshire +Fixed compile warning: declaration of 'index' shadows a global declaration + Revision 1.17 2007/10/02 19:36:04 cheshire TXTRecordGetValuePtr should be case-insenstive @@ -353,7 +356,7 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex ( uint16_t txtLen, const void *txtRecord, - uint16_t index, + uint16_t itemIndex, uint16_t keyBufLen, char *key, uint8_t *valueLen, @@ -363,7 +366,7 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex uint16_t count = 0; uint8_t *p = (uint8_t*)txtRecord; uint8_t *e = p + txtLen; - while (p Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails) +Wrap hack code in "#if APPLE_OSX_mDNSResponder" since (as far as we know right now) +we don't want to do this on 64-bit Linux, Solaris, etc. + +Revision 1.99 2007/11/02 17:29:40 cheshire + Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails) +To get 64-bit code that works, we need to NOT use the standard CMSG_* macros + +Revision 1.98 2007/11/01 19:52:43 cheshire +Wrap debugging messages in "#if DEBUG_64BIT_SCM_RIGHTS" + +Revision 1.97 2007/11/01 19:45:55 cheshire +Added "DEBUG_64BIT_SCM_RIGHTS" debugging code +See Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails) + +Revision 1.96 2007/11/01 15:59:33 cheshire +umask not being set and restored properly in USE_NAMED_ERROR_RETURN_SOCKET code +(no longer used on OS X, but relevant for other platforms) + +Revision 1.95 2007/10/31 20:07:16 cheshire + Set SO_NOSIGPIPE on client socket +Refinement: the cleanup code still needs to close listenfd when necesssary + +Revision 1.94 2007/10/15 22:34:27 cheshire + Set SO_NOSIGPIPE on client socket + Revision 1.93 2007/10/10 00:48:54 cheshire Daemon spins in an infinite loop when it doesn't get the control message it's expecting @@ -480,6 +507,9 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f } else { + #ifdef SO_NOSIGPIPE + const unsigned long optval = 1; + #endif *ref = NULL; sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0); sdr->validator = sdr->sockfd ^ ValidatorBits; @@ -489,6 +519,11 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f FreeDNSServiceOp(sdr); return kDNSServiceErr_NoMemory; } + #ifdef SO_NOSIGPIPE + // Some environments (e.g. OS X) support turning off SIGPIPE for a socket + if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0) + syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", errno, strerror(errno)); + #endif #if defined(USE_TCP_LOOPBACK) saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR); @@ -565,8 +600,9 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) } #elif defined(USE_NAMED_ERROR_RETURN_SOCKET) { + mode_t mask; + int bindresult; dnssd_sockaddr_t caddr; - mode_t mask = umask(0); listenfd = socket(AF_DNSSD, SOCK_STREAM, 0); if (!dnssd_SocketValid(listenfd)) goto cleanup; @@ -577,8 +613,10 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) caddr.sun_len = sizeof(struct sockaddr_un); #endif strcpy(caddr.sun_path, data); + mask = umask(0); + bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)); umask(mask); - if (bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)) < 0) goto cleanup; + if (bindresult < 0) goto cleanup; listen(listenfd, 1); } #else @@ -634,29 +672,66 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) errsd = accept(listenfd, (struct sockaddr *)&daddr, &len); if (!dnssd_SocketValid(errsd)) goto cleanup; #else + +#if APPLE_OSX_mDNSResponder +// On Leopard, the stock definitions of the CMSG_* macros in /usr/include/sys/socket.h, +// while arguably correct in theory, nonetheless in practice produce code that doesn't work on 64-bit machines +// For details see Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails) +#undef CMSG_DATA +#define CMSG_DATA(cmsg) ((unsigned char *)(cmsg) + (sizeof(struct cmsghdr))) +#undef CMSG_SPACE +#define CMSG_SPACE(l) ((sizeof(struct cmsghdr)) + (l)) +#undef CMSG_LEN +#define CMSG_LEN(l) ((sizeof(struct cmsghdr)) + (l)) +#endif + struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS struct msghdr msg; struct cmsghdr *cmsg; - char cbuf[sizeof(struct cmsghdr) + sizeof(dnssd_sock_t)]; + char cbuf[CMSG_SPACE(sizeof(dnssd_sock_t))]; msg.msg_name = 0; msg.msg_namelen = 0; msg.msg_iov = &vec; msg.msg_iovlen = 1; msg.msg_control = cbuf; - msg.msg_controllen = sizeof(cbuf); + msg.msg_controllen = CMSG_LEN(sizeof(dnssd_sock_t)); msg.msg_flags = 0; cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = sizeof(cbuf); + cmsg->cmsg_len = CMSG_LEN(sizeof(dnssd_sock_t)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd; + #if TEST_KQUEUE_CONTROL_MESSAGE_BUG sleep(1); #endif + +#if DEBUG_64BIT_SCM_RIGHTS + syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld", + errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*), + sizeof(struct cmsghdr) + sizeof(dnssd_sock_t), + CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)), + (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf)); +#endif DEBUG_64BIT_SCM_RIGHTS + if (sendmsg(sdr->sockfd, &msg, 0) < 0) + { syslog(LOG_WARNING, "dnssd_clientstub ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)", errsd, listenfd, errno, strerror(errno)); + err = kDNSServiceErr_Incompatible; + goto cleanup; + } + +#if DEBUG_64BIT_SCM_RIGHTS + syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd); +#endif DEBUG_64BIT_SCM_RIGHTS + #endif + // Close our end of the socketpair *before* blocking in read_all to get the four-byte error code. + // Otherwise, if the daemon closes our socket (or crashes), we block in read_all() forever + // because the socket is not closed (we still have an open reference to it ourselves). + dnssd_close(listenfd); + listenfd = dnssd_InvalidSocket; // Make sure we don't close it a second time in the cleanup handling below } // At this point we may block in read_all for a few milliseconds waiting for the daemon to send us the error code, diff --git a/mDNSShared/mDNSDebug.c b/mDNSShared/mDNSDebug.c index ca3eda9..4d0adbc 100644 --- a/mDNSShared/mDNSDebug.c +++ b/mDNSShared/mDNSDebug.c @@ -23,6 +23,9 @@ Change History (most recent first): $Log: mDNSDebug.c,v $ +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 @@ -68,14 +71,11 @@ Changes necessary to support mDNSResponder on Linux. #include -#if defined(WIN32) -// Need to add Windows syslog support here +#if defined(WIN32) || defined(EFI32) || defined(EFI64) || defined(EFIX64) +// Need to add Windows/EFI syslog support here #define LOG_PID 0x01 #define LOG_CONS 0x02 #define LOG_PERROR 0x20 -#define openlog(A,B,C) (void)(A); (void)(B) -#define syslog(A,B,C) -#define closelog() #else #include #endif @@ -95,44 +95,27 @@ mDNSexport int mDNS_DebugMode = mDNSfalse; #if MDNS_DEBUGMSGS mDNSexport void debugf_(const char *format, ...) { - unsigned char buffer[512]; + char buffer[512]; va_list ptr; va_start(ptr,format); - buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0; + buffer[mDNS_vsnprintf(buffer, sizeof(buffer), format, ptr)] = 0; va_end(ptr); - fprintf(stderr,"%s\n", buffer); - fflush(stderr); + mDNSPlatformWriteDebugMsg(buffer); } #endif #if MDNS_DEBUGMSGS > 1 mDNSexport void verbosedebugf_(const char *format, ...) { - unsigned char buffer[512]; + char buffer[512]; va_list ptr; va_start(ptr,format); - buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0; + buffer[mDNS_vsnprintf(buffer, sizeof(buffer), format, ptr)] = 0; va_end(ptr); - fprintf(stderr,"%s\n", buffer); - fflush(stderr); + mDNSPlatformWriteDebugMsg(buffer); } #endif -mDNSlocal void WriteLogMsg(const char *ident, const char *buffer, int logoptflags) - { - if (mDNS_DebugMode) // In debug mode we write to stderr - { - fprintf(stderr,"%s\n", buffer); - fflush(stderr); - } - else // else, in production mode, we write to syslog - { - openlog(ident, LOG_CONS | logoptflags, LOG_DAEMON); - syslog(LOG_ERR, "%s", buffer); - closelog(); - } - } - // Log message with default "mDNSResponder" ident string at the start mDNSexport void LogMsg(const char *format, ...) { @@ -141,7 +124,7 @@ mDNSexport void LogMsg(const char *format, ...) va_start(ptr,format); buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0; va_end(ptr); - WriteLogMsg(ProgramName, buffer, 0); + mDNSPlatformWriteLogMsg(ProgramName, buffer, 0); } // Log message with specified ident string at the start @@ -152,7 +135,7 @@ mDNSexport void LogMsgIdent(const char *ident, const char *format, ...) va_start(ptr,format); buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0; va_end(ptr); - WriteLogMsg(ident, buffer, ident && *ident ? LOG_PID : 0); + mDNSPlatformWriteLogMsg(ident, buffer, ident && *ident ? LOG_PID : 0); } // Log message with no ident string at the start @@ -163,7 +146,7 @@ mDNSexport void LogMsgNoIdent(const char *format, ...) va_start(ptr,format); buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0; va_end(ptr); - WriteLogMsg("", buffer, 0); + mDNSPlatformWriteLogMsg("", buffer, 0); } mDNSlocal const char *CStringForLogLevel(LogLevel_t level) diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c index 201a44b..3e0a601 100644 --- a/mDNSShared/uds_daemon.c +++ b/mDNSShared/uds_daemon.c @@ -17,6 +17,21 @@ Change History (most recent first): $Log: uds_daemon.c,v $ +Revision 1.384 2007/12/22 01:38:05 cheshire +Improve display of "Auth Records" SIGINFO output + +Revision 1.383 2007/12/07 00:45:58 cheshire + BTMM: Need to deregister records and services on shutdown/sleep + +Revision 1.382 2007/11/30 20:11:48 cheshire +Fixed compile warning: declaration of 'remove' shadows a global declaration + +Revision 1.381 2007/11/28 22:02:52 cheshire +Remove pointless "if (!domain)" check (domain is an array on the stack, so its address can never be null) + +Revision 1.380 2007/11/28 18:38:41 cheshire +Fixed typo in log message: "DNSServiceResolver" -> "DNSServiceResolve" + Revision 1.379 2007/11/01 19:32:14 cheshire Added "DEBUG_64BIT_SCM_RIGHTS" debugging code @@ -2067,10 +2082,10 @@ mDNSlocal void udsserver_automatic_browse_domain_changed(const DNameListElem *co if (p) debugf("udsserver_automatic_browse_domain_changed %##s still in list, not removing", &d->name); else { - browser_t *remove = *ptr; + browser_t *rem = *ptr; *ptr = (*ptr)->next; - mDNS_StopQueryWithRemoves(&mDNSStorage, &remove->q); - freeL("browser_t/udsserver_automatic_browse_domain_changed", remove); + mDNS_StopQueryWithRemoves(&mDNSStorage, &rem->q); + freeL("browser_t/udsserver_automatic_browse_domain_changed", rem); } } } @@ -2138,9 +2153,9 @@ mDNSlocal void DeregisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, in { if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs)) { - ARListElem *remove = *ptr; + ARListElem *rem = *ptr; *ptr = (*ptr)->next; - mDNS_Deregister(m, &remove->ar); + mDNS_Deregister(m, &rem->ar); return; } else ptr = &(*ptr)->next; @@ -2335,7 +2350,7 @@ mDNSlocal mStatus handle_browse_request(request_state *request) if (!request->msgptr) { LogMsg("%3d: DNSServiceBrowse(unreadable parameters)", request->sd); return(mStatus_BadParamErr); } - if (!domain || (domain[0] == '\0')) uDNS_RegisterSearchDomains(&mDNSStorage); + if (domain[0] == '\0') uDNS_RegisterSearchDomains(&mDNSStorage); typedn.c[0] = 0; NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes @@ -3300,7 +3315,13 @@ mDNSlocal void request_callback(int fd, short filter, void *info) req = newreq; } - switch(req->hdr.op) + // If we're shutting down, don't allow new client requests + // We do allow "cancel" and "getproperty" during shutdown + if (mDNSStorage.ShutdownTime && req->hdr.op != cancel_request && req->hdr.op != getproperty_request) + { + err = mStatus_ServiceNotRunning; + } + else switch(req->hdr.op) { // These are all operations that have their own first-class request_state object case connection_request: @@ -3331,8 +3352,7 @@ mDNSlocal void request_callback(int fd, short filter, void *info) if (req->msgbuf) freeL("request_state msgbuf", req->msgbuf); // There's no return data for a cancel request (DNSServiceRefDeallocate returns no result) - // For a DNSServiceGetProperty call, the handler already generated the response, - // so no need to do it again here + // For a DNSServiceGetProperty call, the handler already generated the response, so no need to do it again here if (req->hdr.op != cancel_request && req->hdr.op != getproperty_request) { err = dnssd_htonl(err); @@ -3402,10 +3422,10 @@ mDNSlocal void connect_callback(int fd, short filter, void *info) request->errsd = sd; #if APPLE_OSX_mDNSResponder struct xucred x; - socklen_t len = sizeof(x); - if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &len) >= 0 && x.cr_version == XUCRED_VERSION) request->uid = x.cr_uid; + socklen_t xucredlen = sizeof(x); + if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 && x.cr_version == XUCRED_VERSION) request->uid = x.cr_uid; else my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); - debugf("LOCAL_PEERCRED %d %u %u %d", len, x.cr_version, x.cr_uid, x.cr_ngroups); + debugf("LOCAL_PEERCRED %d %u %u %d", xucredlen, x.cr_version, x.cr_uid, x.cr_ngroups); #endif APPLE_OSX_mDNSResponder LogOperation("%3d: Adding FD for uid %u", request->sd, request->uid); udsSupportAddFDToEventLoop(sd, request_callback, request); @@ -3665,11 +3685,19 @@ mDNSexport void udsserver_info(mDNS *const m) AuthRecord *ar; LogMsgNoIdent(" Int Next Expire State"); for (ar = m->ResourceRecords; ar; ar=ar->next) - LogMsgNoIdent("%7d %7d %7d %7d %s", - ar->ThisAPInterval / mDNSPlatformOneSecond, - AuthRecord_uDNS(ar) || ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0, - AuthRecord_uDNS(ar) && ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0, - ar->state, ARDisplayString(m, ar)); + if (AuthRecord_uDNS(ar)) + LogMsgNoIdent("%7d %7d %7d %7d %s", + ar->ThisAPInterval / mDNSPlatformOneSecond, + (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond, + ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0, + ar->state, ARDisplayString(m, ar)); + else if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly) + LogMsgNoIdent("%7d %7d M %s", + ar->ThisAPInterval / mDNSPlatformOneSecond, + ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0, + ARDisplayString(m, ar)); + else + LogMsgNoIdent(" LO %s", ARDisplayString(m, ar)); } LogMsgNoIdent("----- ServiceRegistrations -----"); @@ -3864,7 +3892,7 @@ mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent) if ((*req)->u.resolve.ReportTime && now - (*req)->u.resolve.ReportTime >= 0) { (*req)->u.resolve.ReportTime = 0; - LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. " + LogMsgNoIdent("Client application bug: DNSServiceResolve(%##s) active for over two minutes. " "This places considerable burden on the network.", (*req)->u.resolve.qsrv.qname.c); } diff --git a/mDNSWindows/mDNSWin32.c b/mDNSWindows/mDNSWin32.c index 13b0404..1cb1f64 100755 --- a/mDNSWindows/mDNSWin32.c +++ b/mDNSWindows/mDNSWin32.c @@ -17,6 +17,9 @@ Change History (most recent first): $Log: mDNSWin32.c,v $ +Revision 1.130 2007/11/16 18:53:56 cheshire +TCPSocketFlags needs to be first field of TCPSocket_struct + Revision 1.129 2007/10/17 22:52:26 cheshire Get rid of unused mDNS_UpdateLLQs() @@ -219,8 +222,8 @@ struct mDNSPlatformInterfaceInfo struct TCPSocket_struct { + TCPSocketFlags flags; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags SocketRef fd; - TCPSocketFlags flags; BOOL connected; TCPConnectionCallback callback; void * context; -- 2.47.2