}
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
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];
include /Developer/Makefiles/pb_makefiles/platform.make
-MVERS = "mDNSResponder-258.18"
+MVERS = "mDNSResponder-258.21"
DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
q->ForceMCast = mDNSfalse;
q->ReturnIntermed = mDNSfalse;
q->SuppressUnusable = mDNSfalse;
+ q->WakeOnResolve = mDNSfalse;
q->QuestionCallback = callback;
q->QuestionContext = context;
}
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
#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.
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
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
// 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--;
+ }
+ }
}
}
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));
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;
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);
query->qSRV.ForceMCast = mDNSfalse;
query->qSRV.ReturnIntermed = mDNSfalse;
query->qSRV.SuppressUnusable = mDNSfalse;
+ query->qSRV.WakeOnResolve = mDNSfalse;
query->qSRV.QuestionCallback = FoundServiceInfoSRV;
query->qSRV.QuestionContext = query;
query->qTXT.ForceMCast = mDNSfalse;
query->qTXT.ReturnIntermed = mDNSfalse;
query->qTXT.SuppressUnusable = mDNSfalse;
+ query->qTXT.WakeOnResolve = mDNSfalse;
query->qTXT.QuestionCallback = FoundServiceInfoTXT;
query->qTXT.QuestionContext = query;
query->qAv4.ForceMCast = mDNSfalse;
query->qAv4.ReturnIntermed = mDNSfalse;
query->qAv4.SuppressUnusable = mDNSfalse;
+ query->qAv4.WakeOnResolve = mDNSfalse;
query->qAv4.QuestionCallback = FoundServiceInfo;
query->qAv4.QuestionContext = query;
query->qAv6.ForceMCast = mDNSfalse;
query->qAv6.ReturnIntermed = mDNSfalse;
query->qAv6.SuppressUnusable = mDNSfalse;
+ query->qAv6.WakeOnResolve = mDNSfalse;
query->qAv6.QuestionCallback = FoundServiceInfo;
query->qAv6.QuestionContext = query;
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);
}
}
+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);
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;
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;
};
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.
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
{
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) &&
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;
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)
{
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
// 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;
{
*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);
q->ForceMCast = mDNSfalse;
q->ReturnIntermed = mDNStrue;
q->SuppressUnusable = mDNSfalse;
+ q->WakeOnResolve = mDNSfalse;
q->QuestionCallback = FoundStaticHostname;
q->QuestionContext = mDNSNULL;
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);
// 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];
};
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;
+ }
#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
#include <TargetConditionals.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
+#include <net/bpf.h>
#include "mDNSEmbeddedAPI.h"
#include "dns_sd.h"
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;
+ }
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 */
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);
p->q.ForceMCast = mDNSfalse;
p->q.ReturnIntermed = mDNStrue;
p->q.SuppressUnusable = mDNSfalse;
+ p->q.WakeOnResolve = mDNSfalse;
p->q.QuestionCallback = AutoTunnelCallback;
p->q.QuestionContext = p;
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);
+ }
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;
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;
*/
#ifndef _DNS_SD_H
-#define _DNS_SD_H 2581800
+#define _DNS_SD_H 2582100
#ifdef __cplusplus
extern "C" {
* 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)
* 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.
+ */
};
x->qTXT.ForceMCast = mDNSfalse;
x->qTXT.ReturnIntermed = mDNSfalse;
x->qTXT.SuppressUnusable = mDNSfalse;
+ x->qTXT.WakeOnResolve = mDNSfalse;
x->qTXT.QuestionCallback = FoundServiceInfo;
x->qTXT.QuestionContext = x;
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
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;
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;
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;
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)
{
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];
};
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 -