+#ifndef NO_SECURITYFRAMEWORK
+
+static CFMutableDictionaryRef domainStatusDict = NULL;
+
+// MUST be called with lock held
+mDNSlocal void RemoveAutoTunnelDomainStatus(const DomainAuthInfo *const info)
+ {
+ char buffer[1024];
+ CFStringRef domain;
+
+ LogOperation("RemoveAutoTunnelDomainStatus: %##s", info->domain.c);
+
+ if (!domainStatusDict) { LogMsg("RemoveAutoTunnelDomainStatus: No domainStatusDict"); return; }
+
+ buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c) - 1] = 0;
+ domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+ if (!domain) { LogMsg("RemoveAutoTunnelDomainStatus: Could not create CFString domain"); return; }
+
+ if (CFDictionaryContainsKey(domainStatusDict, domain))
+ {
+ CFDictionaryRemoveValue(domainStatusDict, domain);
+ mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, domainStatusDict);
+ }
+ CFRelease(domain);
+ }
+
+#endif // ndef NO_SECURITYFRAMEWORK
+
+// MUST be called with lock held
+mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
+ {
+#ifdef NO_SECURITYFRAMEWORK
+ (void)m;
+ (void)info;
+#else
+ const NATTraversalInfo *const llq = m->LLQNAT.clientContext ? &m->LLQNAT : mDNSNULL;
+ const NATTraversalInfo *const tun = info->AutoTunnelNAT.clientContext ? &info->AutoTunnelNAT : mDNSNULL;
+ char buffer[1024];
+ CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFStringRef domain = NULL;
+ CFStringRef tmp = NULL;
+ CFNumberRef num = NULL;
+ mStatus status = mStatus_NoError;
+
+ if (!domainStatusDict)
+ {
+ domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
+ }
+
+ if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
+
+ buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c) - 1] = 0;
+ domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+ if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
+
+ mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
+ tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+ if (!tmp)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
+ CFRelease(tmp);
+ }
+
+ mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &m->ExternalAddress);
+ tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+ if (!tmp)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
+ CFRelease(tmp);
+ }
+
+ if (llq)
+ {
+ mDNSu32 port = mDNSVal16(llq->ExternalPort);
+
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
+ if (!num)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
+ CFRelease(num);
+ }
+
+ if (llq->Result)
+ {
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
+ if (!num)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
+ CFRelease(num);
+ }
+ }
+ }
+
+ if (tun)
+ {
+ mDNSu32 port = mDNSVal16(tun->ExternalPort);
+
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
+ if (!num)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
+ CFRelease(num);
+ }
+
+ if (tun->Result)
+ {
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
+ if (!num)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
+ CFRelease(num);
+ }
+ }
+ }
+
+ if (!llq && !tun)
+ {
+ status = mStatus_NotInitializedErr;
+ mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
+ }
+ else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
+ {
+ status = mStatus_DoubleNAT;
+ mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting an external address");
+ }
+ else if ((llq && llq->Result) || (tun && tun->Result))
+ {
+ status = mStatus_NATTraversal;
+ mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
+ }
+ else if (m->Router.type == mDNSAddrType_None)
+ {
+ status = mStatus_NoRouter;
+ mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
+ }
+ else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
+ {
+ status = mStatus_NoRouter;
+ mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
+ }
+ else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
+ {
+ status = mStatus_NATTraversal;
+ mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
+ }
+ else
+ {
+ DNSQuestion* q;
+ for (q = m->Questions; q; q=q->next)
+ if (q->LongLived && q->AuthInfo == info && q->state == LLQ_Poll)
+ {
+ status = mStatus_PollingMode;
+ mDNS_snprintf(buffer, sizeof(buffer), "Query polling %##s", q->qname.c);
+ break;
+ }
+ if (status == mStatus_NoError)
+ for (q = m->Questions; q; q=q->next)
+ if (q->LongLived && q->AuthInfo == info && q->state != LLQ_Established && !q->DuplicateOf)
+ {
+ status = mStatus_TransientErr;
+ mDNS_snprintf(buffer, sizeof(buffer), "Query not yet established %##s", q->qname.c);
+ break;
+ }
+ if (status == mStatus_NoError) mDNS_snprintf(buffer, sizeof(buffer), "Success");
+ }
+
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
+ if (!num)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
+ CFRelease(num);
+ }
+
+ tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+ if (!tmp)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
+ CFRelease(tmp);
+ }
+
+ if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
+ !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
+ {
+ CFDictionarySetValue(domainStatusDict, domain, dict);
+ mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, domainStatusDict);
+ }
+
+ CFRelease(domain);
+ CFRelease(dict);
+
+ LogOperation("UpdateAutoTunnelDomainStatus: %s", buffer);
+#endif // def NO_SECURITYFRAMEWORK
+ }
+
+// MUST be called with lock held
+mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
+ {
+#ifdef NO_SECURITYFRAMEWORK
+ (void)m;
+#else
+ DomainAuthInfo* info;
+ for (info = m->AuthInfoList; info; info = info->next)
+ if (info->AutoTunnel && !info->deltime)
+ UpdateAutoTunnelDomainStatus(m, info);
+#endif // def NO_SECURITYFRAMEWORK
+ }
+