From 1f519c617ce606e0f03914d2ccf87094a6a18799 Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 12 May 2011 22:10:54 +0000 Subject: [PATCH] mDNSResponder-258.21.tar.gz --- Clients/dns-sd.c | 23 +++++--- Makefile | 2 +- mDNSCore/DNSCommon.c | 1 + mDNSCore/mDNS.c | 105 +++++++++++++++++++++++++++++++++- mDNSCore/mDNSEmbeddedAPI.h | 9 ++- mDNSCore/uDNS.c | 37 +++++++++++- mDNSMacOSX/helper-stubs.c | 11 ++++ mDNSMacOSX/helper.c | 90 +++++++++++++++++++++++++++++ mDNSMacOSX/helper.h | 1 + mDNSMacOSX/helpermsg.defs | 8 +++ mDNSMacOSX/mDNSMacOSX.c | 15 +++++ mDNSPosix/Identify.c | 2 + mDNSPosix/mDNSPosix.c | 9 +++ mDNSShared/dns_sd.h | 9 ++- mDNSShared/dnssd_clientshim.c | 1 + mDNSShared/dnssd_clientstub.c | 10 ++++ mDNSShared/uds_daemon.c | 7 ++- mDNSWindows/mDNSWin32.c | 8 +++ 18 files changed, 327 insertions(+), 21 deletions(-) diff --git a/Clients/dns-sd.c b/Clients/dns-sd.c index c1c5d27..826245b 100644 --- a/Clients/dns-sd.c +++ b/Clients/dns-sd.c @@ -1073,7 +1073,7 @@ int main(int argc, char **argv) } if (argc < 2) goto Fail; // Minimum command line is the command name and one argument - operation = getfirstoption(argc, argv, "EFBZLRPQqCAUNTMISV" + operation = getfirstoption(argc, argv, "EFBZLlRPQqCAUNTMISV" #if HAS_NAT_PMP_API "X" #endif @@ -1117,14 +1117,19 @@ int main(int argc, char **argv) err = DNSServiceBrowse(&sc1, kDNSServiceFlagsShareConnection, opinterface, typ, dom, zonedata_browse, NULL); break; - 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[opi+0], typ, dom); - err = DNSServiceResolve(&client, 0, opinterface, argv[opi+0], typ, dom, resolve_reply, NULL); - break; + case 'l': + case 'L': { + DNSServiceFlags rflags = 0; + 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[opi+0], typ, dom); + if (operation == 'l') rflags |= kDNSServiceFlagsWakeOnResolve; + err = DNSServiceResolve(&client, rflags, opinterface, argv[opi+0], typ, dom, resolve_reply, NULL); + break; + } case 'R': if (argc < opi+4) goto Fail; typ = (argc < opi+2) ? "" : argv[opi+1]; diff --git a/Makefile b/Makefile index 18b458f..c8c8ef9 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ include /Developer/Makefiles/pb_makefiles/platform.make -MVERS = "mDNSResponder-258.18" +MVERS = "mDNSResponder-258.21" DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig" diff --git a/mDNSCore/DNSCommon.c b/mDNSCore/DNSCommon.c index bb7a082..b0fe39d 100644 --- a/mDNSCore/DNSCommon.c +++ b/mDNSCore/DNSCommon.c @@ -1074,6 +1074,7 @@ mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID I q->ForceMCast = mDNSfalse; q->ReturnIntermed = mDNSfalse; q->SuppressUnusable = mDNSfalse; + q->WakeOnResolve = mDNSfalse; q->QuestionCallback = callback; q->QuestionContext = context; } diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c index 700282e..51cc367 100755 --- a/mDNSCore/mDNS.c +++ b/mDNSCore/mDNS.c @@ -75,6 +75,7 @@ void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import)); mDNSlocal void BeginSleepProcessing(mDNS *const m); mDNSlocal void RetrySPSRegistrations(mDNS *const m); mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password); +mDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q); // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK @@ -278,6 +279,9 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec #define GoodbyeCount ((mDNSu8)3) #define WakeupCount ((mDNSu8)18) +// Number of wakeups we send if WakeOnResolve is set in the question +#define InitialWakeOnResolveCount ((mDNSu8)3) + // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not. // This means that because the announce interval is doubled after sending the first packet, the first // observed on-the-wire inter-packet interval between announcements is actually one second. @@ -776,6 +780,11 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) rr->InFlightRDLen = 0; rr->QueuedRData = 0; rr->QueuedRDLen = 0; + //mDNSPlatformMemZero(&rr->NATinfo, sizeof(rr->NATinfo)); + // We should be recording the actual internal port for this service record here. Once we initiate our NAT mapping + // request we'll subsequently overwrite srv.port with the allocated external NAT port -- potentially multiple + // times with different values if the external NAT port changes during the lifetime of the service registration. + //if (rr->resrec.rrtype == kDNSType_SRV) rr->NATinfo.IntPort = rr->resrec.rdata->u.srv.port; // rr->resrec.interface = already set in mDNS_SetupResourceRecord // rr->resrec.name->c = MUST be set by client @@ -2273,6 +2282,57 @@ mDNSlocal int RecordDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDN return(i); } +mDNSlocal void mDNSSendWakeOnResolve(mDNS *const m, DNSQuestion *q) + { + int len, i, cnt; + mDNSInterfaceID InterfaceID = q->InterfaceID; + domainname *d = &q->qname; + + // We can't send magic packets without knowing which interface to send it on. + if (InterfaceID == mDNSInterface_Any || InterfaceID == mDNSInterface_LocalOnly || InterfaceID == mDNSInterface_P2P) + { + LogMsg("mDNSSendWakeOnResolve: ERROR!! Invalid InterfaceID %p for question %##s", InterfaceID, q->qname.c); + return; + } + + // Split MAC@IPAddress and pass them separately + len = d->c[0]; + i = 1; + cnt = 0; + for (i = 1; i < len; i++) + { + if (d->c[i] == '@') + { + char EthAddr[18]; // ethernet adddress : 12 bytes + 5 ":" + 1 NULL byte + char IPAddr[47]; // Max IP address len: 46 bytes (IPv6) + 1 NULL byte + if (cnt != 5) + { + LogMsg("mDNSSendWakeOnResolve: ERROR!! Malformed Ethernet address %##s, cnt %d", q->qname.c, cnt); + return; + } + if ((i - 1) > (int) (sizeof(EthAddr) - 1)) + { + LogMsg("mDNSSendWakeOnResolve: ERROR!! Malformed Ethernet address %##s, length %d", q->qname.c, i - 1); + return; + } + if ((len - i) > (int)(sizeof(IPAddr) - 1)) + { + LogMsg("mDNSSendWakeOnResolve: ERROR!! Malformed IP address %##s, length %d", q->qname.c, len - i); + return; + } + mDNSPlatformMemCopy(EthAddr, &d->c[1], i - 1); + EthAddr[i - 1] = 0; + mDNSPlatformMemCopy(IPAddr, &d->c[i + 1], len - i); + IPAddr[len - i] = 0; + mDNSPlatformSendWakeupPacket(m, InterfaceID, EthAddr, IPAddr, InitialWakeOnResolveCount - q->WakeOnResolveCount); + return; + } + else if (d->c[i] == ':') + cnt++; + } + LogMsg("mDNSSendWakeOnResolve: ERROR!! Malformed WakeOnResolve name %##s", q->qname.c); + } + mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q) { // If more than 90% of the way to the query time, we should unconditionally accelerate it @@ -2568,7 +2628,14 @@ mDNSlocal void SendQueries(mDNS *const m) // If we're suppressing this question, or we successfully put it, update its SendQNow state if (SuppressOnThisInterface(q->DupSuppress, intf) || BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast)) - q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf); + { + q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf); + if (q->WakeOnResolveCount) + { + mDNSSendWakeOnResolve(m, q); + q->WakeOnResolveCount--; + } + } } } @@ -5932,8 +5999,11 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will rename %s", rr->ProbeCount, ARDisplayString(m, rr)); mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); } - // We assumed this record must be unique, but we were wrong. (e.g. There are two mDNSResponders on the same machine giving - // different answers for the reverse mapping record.) This is simply a misconfiguration, and we don't try to recover from it. + // We assumed this record must be unique, but we were wrong. (e.g. There are two mDNSResponders on the + // same machine giving different answers for the reverse mapping record, or there are two machines on the + // network using the same IP address.) This is simply a misconfiguration, and there's nothing we can do + // to fix it -- e.g. it's not our job to be trying to change the machine's IP address. We just discard our + // record to avoid continued conflicts (as we do for a conflict on our Unique records) and get on with life. else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique) { LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m, rr)); @@ -7378,6 +7448,13 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu question->validDNSServers = zeroOpaque64; question->triedAllServersOnce = 0; question->noServerResponse = 0; + if (question->WakeOnResolve) + { + question->WakeOnResolveCount = InitialWakeOnResolveCount; + mDNS_PurgeBeforeResolve(m, question); + } + else + question->WakeOnResolveCount = 0; if (question->DuplicateOf) question->AuthInfo = question->DuplicateOf->AuthInfo; @@ -7682,6 +7759,7 @@ mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const qu question->ForceMCast = ForceMCast; question->ReturnIntermed = mDNSfalse; question->SuppressUnusable = mDNSfalse; + question->WakeOnResolve = mDNSfalse; question->QuestionCallback = Callback; question->QuestionContext = Context; if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr); @@ -7855,6 +7933,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m, query->qSRV.ForceMCast = mDNSfalse; query->qSRV.ReturnIntermed = mDNSfalse; query->qSRV.SuppressUnusable = mDNSfalse; + query->qSRV.WakeOnResolve = mDNSfalse; query->qSRV.QuestionCallback = FoundServiceInfoSRV; query->qSRV.QuestionContext = query; @@ -7869,6 +7948,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m, query->qTXT.ForceMCast = mDNSfalse; query->qTXT.ReturnIntermed = mDNSfalse; query->qTXT.SuppressUnusable = mDNSfalse; + query->qTXT.WakeOnResolve = mDNSfalse; query->qTXT.QuestionCallback = FoundServiceInfoTXT; query->qTXT.QuestionContext = query; @@ -7883,6 +7963,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m, query->qAv4.ForceMCast = mDNSfalse; query->qAv4.ReturnIntermed = mDNSfalse; query->qAv4.SuppressUnusable = mDNSfalse; + query->qAv4.WakeOnResolve = mDNSfalse; query->qAv4.QuestionCallback = FoundServiceInfo; query->qAv4.QuestionContext = query; @@ -7897,6 +7978,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m, query->qAv6.ForceMCast = mDNSfalse; query->qAv6.ReturnIntermed = mDNSfalse; query->qAv6.SuppressUnusable = mDNSfalse; + query->qAv6.WakeOnResolve = mDNSfalse; query->qAv6.QuestionCallback = FoundServiceInfo; query->qAv6.QuestionContext = query; @@ -7947,6 +8029,7 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m question->ForceMCast = mDNSfalse; question->ReturnIntermed = mDNSfalse; question->SuppressUnusable = mDNSfalse; + question->WakeOnResolve = mDNSfalse; question->QuestionCallback = Callback; question->QuestionContext = Context; if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr); @@ -9673,6 +9756,22 @@ mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const } } +mDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q) + { + const mDNSu32 slot = HashSlot(&q->qname); + CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); + CacheRecord *rp; + + for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next) + { + if (SameNameRecordAnswersQuestion(&rp->resrec, q)) + { + LogInfo("mDNS_PurgeBeforeResolve: Flushing %s", CRDisplayString(m, rp)); + mDNS_PurgeCacheResourceRecord(m, rp); + } + } + } + mDNSlocal void CacheRecordResetDNSServer(mDNS *const m, DNSQuestion *q, DNSServer *new) { const mDNSu32 slot = HashSlot(&q->qname); diff --git a/mDNSCore/mDNSEmbeddedAPI.h b/mDNSCore/mDNSEmbeddedAPI.h index a9881d0..26aa0a8 100755 --- a/mDNSCore/mDNSEmbeddedAPI.h +++ b/mDNSCore/mDNSEmbeddedAPI.h @@ -1452,6 +1452,7 @@ struct DNSQuestion_struct mDNSs32 LastQTxTime; // Last time this Q was sent on one (but not necessarily all) interfaces mDNSu32 CNAMEReferrals; // Count of how many CNAME redirections we've done mDNSBool SuppressQuery; // This query should be suppressed and not sent on the wire + mDNSu8 WakeOnResolveCount; // Number of wakes that should be sent on resolve // Wide Area fields. These are used internally by the uDNS core UDPSocket *LocalSocket; @@ -1493,6 +1494,7 @@ struct DNSQuestion_struct mDNSBool ForceMCast; // Set by client to force mDNS query, even for apparently uDNS names mDNSBool ReturnIntermed; // Set by client to request callbacks for intermediate CNAME/NXDOMAIN results mDNSBool SuppressUnusable; // Set by client to suppress unusable queries to be sent on the wire + mDNSBool WakeOnResolve; // Send wakeup on resolve mDNSQuestionCallback *QuestionCallback; void *QuestionContext; }; @@ -2541,6 +2543,7 @@ extern mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, m extern void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status); extern void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep); +extern void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration); #ifdef _LEGACY_NAT_TRAVERSAL_ // Support for legacy NAT traversal protocols, implemented by the platform layer and callable by the core. @@ -2810,15 +2813,15 @@ struct CompileTimeAssertionChecks_mDNS char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1208) ? 1 : -1]; char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 184) ? 1 : -1]; char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 184) ? 1 : -1]; - char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 752) ? 1 : -1]; - char sizecheck_ZoneData [(sizeof(ZoneData) <= 1588) ? 1 : -1]; + char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 762) ? 1 : -1]; + char sizecheck_ZoneData [(sizeof(ZoneData) <= 1598) ? 1 : -1]; char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 192) ? 1 : -1]; char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3050) ? 1 : -1]; char sizecheck_DNSServer [(sizeof(DNSServer) <= 320) ? 1 : -1]; char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 6750) ? 1 : -1]; char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5500) ? 1 : -1]; char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7550) ? 1 : -1]; - char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 3050) ? 1 : -1]; + char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 3090) ? 1 : -1]; #if APPLE_OSX_mDNSResponder char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1104) ? 1 : -1]; #endif diff --git a/mDNSCore/uDNS.c b/mDNSCore/uDNS.c index 2d6ba4b..5d0facf 100755 --- a/mDNSCore/uDNS.c +++ b/mDNSCore/uDNS.c @@ -553,6 +553,9 @@ mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalIn { LogMsg("Error! Tried to add a NAT traversal that's already in the active list: request %p Prot %d Int %d TTL %d", traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease); + #if ForceAlerts + *(long*)0 = 0; + #endif return(mStatus_AlreadyRegistered); } if (traversal->Protocol && traversal->Protocol == (*n)->Protocol && mDNSSameIPPort(traversal->IntPort, (*n)->IntPort) && @@ -1572,6 +1575,7 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt zd->question.ForceMCast = mDNSfalse; zd->question.ReturnIntermed = mDNStrue; zd->question.SuppressUnusable = mDNSfalse; + zd->question.WakeOnResolve = mDNSfalse; zd->question.QuestionCallback = GetZoneData_QuestionCallback; zd->question.QuestionContext = zd; @@ -1709,7 +1713,7 @@ mDNSlocal void CompleteRecordNatMap(mDNS *m, NATTraversalInfo *n) if (!rr->nta || mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4)) { LogInfo("CompleteRecordNatMap called for %s but no zone information!", ARDisplayString(m, rr)); - // We need to clear out the NATinfo state so that it will result in re-acuqiring the mapping + // We need to clear out the NATinfo state so that it will result in re-acquiring the mapping // and hence this callback called again. if (rr->NATinfo.clientContext) { @@ -1802,8 +1806,13 @@ mDNSlocal void StartRecordNatMap(mDNS *m, AuthRecord *rr) else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) protocol = NATOp_MapUDP; else { LogMsg("StartRecordNatMap: could not determine transport protocol of service %##s", rr->resrec.name->c); return; } + //LogMsg("StartRecordNatMap: clientContext %p IntPort %d srv.port %d %s", + // rr->NATinfo.clientContext, mDNSVal16(rr->NATinfo.IntPort), mDNSVal16(rr->resrec.rdata->u.srv.port), ARDisplayString(m, rr)); if (rr->NATinfo.clientContext) mDNS_StopNATOperation_internal(m, &rr->NATinfo); rr->NATinfo.Protocol = protocol; + + // Shouldn't be trying to set IntPort here -- + // BuildUpdateMessage overwrites srs->RR_SRV.resrec.rdata->u.srv.port with external (mapped) port number rr->NATinfo.IntPort = rr->resrec.rdata->u.srv.port; rr->NATinfo.RequestedPort = rr->resrec.rdata->u.srv.port; rr->NATinfo.NATLease = 0; // Request default lease @@ -1818,6 +1827,19 @@ mDNSlocal void StartRecordNatMap(mDNS *m, AuthRecord *rr) // record is temporarily left in the ResourceRecords list so that we can initialize later // when the target is resolvable. Similarly, when host name changes, we enter regState_NoTarget // and we do the same. + +// This UnlinkResourceRecord routine is very worrying. It bypasses all the normal cleanup performed +// by mDNS_Deregister_internal and just unceremoniously cuts the record from the active list. +// This is why re-regsitering this record was producing syslog messages like this: +// "Error! Tried to add a NAT traversal that's already in the active list" +// Right now UnlinkResourceRecord is fortunately only called by RegisterAllServiceRecords, +// which then immediately calls mDNS_Register_internal to re-register the record, which probably +// masked more serious problems. Any other use of UnlinkResourceRecord is likely to lead to crashes. +// For now we'll workaround that specific problem by explicitly calling mDNS_StopNATOperation_internal, +// but long-term we should either stop cancelling the record registration and then re-registering it, +// or if we really do need to do this for some reason it should be done via the usual +// mDNS_Deregister_internal path instead of just cutting the record from the list. + mDNSlocal mStatus UnlinkResourceRecord(mDNS *const m, AuthRecord *const rr) { AuthRecord **list = &m->ResourceRecords; @@ -1826,6 +1848,15 @@ mDNSlocal mStatus UnlinkResourceRecord(mDNS *const m, AuthRecord *const rr) { *list = rr->next; rr->next = mDNSNULL; + + // Temporary workaround to cancel any active NAT mapping operation + if (rr->NATinfo.clientContext) + { + mDNS_StopNATOperation_internal(m, &rr->NATinfo); + rr->NATinfo.clientContext = mDNSNULL; + if (rr->resrec.rrtype == kDNSType_SRV) rr->resrec.rdata->u.srv.port = rr->NATinfo.IntPort; + } + return(mStatus_NoError); } LogMsg("UnlinkResourceRecord:ERROR!! - no such active record %##s", rr->resrec.name->c); @@ -2189,6 +2220,7 @@ mDNSlocal void GetStaticHostname(mDNS *m) q->ForceMCast = mDNSfalse; q->ReturnIntermed = mDNStrue; q->SuppressUnusable = mDNSfalse; + q->WakeOnResolve = mDNSfalse; q->QuestionCallback = FoundStaticHostname; q->QuestionContext = mDNSNULL; @@ -4786,6 +4818,7 @@ mDNSlocal void mDNS_StartCFQuestion(mDNS *const m, DNSQuestion *question, domain question->ForceMCast = mDNSfalse; question->ReturnIntermed = mDNSfalse; question->SuppressUnusable = mDNSfalse; + question->WakeOnResolve = mDNSfalse; question->QuestionCallback = FoundCFDomain; question->QuestionContext = context; LogInfo("mDNS_StartCFQuestion: Start CF domain question %##s", question->qname.c); @@ -4919,5 +4952,5 @@ struct CompileTimeAssertionChecks_uDNS // other overly-large structures instead of having a pointer to them, can inadvertently // cause structure sizes (and therefore memory usage) to balloon unreasonably. char sizecheck_tcpInfo_t [(sizeof(tcpInfo_t) <= 9056) ? 1 : -1]; - char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 4800) ? 1 : -1]; + char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 4860) ? 1 : -1]; }; diff --git a/mDNSMacOSX/helper-stubs.c b/mDNSMacOSX/helper-stubs.c index 9e56860..a1bd530 100644 --- a/mDNSMacOSX/helper-stubs.c +++ b/mDNSMacOSX/helper-stubs.c @@ -261,3 +261,14 @@ int mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner, fin: return err; } + +void mDNSSendWakeupPacket(unsigned ifid, char *eth_addr, char *ip_addr, int iteration) + { + kern_return_t kr = KERN_SUCCESS; + int retry = 0, err = 0; + MACHRETRYLOOP_BEGIN(kr, retry, err, fin); + kr = proxy_mDNSSendWakeupPacket(getHelperPort(retry), ifid, eth_addr, ip_addr, iteration); + MACHRETRYLOOP_END(kr, retry, err, fin); +fin: + (void) err; + } diff --git a/mDNSMacOSX/helper.c b/mDNSMacOSX/helper.c index f4c0771..a3a9046 100644 --- a/mDNSMacOSX/helper.c +++ b/mDNSMacOSX/helper.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "mDNSEmbeddedAPI.h" #include "dns_sd.h" @@ -2349,3 +2350,92 @@ fin: update_idle_timer(); return KERN_SUCCESS; } + +kern_return_t +do_mDNSSendWakeupPacket(__unused mach_port_t port, unsigned ifid, const char *eth_addr, const char *ip_addr, int iteration, audit_token_t token) + { + int bpf_fd, i, j; + struct ifreq ifr; + char ifname[IFNAMSIZ]; + char packet[512]; + char *ptr = packet; + char bpf_device[12]; + struct ether_addr *ea; + (void) ip_addr; // unused + (void) iteration; // unused + (void) token; // unused + + if (if_indextoname(ifid, ifname) == NULL) + { + helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket invalid interface index %u", ifid); + return errno; + } + + ea = ether_aton(eth_addr); + if (ea == NULL) + { + helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket invalid ethernet address %s", eth_addr); + return errno; + } + + for (i = 0; i < 100; i++) + { + snprintf(bpf_device, sizeof(bpf_device), "/dev/bpf%d", i); + bpf_fd = open(bpf_device, O_RDWR, 0); + if (bpf_fd == -1) + continue; + else break; + } + + if (bpf_fd == -1) + { + helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket cannot find a bpf device"); + return ENXIO; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + if (ioctl(bpf_fd, BIOCSETIF, (char *)&ifr) < 0) + { + helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket BIOCSETIF failed %s", strerror(errno)); + return errno; + } + + // 0x00 Destination address + for (i=0; i<6; i++) *ptr++ = ea->octet[i]; + + // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us) + for (i=0; i<6; i++) *ptr++ = 0; + + // 0x0C Ethertype (0x0842) + *ptr++ = 0x08; + *ptr++ = 0x42; + + // 0x0E Wakeup sync sequence + for (i=0; i<6; i++) *ptr++ = 0xFF; + + // 0x14 Wakeup data + for (j=0; j<16; j++) for (i=0; i<6; i++) *ptr++ = ea->octet[i]; + + // 0x74 Password + for (i=0; i<6; i++) *ptr++ = 0; + + if (write(bpf_fd, packet, ptr - packet) < 0) + { + helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket write failed %s", strerror(errno)); + return errno; + } + helplog(ASL_LEVEL_INFO, "do_mDNSSendWakeupPacket sent unicast eth_addr %s, ip_addr %s", eth_addr, ip_addr); + // Send a broadcast one to handle ethernet switches that don't flood forward packets with + // unknown mac addresses. + for (i=0; i<6; i++) packet[i] = 0xFF; + if (write(bpf_fd, packet, ptr - packet) < 0) + { + helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket write failed %s", strerror(errno)); + return errno; + } + helplog(ASL_LEVEL_INFO, "do_mDNSSendWakeupPacket sent broadcast eth_addr %s, ip_addr %s", eth_addr, ip_addr); + close(bpf_fd); + return KERN_SUCCESS; + } diff --git a/mDNSMacOSX/helper.h b/mDNSMacOSX/helper.h index 7bf8f49..e9abade 100644 --- a/mDNSMacOSX/helper.h +++ b/mDNSMacOSX/helper.h @@ -73,5 +73,6 @@ extern void mDNSConfigureServer(int updown, const domainname *const fqdn); extern int mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner, v6addr_t local_outer, short local_port, v6addr_t remote_inner, v6addr_t remote_outer, short remote_port, const domainname *const fqdn); +extern void mDNSSendWakeupPacket(unsigned ifid, char *eth_addr, char *ip_addr, int iteration); #endif /* H_HELPER_H */ diff --git a/mDNSMacOSX/helpermsg.defs b/mDNSMacOSX/helpermsg.defs index ad946a3..546621e 100644 --- a/mDNSMacOSX/helpermsg.defs +++ b/mDNSMacOSX/helpermsg.defs @@ -98,3 +98,11 @@ routine mDNSAutoTunnelSetKeys( port : mach_port_t; fqdn : string_t; out err : int; ServerAuditToken token : audit_token_t); + +simpleroutine mDNSSendWakeupPacket( + port : mach_port_t; + ifid : unsigned; + eth_addr : string_t; + ip_addr : string_t; + iteration : int; + ServerAuditToken token : audit_token_t); diff --git a/mDNSMacOSX/mDNSMacOSX.c b/mDNSMacOSX/mDNSMacOSX.c index 19f5d0a..a3f3ad3 100644 --- a/mDNSMacOSX/mDNSMacOSX.c +++ b/mDNSMacOSX/mDNSMacOSX.c @@ -4352,6 +4352,7 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q) p->q.ForceMCast = mDNSfalse; p->q.ReturnIntermed = mDNStrue; p->q.SuppressUnusable = mDNSfalse; + p->q.WakeOnResolve = mDNSfalse; p->q.QuestionCallback = AutoTunnelCallback; p->q.QuestionContext = p; @@ -7672,3 +7673,17 @@ mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep) LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__); } } + +mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration) + { + mDNSu32 ifindex; + + // Sanity check + ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID); + if (ifindex <= 0) + { + LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex); + return; + } + mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration); + } diff --git a/mDNSPosix/Identify.c b/mDNSPosix/Identify.c index df83b8e..6bc9a24 100644 --- a/mDNSPosix/Identify.c +++ b/mDNSPosix/Identify.c @@ -220,6 +220,8 @@ mDNSlocal mStatus StartQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const m q->ExpectUnique = mDNSfalse; // Don't want to stop after the first response packet q->ForceMCast = mDNStrue; // Query via multicast, even for apparently uDNS names like 1.1.1.17.in-addr.arpa. q->ReturnIntermed = mDNStrue; + q->SuppressUnusable = mDNSfalse; + q->WakeOnResolve = mDNSfalse; q->QuestionCallback = callback; q->QuestionContext = NULL; diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c index f205cd0..45aa621 100755 --- a/mDNSPosix/mDNSPosix.c +++ b/mDNSPosix/mDNSPosix.c @@ -1359,6 +1359,15 @@ mDNSexport mDNSs32 mDNSPlatformUTC(void) return time(NULL); } +mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration) + { + (void) m; + (void) InterfaceID; + (void) EthAddr; + (void) IPAddr; + (void) iteration; + } + mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s) { if (*nfds < s + 1) *nfds = s + 1; diff --git a/mDNSShared/dns_sd.h b/mDNSShared/dns_sd.h index 911c70d..d2a9fdd 100644 --- a/mDNSShared/dns_sd.h +++ b/mDNSShared/dns_sd.h @@ -77,7 +77,7 @@ */ #ifndef _DNS_SD_H -#define _DNS_SD_H 2581800 +#define _DNS_SD_H 2582100 #ifdef __cplusplus extern "C" { @@ -341,7 +341,7 @@ enum * lock or take similar appropriate precautions to serialize those calls. */ - kDNSServiceFlagsSuppressUnusable = 0x8000 + kDNSServiceFlagsSuppressUnusable = 0x8000, /* * This flag is meaningful only in DNSServiceQueryRecord which suppresses unusable queries on the * wire. If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name) @@ -350,6 +350,11 @@ enum * if this host has no routable IPv4 address, the call will not try to look up IPv4 addresses for * "hostname". */ + kDNSServiceFlagsWakeOnResolve = 0x40000 + /* + * This flag is meaningful only in DNSServiceResolve. When set, it tries to send a magic packet + * to wake up the client. + */ }; diff --git a/mDNSShared/dnssd_clientshim.c b/mDNSShared/dnssd_clientshim.c index 17f2e93..a891915 100644 --- a/mDNSShared/dnssd_clientshim.c +++ b/mDNSShared/dnssd_clientshim.c @@ -523,6 +523,7 @@ DNSServiceErrorType DNSServiceResolve x->qTXT.ForceMCast = mDNSfalse; x->qTXT.ReturnIntermed = mDNSfalse; x->qTXT.SuppressUnusable = mDNSfalse; + x->qTXT.WakeOnResolve = mDNSfalse; x->qTXT.QuestionCallback = FoundServiceInfo; x->qTXT.QuestionContext = x; diff --git a/mDNSShared/dnssd_clientstub.c b/mDNSShared/dnssd_clientstub.c index 62f640e..fc43730 100644 --- a/mDNSShared/dnssd_clientstub.c +++ b/mDNSShared/dnssd_clientstub.c @@ -1094,6 +1094,16 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam; + // Need a real InterfaceID for WakeOnResolve + if ((flags & kDNSServiceFlagsWakeOnResolve) != 0 && + ((interfaceIndex == kDNSServiceInterfaceIndexAny) || + (interfaceIndex == kDNSServiceInterfaceIndexLocalOnly) || + (interfaceIndex == kDNSServiceInterfaceIndexUnicast) || + (interfaceIndex == kDNSServiceInterfaceIndexP2P))) + { + return kDNSServiceErr_BadParam; + } + err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, callBack, context); if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c index 964667c..9ad7bc5 100644 --- a/mDNSShared/uds_daemon.c +++ b/mDNSShared/uds_daemon.c @@ -2203,6 +2203,8 @@ mDNSlocal mStatus handle_resolve_request(request_state *request) request->u.resolve.qsrv.ExpectUnique = mDNStrue; request->u.resolve.qsrv.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0; request->u.resolve.qsrv.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; + request->u.resolve.qsrv.SuppressUnusable = mDNSfalse; + request->u.resolve.qsrv.WakeOnResolve = (flags & kDNSServiceFlagsWakeOnResolve ) != 0; request->u.resolve.qsrv.QuestionCallback = resolve_result_callback; request->u.resolve.qsrv.QuestionContext = request; @@ -2216,6 +2218,7 @@ mDNSlocal mStatus handle_resolve_request(request_state *request) request->u.resolve.qtxt.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0; request->u.resolve.qtxt.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; request->u.resolve.qtxt.SuppressUnusable = mDNSfalse; + request->u.resolve.qtxt.WakeOnResolve = mDNSfalse; request->u.resolve.qtxt.QuestionCallback = resolve_result_callback; request->u.resolve.qtxt.QuestionContext = request; @@ -2449,6 +2452,7 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request) q->ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0; q->ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; q->SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable) != 0; + q->WakeOnResolve = mDNSfalse; q->QuestionCallback = queryrecord_result_callback; q->QuestionContext = request; @@ -2858,6 +2862,7 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) request->u.addrinfo.q4.ForceMCast = request->u.addrinfo.q6.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0; request->u.addrinfo.q4.ReturnIntermed = request->u.addrinfo.q6.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; request->u.addrinfo.q4.SuppressUnusable = request->u.addrinfo.q6.SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable ) != 0; + request->u.addrinfo.q4.SuppressUnusable = request->u.addrinfo.q6.SuppressUnusable = mDNSfalse; if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4) { @@ -4020,7 +4025,7 @@ struct CompileTimeAssertionChecks_uds_daemon char sizecheck_request_state [(sizeof(request_state) <= 2000) ? 1 : -1]; char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <= 60) ? 1 : -1]; char sizecheck_service_instance [(sizeof(service_instance) <= 6552) ? 1 : -1]; - char sizecheck_browser_t [(sizeof(browser_t) <= 1016) ? 1 : -1]; + char sizecheck_browser_t [(sizeof(browser_t) <= 1026) ? 1 : -1]; char sizecheck_reply_hdr [(sizeof(reply_hdr) <= 12) ? 1 : -1]; char sizecheck_reply_state [(sizeof(reply_state) <= 64) ? 1 : -1]; }; diff --git a/mDNSWindows/mDNSWin32.c b/mDNSWindows/mDNSWin32.c index 4add845..58feb7f 100755 --- a/mDNSWindows/mDNSWin32.c +++ b/mDNSWindows/mDNSWin32.c @@ -2183,6 +2183,14 @@ exit: return err; } +mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration) + { + (void) m; + (void) InterfaceID; + (void) EthAddr; + (void) IPAddr; + (void) iteration; + } #if 0 #pragma mark - -- 2.47.2