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);
}
}
#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();
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)
{
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 --
#if HAS_ADDRINFO_API
"G"
#endif
- , &optind);
+ , &opi);
if (operation == -1) goto Fail;
if (opinterface) printf("Using interface %d\n", opinterface);
//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;
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;
}
#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);
#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
include /Developer/Makefiles/pb_makefiles/platform.make
-MVERS = "mDNSResponder-164"
+MVERS = "mDNSResponder-170"
DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
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
+<rdar://problem/5526800> 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
+<rdar://problem/5526800> 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
+<rdar://problem/5636422> 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
+<rdar://problem/5589039> 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
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
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,
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);
}
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)
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)
// 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;
*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
}
return(status);
-
- tcp_error:
- LogMsg("mDNSSendDNSMessage: error sending message over tcp");
- return mStatus_UnknownErr;
}
// ***************************************************************************
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;
}
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);
}
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
#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)
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
#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;
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
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
// 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);
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)
Change History (most recent first):
$Log: mDNS.c,v $
+Revision 1.767 2007/12/22 02:25:29 cheshire
+<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
+
+Revision 1.766 2007/12/15 01:12:27 cheshire
+<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
+
+Revision 1.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
+<rdar://problem/5636422> 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
+<rdar://problem/5526800> 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
+<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
+
+Revision 1.757 2007/12/06 00:22:27 mcguire
+<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
+
+Revision 1.756 2007/12/05 01:52:30 cheshire
+<rdar://problem/5624763> 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
+<rdar://problem/5623140> 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
+<rdar://problem/5623140> 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
<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
LLQ state was not being transferred properly between duplicate questions
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);
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.
}
}
-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
// 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;
// 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);
}
rr->AnnounceCount = InitialAnnounceCount;
rr->RequireGoodbye = mDNSfalse;
- rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
- InitializeLastAPTime(m,rr);
+ InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
}
}
}
}
+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))
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;
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()
{ 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)
{
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
}
#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;
// 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
}
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
// 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
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
}
}
// 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
{
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
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);
if (m->CurrentQuestion == q)
{
+ CacheRecord *rr;
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
if (SameNameRecordAnswersQuestion(&rr->resrec, q))
{
{
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)
// 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);
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);
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
// 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));
}
}
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);
{
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;
}
}
for (i=0; i<query->h.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;
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.
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,
// 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;
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);
}
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
// 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);
// 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
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)
#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; }
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;
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;
}
}
-// 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;
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; }
}
question->NoAnswer = NoAnswer_Normal;
question->state = LLQ_InitialRequest;
- question->origLease = 0;
+ question->ReqLease = 0;
question->expire = 0;
question->ntries = 0;
question->id = zeroOpaque64;
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
}
// 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);
// 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);
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().
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)
{
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));
}
}
// 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;
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:
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.
// 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;
m->LastNATReplyLocalTime = timenow;
m->UPnPInterfaceID = 0;
+ m->SSDPSocket = mDNSNULL;
m->UPnPRouterPort = zeroIPPort;
m->UPnPSOAPPort = zeroIPPort;
m->UPnPRouterURL = mDNSNULL;
// 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);
}
}
+ // 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);
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).
}
}
-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);
// 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
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");
}
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
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
#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
#define ForceAlerts 0
-#define VerifySameNameAssumptions 0
-
#ifdef __cplusplus
}
#endif
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
+<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
+
+Revision 1.457 2007/12/06 00:22:27 mcguire
+<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
+
+Revision 1.456 2007/12/05 01:45:35 cheshire
+Renamed markedForDeletion -> MarkedForDeletion
+
+Revision 1.455 2007/12/01 01:21:27 jgraessley
+<rdar://problem/5623140> 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
#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> // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration
#endif
#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
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
} 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:
#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,
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
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
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"
// 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
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
// 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;
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
{
struct ClientTunnel *next;
domainname dstname;
- mDNSBool markedForDeletion;
+ mDNSBool MarkedForDeletion;
mDNSv6Addr loc_inner;
mDNSv4Addr loc_outer;
mDNSv6Addr rmt_inner;
// 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;
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
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
// 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,
#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);
// 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]))
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
// 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
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
Change History (most recent first):
$Log: uDNS.c,v $
+Revision 1.545 2007/12/22 02:25:29 cheshire
+<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
+
+Revision 1.544 2007/12/18 00:40:11 cheshire
+<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
+Reordered code to avoid double-TSIGs in some cases
+
+Revision 1.543 2007/12/17 23:57:43 cheshire
+<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
+Need to include TSIG signature when sending LLQ cancellations over TLS
+
+Revision 1.542 2007/12/15 01:12:27 cheshire
+<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
+
+Revision 1.541 2007/12/15 00:18:51 cheshire
+Renamed question->origLease to question->ReqLease
+
+Revision 1.540 2007/12/14 23:55:28 cheshire
+Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h
+
+Revision 1.539 2007/12/14 20:44:24 cheshire
+<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
+SleepRecordRegistrations/WakeRecordRegistrations should only operate on uDNS records
+
+Revision 1.538 2007/12/14 01:13:40 cheshire
+<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
+Additional fixes (existing code to deregister private records and services didn't work at all)
+
+Revision 1.537 2007/12/11 00:18:25 cheshire
+<rdar://problem/5569316> BTMM: My iMac has a "ghost" ID associated with it
+There were cases where the code was incorrectly clearing the "uselease" flag, and never resetting it.
+
+Revision 1.536 2007/12/10 23:07:00 cheshire
+Removed some unnecessary log messages
+
+Revision 1.535 2007/12/06 00:22:27 mcguire
+<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
+
+Revision 1.534 2007/12/04 00:49:37 cheshire
+<rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1
+
+Revision 1.533 2007/12/01 01:21:27 jgraessley
+<rdar://problem/5623140> mDNSResponder unicast DNS improvements
+
+Revision 1.532 2007/11/30 20:16:44 cheshire
+Fixed compile warning: declaration of 'end' shadows a previous local
+
+Revision 1.531 2007/11/28 22:00:09 cheshire
+In StartSRVNatMap, change "mDNSu8 *p" to "const mDNSu8 *p"
+
+Revision 1.530 2007/11/16 22:19:40 cheshire
+<rdar://problem/5547474> mDNSResponder leaks on network changes
+The "connection failed" code path in MakeTCPConn was not disposing of the TCPSocket it had created
+
+Revision 1.529 2007/11/15 22:52:29 cheshire
+<rdar://problem/5589039> ERROR: mDNSPlatformWriteTCP - send Broken pipe
+
Revision 1.528 2007/11/02 21:32:30 cheshire
<rdar://problem/5575593> BTMM: Deferring deregistration of record log messages on sleep/wake
#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;
// -- 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
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;
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;
(*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);
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;
}
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);
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
{
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 <rdar://problem/5546824> Crash in mDNSResponder at GetAuthInfoForName_internal + 366
+ // Don't know yet what's causing this, but at least we can be cautious and try to avoid crashing if we find our pointers in an unexpected state
+ if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage)
+ LogMsg("tcpCallback: ERROR: tcpInfo->srs->RR_SRV.resrec.name %p != &tcpInfo->srs->RR_SRV.namestorage %p",
+ tcpInfo->srs->RR_SRV.resrec.name, &tcpInfo->srs->RR_SRV.namestorage);
+ if (tcpInfo->rr && tcpInfo->rr->resrec.name != &tcpInfo->rr->namestorage)
+ LogMsg("tcpCallback: ERROR: tcpInfo->rr->resrec.name %p != &tcpInfo->rr->namestorage %p",
+ tcpInfo->rr->resrec.name, &tcpInfo->rr->namestorage);
+ if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage) return;
+ if (tcpInfo->rr && tcpInfo->rr-> resrec.name != &tcpInfo->rr-> namestorage) return;
+
+ AuthInfo = tcpInfo->srs ? GetAuthInfoForName(m, tcpInfo->srs->RR_SRV.resrec.name) :
+ tcpInfo->rr ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name) : mDNSNULL;
+
// 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
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 <rdar://problem/5546824> Crash in mDNSResponder at GetAuthInfoForName_internal + 366
- // Don't know yet what's causing this, but at least we can be cautious and try to avoid crashing if we find our pointers in an unexpected state
- if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage)
- LogMsg("tcpCallback: ERROR: tcpInfo->srs->RR_SRV.resrec.name %p != &tcpInfo->srs->RR_SRV.namestorage %p",
- tcpInfo->srs->RR_SRV.resrec.name, &tcpInfo->srs->RR_SRV.namestorage);
- if (tcpInfo->rr && tcpInfo->rr->resrec.name != &tcpInfo->rr->namestorage)
- LogMsg("tcpCallback: ERROR: tcpInfo->rr->resrec.name %p != &tcpInfo->rr->namestorage %p",
- tcpInfo->rr->resrec.name, &tcpInfo->rr->namestorage);
- if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage) return;
- if (tcpInfo->rr && tcpInfo->rr-> resrec.name != &tcpInfo->rr-> namestorage) return;
-
- AuthInfo = tcpInfo->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);
}
}
// 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;
}
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)
{
{
// 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;
}
// 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);
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);
// 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);
}
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;
// 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);
return;
exit:
-
if (err)
{
LogMsg("SendServiceRegistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
-
unlinkSRS(m, srs);
srs->state = regState_Unregistered;
mDNS_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
+ // <rdar://problem/5607082> 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);
}
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;
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)" : "",
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);
return;
exit:
-
if (err)
{
LogMsg("SendServiceDeregistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
// 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;
}
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);
}
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);
}
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);
}
}
// 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)
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;
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)
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.",
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)
{
if (!err)
{
- rr->state = regState_Registered;
if (rr->state == regState_Refresh) InvokeCallback = mDNSfalse;
+ rr->state = regState_Registered;
}
else
{
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; }
}
// <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
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
#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++;
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;
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; }
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);
}
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));
{
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)
}
}
{
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)
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)
{
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)
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)
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)
}
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;
}
}
// 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
Change History (most recent first):
$Log: uDNS.h,v $
+Revision 1.90 2007/12/22 02:25:30 cheshire
+<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
+
+Revision 1.89 2007/12/15 01:12:27 cheshire
+<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
+
Revision 1.88 2007/10/25 20:06:13 cheshire
Don't try to do SOA queries using private DNS (TLS over TCP) queries
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);
Change History (most recent first):
$Log: LegacyNATTraversal.c,v $
+Revision 1.45 2007/12/06 00:22:27 mcguire
+<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
+
Revision 1.44 2007/11/02 20:45:40 cheshire
Don't log "connection failed" in customer builds
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);
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_ */
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
<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
}
-- (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;
}
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
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);
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
<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
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;
{ 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;
}
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
<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
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
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
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;
Change History (most recent first):
$Log: daemon.c,v $
+Revision 1.356 2007/12/18 00:28:56 cheshire
+<rdar://problem/5526800> 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
+<rdar://problem/5526800> 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
+<rdar://problem/5526796> 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
+<rdar://problem/5526800> 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 <rdar://problem/5124399> "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
+<rdar://problem/5526800> 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
<rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
Need to hold the lock while calling SetDomainSecrets
}
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;
{
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;
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)
{
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
{
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
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");
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);
}
}
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
// See <rdar://problem/5124399> 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);
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)",
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)
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
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);
}
}
}
Change History (most recent first):
$Log: helper-error.h,v $
+Revision 1.8 2007/11/07 00:22:30 jgraessley
+Bug #: <rdar://problem/5573573> mDNSResponder doesn't build without IPSec
+Reviewed by: Stuart Cheshire
+
Revision 1.7 2007/09/12 00:42:47 mcguire
<rdar://problem/5468236> BTMM: Need to clean up security associations
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")
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
<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
return p;
}
-
/* Ugly but handy. */
#define MACHRETRYLOOP_BEGIN(kr, retry, err, fin) for (;;) {
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)))
{
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
+<rdar://problem/5613538> Interface specific resolvers not setup correctly
+
+Revision 1.21 2007/11/07 00:22:30 jgraessley
+Bug #: <rdar://problem/5573573> 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")
#include <SystemConfiguration/SCDynamicStore.h>
#include <SystemConfiguration/SCPreferencesSetSpecific.h>
#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
+#include <TargetConditionals.h>
#include "mDNSEmbeddedAPI.h"
#include "dns_sd.h"
#include "dnssd_ipc.h"
#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
return ok;
}
+#ifndef MDNS_NO_IPSEC
static void
closefds(int from)
{
}
closedir(dirp);
}
+#endif
kern_return_t
do_mDNSIdleExit(__unused mach_port_t port, audit_token_t token)
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;
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)
{
ShowNameConflictNotification(header, *subtext);
CFRelease(header);
}
+#endif
}
kern_return_t
#endif
}
+#ifndef MDNS_NO_IPSEC
typedef enum _mDNSTunnelPolicyWhich
{
kmDNSTunnelPolicySetup,
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))
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";
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;
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
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;
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;
&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)
&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;
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"
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;
}
Change History (most recent first):
$Log: mDNSMacOSX.c,v $
+Revision 1.521 2007/12/14 00:58:28 cheshire
+<rdar://problem/5526800> 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
+<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
+
+Revision 1.518 2007/12/05 01:52:30 cheshire
+<rdar://problem/5624763> 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
+<rdar://problem/5623140> 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
+<rdar://problem/5613538> 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
+<rdar://problem/5585972> 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
<rdar://problem/5518845> 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
<rdar://problem/5513378> Crash in ReissueBlockedQuestions
#include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
#include "PlatformCommon.h"
-
#include <stdio.h>
#include <stdarg.h> // For va_list support
#include <net/if.h>
#if TARGET_OS_EMBEDDED
#define NO_SECURITYFRAMEWORK 1
+#define NO_CFUSERNOTIFICATION 1
#endif
#ifndef NO_SECURITYFRAMEWORK
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);
}
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
// 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)
{
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))
{
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)
{
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] = "";
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)
#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!
}
sock->fd = -1;
}
- freeL("mDNSPlatformTCPCloseConnection", sock);
+ freeL("TCPSocket/mDNSPlatformTCPCloseConnection", 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;
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)
{
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
return(err);
}
-struct UDPSocket_struct
- {
- KQSocketSet ss;
- };
-
mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort port)
{
mStatus err;
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
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);
}
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);
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);
}
// 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);
}
}
+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);
}
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;
}
{
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;
}
}
else needSetKeys = mDNSfalse;
+ LogOperation("AutoTunnelCallback: Disposing ClientTunnel %p", tun);
freeL("ClientTunnel", old);
}
}
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;
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;
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);
}
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
// 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",
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").
+ // <rdar://problem/5585972> 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;
// 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)
{
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)
{
// 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.
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; }
}
}
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;
}
}
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
if (RegDomains)
{
- CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("RegistrationDomains"));
+ CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
if (regArray && CFArrayGetCount(regArray) > 0)
{
CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
if (BrowseDomains)
{
- CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("BrowseDomains"));
+ CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
if (browseArray)
{
for (i = 0; i < CFArrayGetCount(browseArray); i++)
}
}
}
- CFRelease(dict);
+ CFRelease(ddnsdict);
}
if (RegDomains)
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);
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;
}
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
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)))
{
#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;
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; i<c; i++)
m->p->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.
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
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 */
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;
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
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
<rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
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;
// 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
/* 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 */; };
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 */; };
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 */ = {
2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */,
2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */,
2E4D9B050C38C19500480551 /* Security.framework in Frameworks */,
- 2E8165F70C59835F00485EB2 /* libipsec.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
isa = PBXNativeTarget;
buildConfigurationList = 2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */;
buildPhases = (
+ 030BBED60CE11EEC00472F0C /* ShellScript */,
2EC8F8ED0C39CCCA003C9C48 /* Headers */,
2E0405ED0C31955500F13B59 /* Sources */,
2E0405EE0C31955500F13B59 /* Frameworks */,
isa = PBXNativeTarget;
buildConfigurationList = D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */;
buildPhases = (
+ 030BBF010CE13A2800472F0C /* ShellScript */,
D284BEC20ADD80A20027CCDF /* Headers */,
D284BEC40ADD80A20027CCDF /* Sources */,
D284BECE0ADD80A20027CCDF /* Frameworks */,
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */;
+ compatibilityVersion = "Xcode 2.4";
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* mDNSResponder */;
projectDirPath = "";
/* 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;
);
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;
);
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;
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;
};
"-Wmissing-prototypes",
"-Wno-four-char-constants",
"-Wno-unknown-pragmas",
+ "-Wshadow",
);
YACC_GENERATED_FILE_STEM = Standard;
};
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 = "";
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 = "";
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 = "";
#include "ipsec_strerror.h"
#include "libpfkey.h"
+#include "ipsec_options.h"
+
+#ifndef MDNS_NO_IPSEC
#define CALLOC(size, cast) (cast)calloc(1, (size))
return(buf + len);
}
+
+#endif /* ndef MDNS_NO_IPSEC */
Change History (most recent first):
$Log: mDNSUNP.c,v $
+Revision 1.35 2007/11/15 21:36:19 cheshire
+<rdar://problem/5289340> 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
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;
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
<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
#include <sys/socket.h>
#include <net/if.h>
#endif // _WIN32
-#include <jni.h>
+// 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 <syslog.h>
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)
#include <errno.h> // Needed for errno etc.
#include <sys/socket.h> // Needed for socket() etc.
#include <netinet/in.h> // Needed for sockaddr_in
+#include <syslog.h>
#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
#include "DNSCommon.h"
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();
+ }
+ }
*/
#ifndef _DNS_SD_H
-#define _DNS_SD_H 1640000
+#define _DNS_SD_H 1700000
#ifdef __cplusplus
extern "C" {
#include <sys/types.h>
/* 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 <windows.h>
* 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))
* 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.
*/
};
/* DNSServiceEnumerateDomains() Parameters:
- *
*
* sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
* then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
*********************************************************************************************/
/* Register a service that is discovered via Browse() and Resolve() calls.
- *
*
* DNSServiceRegisterReply() Callback Parameters:
*
* 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().
* - A record added to a registered service via DNSServiceAddRecord()
* - An individual record registered by DNSServiceRegisterRecord()
*
- *
* Parameters:
*
* sdRef: A DNSServiceRef that was initialized by DNSServiceRegister()
*********************************************************************************************/
/* Browse for instances of a service.
- *
*
* DNSServiceBrowseReply() Parameters:
*
*
* Query for an arbitrary DNS record.
*
- *
* DNSServiceQueryRecordReply() Callback Parameters:
*
* sdRef: The DNSServiceRef initialized by DNSServiceQueryRecord().
typedef void (DNSSD_API *DNSServiceQueryRecordReply)
(
- DNSServiceRef DNSServiceRef,
+ DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
*
* Queries for the IP address of a hostname by using either Multicast or Unicast DNS.
*
- *
* DNSServiceGetAddrInfoReply() parameters:
*
* sdRef: The DNSServiceRef initialized by DNSServiceGetAddrInfo().
* Create a connection to the daemon allowing efficient registration of
* multiple individual records.
*
- *
* Parameters:
*
* sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating
* 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
* 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().
*
* 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.
*
(
uint16_t txtLen,
const void *txtRecord,
- uint16_t index,
+ uint16_t itemIndex,
uint16_t keyBufLen,
char *key,
uint8_t *valueLen,
* 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
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
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" ) );
}
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;
}
LargeCacheRecord lcr;
ResourceRecord *rr = &lcr.r.resrec;
const mDNSu8 *ptr, *end;
- struct timeval time;
+ struct timeval tv;
DNSQuestion zone;
char buf[MaxMsg];
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));
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
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);
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];
{
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
}
}
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
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 ) )
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;
}
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
<rdar://problem/5516444> TXTRecordGetValuePtr should be case-insenstive
(
uint16_t txtLen,
const void *txtRecord,
- uint16_t index,
+ uint16_t itemIndex,
uint16_t keyBufLen,
char *key,
uint8_t *valueLen,
uint16_t count = 0;
uint8_t *p = (uint8_t*)txtRecord;
uint8_t *e = p + txtLen;
- while (p<e && count<index) { p += 1 + p[0]; count++; } // Find requested item
+ while (p<e && count<itemIndex) { p += 1 + p[0]; count++; } // Find requested item
if (p<e && p + 1 + p[0] <= e) // If valid
{
uint8_t *x = p+1;
Change History (most recent first):
$Log: dnssd_clientshim.c,v $
+Revision 1.16 2007/11/30 20:12:24 cheshire
+Removed unused "badparam:" label
+
Revision 1.15 2007/07/27 19:30:41 cheshire
Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
to properly reflect tri-state nature of the possible responses
*sdRef = (DNSServiceRef)x;
return(mStatus_NoError);
-badparam:
- err = mStatus_BadParamErr;
fail:
LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname, rrtype, rrclass, errormsg, err);
return(err);
Change History (most recent first):
$Log: dnssd_clientstub.c,v $
+Revision 1.100 2007/11/02 17:56:37 cheshire
+<rdar://problem/5565787> 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
+<rdar://problem/5565787> 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 <rdar://problem/5565787> 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
+<rdar://problem/5541498> 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
+<rdar://problem/5541498> Set SO_NOSIGPIPE on client socket
+
Revision 1.93 2007/10/10 00:48:54 cheshire
<rdar://problem/5526379> Daemon spins in an infinite loop when it doesn't get the control message it's expecting
}
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;
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);
}
#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;
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
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 <rdar://problem/5565787> 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,
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
#include <stdio.h>
-#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 <syslog.h>
#endif
#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, ...)
{
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
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
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)
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
+<rdar://problem/5526800> 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
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);
}
}
}
{
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;
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
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:
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);
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);
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 -----");
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);
}
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()
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;