1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 // ***************************************************************************
20 // Supporting routines to run mDNS on a CFRunLoop platform
21 // ***************************************************************************
23 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
24 // including ones that mDNSResponder chooses not to use.
25 #define LIST_ALL_INTERFACES 0
27 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
28 #include "DNSCommon.h"
30 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
31 #include "dns_sd.h" // For mDNSInterface_LocalOnly etc.
32 #include "dns_sd_internal.h"
33 #include "PlatformCommon.h"
34 #include "uds_daemon.h"
35 #include "CryptoSupport.h"
38 #include <stdarg.h> // For va_list support
39 #include <stdlib.h> // For arc4random
41 #include <net/if_types.h> // For IFT_ETHER
42 #include <net/if_dl.h>
43 #include <net/bpf.h> // For BIOCSETIF etc.
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <sys/sysctl.h>
48 #include <sys/event.h>
50 #include <sys/ioctl.h>
51 #include <time.h> // platform support for UTC time
52 #include <arpa/inet.h> // for inet_aton
54 #include <netdb.h> // for getaddrinfo
55 #include <sys/sockio.h> // for SIOCGIFEFLAGS
57 #include <netinet/in.h> // For IP_RECVTTL
59 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
62 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
63 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
64 #include <netinet6/in6_var.h> // For IN6_IFF_TENTATIVE etc.
66 #include <netinet/tcp.h>
68 #include <DebugServices.h>
73 #include <IOKit/IOKitLib.h>
74 #include <IOKit/IOMessage.h>
76 #include <IOKit/ps/IOPowerSources.h>
77 #include <IOKit/ps/IOPowerSourcesPrivate.h>
78 #include <IOKit/ps/IOPSKeys.h>
80 #include <mach/mach_error.h>
81 #include <mach/mach_port.h>
82 #include <mach/mach_time.h>
84 #include "P2PPacketFilter.h"
86 #include <SystemConfiguration/SCPrivate.h>
89 // For WiFiManagerClientRef etc, declarations.
90 #include <MobileGestalt.h>
91 #include <MobileWiFi/WiFiManagerClient.h>
93 #endif // TARGET_OS_IPHONE
95 // Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
96 #include <Kernel/IOKit/apple80211/apple80211_var.h>
97 #include <network_information.h> // for nwi_state
99 #if APPLE_OSX_mDNSResponder
101 #include <ne_session.h> // for ne_session_set_socket_attributes()
104 #endif // APPLE_OSX_mDNSResponder
106 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
107 #include <IOKit/platform/IOPlatformSupportPrivate.h>
108 #endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
111 #include "unittest.h"
114 #define kInterfaceSpecificOption "interface="
116 #define mDNS_IOREG_KEY "mDNS_KEY"
117 #define mDNS_IOREG_VALUE "2009-07-30"
118 #define mDNS_IOREG_KA_KEY "mDNS_Keepalive"
119 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
121 #define DARK_WAKE_TIME 16 // Time we hold an idle sleep assertion for maintenance after a wake notification
123 // cache the InterfaceID of the AWDL interface
124 mDNSInterfaceID AWDLInterfaceID;
126 // ***************************************************************************
129 #if COMPILER_LIKES_PRAGMA_MARK
130 #pragma mark - Globals
133 // By default we don't offer sleep proxy service
134 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
135 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
136 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
137 mDNSexport int OfferSleepProxyService = 0;
138 mDNSexport int DisableSleepProxyClient = 0;
139 mDNSexport int UseInternalSleepProxy = 1; // Set to non-zero to use internal (in-NIC) Sleep Proxy
141 mDNSexport int OSXVers, iOSVers;
142 mDNSexport int KQueueFD;
144 #ifndef NO_SECURITYFRAMEWORK
145 static CFArrayRef ServerCerts;
146 OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
147 #endif /* NO_SECURITYFRAMEWORK */
149 static CFStringRef NetworkChangedKey_IPv4;
150 static CFStringRef NetworkChangedKey_IPv6;
151 static CFStringRef NetworkChangedKey_Hostnames;
152 static CFStringRef NetworkChangedKey_Computername;
153 static CFStringRef NetworkChangedKey_DNS;
154 static CFStringRef NetworkChangedKey_StateInterfacePrefix;
155 static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
156 static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
157 static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity");
158 static CFStringRef NetworkChangedKey_PowerSettings = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
160 static char HINFO_HWstring_buffer[32];
161 static char *HINFO_HWstring = "Device";
162 static int HINFO_HWstring_prefixlen = 6;
164 mDNSexport int WatchDogReportingThreshold = 250;
166 dispatch_queue_t SSLqueue;
168 #if TARGET_OS_EMBEDDED
169 #define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
172 #if APPLE_OSX_mDNSResponder
173 static mDNSu8 SPMetricPortability = 99;
174 static mDNSu8 SPMetricMarginalPower = 99;
175 static mDNSu8 SPMetricTotalPower = 99;
176 static mDNSu8 SPMetricFeatures = 1; /* The current version supports TCP Keep Alive Feature */
177 mDNSexport domainname ActiveDirectoryPrimaryDomain;
178 mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
179 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
180 #endif // APPLE_OSX_mDNSResponder
182 // Don't send triggers too often. We arbitrarily limit it to three minutes.
183 #define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
185 // Used by AutoTunnel
186 const char btmmprefix[] = "btmmdns:";
187 const char dnsprefix[] = "dns:";
189 // String Array used to write list of private domains to Dynamic Store
190 static CFArrayRef privateDnsArray = NULL;
192 // ***************************************************************************
195 #if COMPILER_LIKES_PRAGMA_MARK
197 #pragma mark - Utility Functions
200 // We only attempt to send and receive multicast packets on interfaces that are
201 // (a) flagged as multicast-capable
202 // (b) *not* flagged as point-to-point (e.g. modem)
203 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
204 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
205 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
207 #if BONJOUR_ON_DEMAND
208 #define MulticastInterface(i) ((i)->m->BonjourEnabled && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
210 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
212 #define SPSInterface(i) ((i)->ifinfo.McastTxRx && !((i)->ifa_flags & IFF_LOOPBACK) && !(i)->D2DInterface)
214 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
216 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
219 // Determine if we're at Apple (17.*.*.*)
220 NetworkInterfaceInfoOSX *i;
221 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
222 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
225 return; // If not at Apple, don't show the alert
229 LogMsg("NotifyOfElusiveBug: %s", title);
230 LogMsg("NotifyOfElusiveBug: %s", msg);
232 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
233 // To avoid this, we don't try to display alerts in the first three minutes after boot.
234 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180))
236 LogMsg("Suppressing notification early in boot: %d", mDNSPlatformRawTime());
240 #ifndef NO_CFUSERNOTIFICATION
241 static int notifyCount = 0; // To guard against excessive display of warning notifications
245 mDNSNotify(title, msg);
247 #endif /* NO_CFUSERNOTIFICATION */
251 // Write a syslog message and display an alert, then if ForceAlerts is set, generate a stack trace
252 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
253 mDNSexport void LogMemCorruption(const char *format, ...)
257 va_start(ptr,format);
258 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
260 LogMsg("!!!! %s !!!!", buffer);
261 NotifyOfElusiveBug("Memory Corruption", buffer);
263 *(volatile long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
268 // Like LogMemCorruption above, but only display the alert if ForceAlerts is set and we're going to generate a stack trace
269 #if APPLE_OSX_mDNSResponder
270 mDNSexport void LogFatalError(const char *format, ...)
274 va_start(ptr,format);
275 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
277 LogMsg("!!!! %s !!!!", buffer);
279 NotifyOfElusiveBug("Fatal Error. See /Library/Logs/DiagnosticReports", buffer);
280 *(volatile long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
285 // Returns true if it is an AppleTV based hardware running iOS, false otherwise
286 mDNSlocal mDNSBool IsAppleTV(void)
288 #if TARGET_OS_EMBEDDED
289 static mDNSBool sInitialized = mDNSfalse;
290 static mDNSBool sIsAppleTV = mDNSfalse;
291 CFStringRef deviceClass = NULL;
295 deviceClass = (CFStringRef) MGCopyAnswer(kMGQDeviceClass, NULL);
298 if(CFEqual(deviceClass, kMGDeviceClassAppleTV))
299 sIsAppleTV = mDNStrue;
300 CFRelease(deviceClass);
302 sInitialized = mDNStrue;
307 #endif // TARGET_OS_EMBEDDED
310 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
312 static struct ifaddrs *ifa = NULL;
325 mDNSlocal void DynamicStoreWrite(int key, const char* subkey, uintptr_t value, signed long valueCnt)
327 CFStringRef sckey = NULL;
328 Boolean release_sckey = FALSE;
329 CFDataRef bytes = NULL;
330 CFPropertyListRef plist = NULL;
332 switch ((enum mDNSDynamicStoreSetConfigKey)key)
334 case kmDNSMulticastConfig:
335 sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
337 case kmDNSDynamicConfig:
338 sckey = CFSTR("State:/Network/DynamicDNS");
340 case kmDNSPrivateConfig:
341 sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
343 case kmDNSBackToMyMacConfig:
344 sckey = CFSTR("State:/Network/BackToMyMac");
346 case kmDNSSleepProxyServersState:
348 CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0);
349 CFStringAppend(tmp, CFSTR("State:/Network/Interface/"));
350 CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8);
351 CFStringAppend(tmp, CFSTR("/SleepProxyServers"));
352 sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp);
353 release_sckey = TRUE;
357 case kmDNSDebugState:
358 sckey = CFSTR("State:/Network/mDNSResponder/DebugState");
361 LogMsg("unrecognized key %d", key);
364 if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
365 valueCnt, kCFAllocatorNull)))
367 LogMsg("CFDataCreateWithBytesNoCopy of value failed");
370 if (NULL == (plist = CFPropertyListCreateWithData(NULL, bytes, kCFPropertyListImmutable, NULL, NULL)))
372 LogMsg("CFPropertyListCreateWithData of bytes failed");
377 SCDynamicStoreSetValue(NULL, sckey, plist);
384 if (release_sckey && sckey)
388 mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value)
390 CFPropertyListRef valueCopy;
391 char *subkeyCopy = NULL;
395 // We need to copy the key and value before we dispatch off the block below as the
396 // caller will free the memory once we return from this function.
397 valueCopy = CFPropertyListCreateDeepCopy(NULL, value, kCFPropertyListImmutable);
400 LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
405 int len = strlen(subkey);
406 subkeyCopy = mDNSPlatformMemAllocate(len + 1);
409 LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
410 CFRelease(valueCopy);
413 mDNSPlatformMemCopy(subkeyCopy, subkey, len);
417 dispatch_async(dispatch_get_main_queue(), ^{
418 CFWriteStreamRef stream = NULL;
419 CFDataRef bytes = NULL;
423 if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL)))
425 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
428 CFWriteStreamOpen(stream);
429 ret = CFPropertyListWrite(valueCopy, stream, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
432 LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
435 if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten)))
437 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
440 CFWriteStreamClose(stream);
443 DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes));
446 CFRelease(valueCopy);
449 CFWriteStreamClose(stream);
455 mDNSPlatformMemFree(subkeyCopy);
457 KQueueUnlock("mDNSDynamicStoreSetConfig");
461 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
462 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(const char *ifname, int type)
464 NetworkInterfaceInfoOSX *i;
465 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
466 if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
467 ((type == AF_UNSPEC ) ||
468 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
469 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
473 mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
476 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
477 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
478 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
479 { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
483 mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(mDNSInterfaceID ifindex)
485 mDNS *const m = &mDNSStorage;
486 mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
487 NetworkInterfaceInfoOSX *i;
489 // Don't get tricked by inactive interfaces
490 for (i = m->p->InterfaceList; i; i = i->next)
491 if (i->Registered && i->scope_id == scope_id) return(i);
496 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
499 if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
500 if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
501 if (ifindex == kDNSServiceInterfaceIndexBLE ) return(mDNSInterface_BLE);
502 if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
504 NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
507 // Not found. Make sure our interface list is up to date, then try again.
508 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
509 mDNSMacOSXNetworkChanged();
510 ifi = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
513 if (!ifi) return(mDNSNULL);
515 return(ifi->ifinfo.InterfaceID);
519 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
521 NetworkInterfaceInfoOSX *i;
522 if (id == mDNSInterface_Any ) return(0);
523 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
524 if (id == mDNSInterface_Unicast ) return(0);
525 if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
526 if (id == mDNSInterface_BLE ) return(kDNSServiceInterfaceIndexBLE);
528 mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
530 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
531 for (i = m->p->InterfaceList; i; i = i->next)
532 if (i->scope_id == scope_id) return(i->scope_id);
534 // If we are supposed to suppress network change, return "id" back
535 if (suppressNetworkChange) return scope_id;
537 // Not found. Make sure our interface list is up to date, then try again.
538 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
539 mDNSMacOSXNetworkChanged();
540 for (i = m->p->InterfaceList; i; i = i->next)
541 if (i->scope_id == scope_id) return(i->scope_id);
546 #if COMPILER_LIKES_PRAGMA_MARK
548 #pragma mark - UDP & TCP send & receive
551 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
553 mDNSBool result = mDNSfalse;
554 SCNetworkConnectionFlags flags;
555 CFDataRef remote_addr;
556 CFMutableDictionaryRef options;
557 SCNetworkReachabilityRef ReachRef = NULL;
559 options = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
560 remote_addr = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len);
561 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, remote_addr);
562 CFDictionarySetValue(options, kSCNetworkReachabilityOptionServerBypass, kCFBooleanTrue);
563 ReachRef = SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault, options);
565 CFRelease(remote_addr);
569 LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions");
572 if (!SCNetworkReachabilityGetFlags(ReachRef, &flags))
574 LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags");
577 result = flags & kSCNetworkFlagsConnectionRequired;
585 // Set traffic class for socket
586 mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass)
590 if (useBackgroundTrafficClass)
591 traffic_class = SO_TC_BK_SYS;
593 traffic_class = SO_TC_CTL;
595 (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class));
599 // Run the unit test main
602 mDNSlocal int mDNSPlatformGetSocktFd(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType)
604 if (transType == mDNSTransport_UDP)
606 UDPSocket* sock = (UDPSocket*) sockCxt;
607 return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6;
609 else if (transType == mDNSTransport_TCP)
611 TCPSocket* sock = (TCPSocket*) sockCxt;
612 return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6;
616 LogInfo("mDNSPlatformGetSocktFd: invalid transport %d", transType);
617 return kInvalidSocketRef;
621 mDNSexport void mDNSPlatformSetSocktOpt(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType, const DNSQuestion *q)
624 char unenc_name[MAX_ESCAPED_DOMAIN_NAME];
626 // verify passed-in arguments exist and that sockfd is valid
627 if (q == mDNSNULL || sockCxt == mDNSNULL || (sockfd = mDNSPlatformGetSocktFd(sockCxt, transType, addrType)) < 0)
632 if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1)
633 LogMsg("mDNSPlatformSetSocktOpt: Delegate PID failed %s for PID %d", strerror(errno), q->pid);
637 if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1)
638 LogMsg("mDNSPlatformSetSocktOpt: Delegate UUID failed %s", strerror(errno));
641 // set the domain on the socket
642 ConvertDomainNameToCString(&q->qname, unenc_name);
643 if (!(ne_session_set_socket_attributes(sockfd, unenc_name, NULL)))
644 LogInfo("mDNSPlatformSetSocktOpt: ne_session_set_socket_attributes()-> setting domain failed for %s", unenc_name);
647 if (setsockopt(sockfd, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
648 LogInfo("mDNSPlatformSetSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
652 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
653 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
654 // OR send via our primary v4 unicast socket
655 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
656 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
657 mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
658 mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
660 NetworkInterfaceInfoOSX *info = mDNSNULL;
661 struct sockaddr_storage to;
663 mStatus result = mStatus_NoError;
668 info = IfindexToInterfaceInfoOSX(InterfaceID);
671 // We may not have registered interfaces with the "core" as we may not have
672 // seen any interface notifications yet. This typically happens during wakeup
673 // where we might try to send DNS requests (non-SuppressUnusable questions internal
674 // to mDNSResponder) before we receive network notifications.
675 LogInfo("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
676 return mStatus_BadParamErr;
680 char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
682 if (dst->type == mDNSAddrType_IPv4)
684 struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
685 sin_to->sin_len = sizeof(*sin_to);
686 sin_to->sin_family = AF_INET;
687 sin_to->sin_port = dstPort.NotAnInteger;
688 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
689 s = (src ? src->ss : m->p->permanentsockets).sktv4;
691 if (!mDNSAddrIsDNSMulticast(dst))
694 const mDNSu32 ifindex = info ? info->scope_id : IFSCOPE_NONE;
695 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
697 static int displayed = 0;
698 if (displayed < 1000)
701 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
707 #ifdef IP_MULTICAST_IFINDEX
708 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IFINDEX, &info->scope_id, sizeof(info->scope_id));
709 // We get an error when we compile on a machine that supports this option and run the binary on
710 // a different machine that does not support it
713 if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno);
714 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
715 if (err < 0 && !m->NetworkChanged)
716 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
719 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
720 if (err < 0 && !m->NetworkChanged)
721 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
725 else if (dst->type == mDNSAddrType_IPv6)
727 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
728 sin6_to->sin6_len = sizeof(*sin6_to);
729 sin6_to->sin6_family = AF_INET6;
730 sin6_to->sin6_port = dstPort.NotAnInteger;
731 sin6_to->sin6_flowinfo = 0;
732 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
733 sin6_to->sin6_scope_id = info ? info->scope_id : 0;
734 s = (src ? src->ss : m->p->permanentsockets).sktv6;
735 if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
737 err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
740 const int setsockopt_errno = errno;
742 if (if_indextoname(info->scope_id, name) != NULL)
743 LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, setsockopt_errno, strerror(setsockopt_errno));
745 LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id);
749 if (info) // Specify outgoing interface for non-multicast destination
751 if (!mDNSAddrIsDNSMulticast(dst))
753 if (info->scope_id == 0)
754 LogInfo("IPV6_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
756 setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
764 LogFatalError("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
765 return mStatus_BadParamErr;
769 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
770 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
772 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
773 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
775 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
776 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
777 if (s < 0) return(mStatus_Invalid);
779 // switch to background traffic class for this message if requested
780 if (useBackgroundTrafficClass)
781 setTrafficClass(s, useBackgroundTrafficClass);
783 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
784 sendto_errno = (err < 0) ? errno : 0;
786 // set traffic class back to default value
787 if (useBackgroundTrafficClass)
788 setTrafficClass(s, mDNSfalse);
792 static int MessageCount = 0;
793 LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
794 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
795 if (!mDNSAddressIsAllDNSLinkGroup(dst))
797 if (sendto_errno == EHOSTUNREACH) return(mStatus_HostUnreachErr);
798 if (sendto_errno == EHOSTDOWN || sendto_errno == ENETDOWN || sendto_errno == ENETUNREACH) return(mStatus_TransientErr);
800 // Don't report EHOSTUNREACH in the first three minutes after boot
801 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
802 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
803 if (sendto_errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
804 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
805 if (sendto_errno == EADDRNOTAVAIL && m->NetworkChanged) return(mStatus_TransientErr);
806 if (sendto_errno == EHOSTUNREACH || sendto_errno == EADDRNOTAVAIL || sendto_errno == ENETDOWN)
807 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
808 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
812 if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs
813 LogMsg("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
814 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
815 else // If logging is enabled, remove the cap and log aggressively
816 LogInfo("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
817 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
820 result = mStatus_UnknownErr;
826 mDNSexport ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
827 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
829 static unsigned int numLogMessages = 0;
830 struct iovec databuffers = { (char *)buffer, max };
833 struct cmsghdr *cmPtr;
834 char ancillary[1024];
836 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
838 // Set up the message
839 msg.msg_name = (caddr_t)from;
840 msg.msg_namelen = *fromlen;
841 msg.msg_iov = &databuffers;
843 msg.msg_control = (caddr_t)&ancillary;
844 msg.msg_controllen = sizeof(ancillary);
848 n = recvmsg(s, &msg, 0);
851 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
854 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
856 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d",
857 s, n, msg.msg_controllen, sizeof(struct cmsghdr), errno);
860 if (msg.msg_flags & MSG_CTRUNC)
862 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
866 *fromlen = msg.msg_namelen;
868 // Parse each option out of the ancillary data.
869 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
871 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
872 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
874 dstaddr->type = mDNSAddrType_IPv4;
875 dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
876 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
878 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
880 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
881 if (sdl->sdl_nlen < IF_NAMESIZE)
883 mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
884 ifname[sdl->sdl_nlen] = 0;
885 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
888 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
889 *ttl = *(u_char*)CMSG_DATA(cmPtr);
890 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
892 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
893 dstaddr->type = mDNSAddrType_IPv6;
894 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
895 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
897 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
898 *ttl = *(int*)CMSG_DATA(cmPtr);
904 // What is this for, and why does it use xor instead of a simple quality check? -- SC
905 mDNSlocal mDNSInterfaceID FindMyInterface(const mDNSAddr *addr)
907 NetworkInterfaceInfo *intf;
909 if (addr->type == mDNSAddrType_IPv4)
911 for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
913 if (intf->ip.type == addr->type && intf->McastTxRx)
915 if ((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) == 0)
917 return(intf->InterfaceID);
923 if (addr->type == mDNSAddrType_IPv6)
925 for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
927 if (intf->ip.type == addr->type && intf->McastTxRx)
929 if (((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) == 0) &&
930 ((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) == 0) &&
931 ((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) == 0) &&
932 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) == 0)))
934 return(intf->InterfaceID);
939 return(mDNSInterface_Any);
942 mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool encounteredEOF)
944 KQSocketSet *const ss = (KQSocketSet *)context;
945 mDNS *const m = ss->m;
946 int err = 0, count = 0, closed = 0;
948 if (filter != EVFILT_READ)
949 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
951 if (s1 != ss->sktv4 && s1 != ss->sktv6)
953 LogMsg("myKQSocketCallBack: native socket %d", s1);
954 LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6);
959 LogMsg("myKQSocketCallBack: socket %d is no longer readable (EOF)", s1);
962 ss->sktv4EOF = mDNStrue;
963 KQueueSet(ss->sktv4, EV_DELETE, EVFILT_READ, &ss->kqsv4);
965 else if (s1 == ss->sktv6)
967 ss->sktv6EOF = mDNStrue;
968 KQueueSet(ss->sktv6, EV_DELETE, EVFILT_READ, &ss->kqsv6);
975 mDNSAddr senderAddr, destAddr = zeroAddr;
976 mDNSIPPort senderPort;
977 struct sockaddr_storage from;
978 size_t fromlen = sizeof(from);
979 char packetifname[IF_NAMESIZE] = "";
981 err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
984 if ((destAddr.type == mDNSAddrType_IPv4 && (destAddr.ip.v4.b[0] & 0xF0) == 0xE0) ||
985 (destAddr.type == mDNSAddrType_IPv6 && (destAddr.ip.v6.b[0] == 0xFF))) m->p->num_mcasts++;
988 if (from.ss_family == AF_INET)
990 struct sockaddr_in *s = (struct sockaddr_in*)&from;
991 senderAddr.type = mDNSAddrType_IPv4;
992 senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
993 senderPort.NotAnInteger = s->sin_port;
994 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
996 else if (from.ss_family == AF_INET6)
998 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
999 senderAddr.type = mDNSAddrType_IPv6;
1000 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
1001 senderPort.NotAnInteger = sin6->sin6_port;
1002 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1006 LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
1010 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1011 mDNSInterfaceID InterfaceID = mDNSNULL;
1012 NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
1015 if (intf->Exists && !strcmp(intf->ifinfo.ifname, packetifname))
1020 // When going to sleep we deregister all our interfaces, but if the machine
1021 // takes a few seconds to sleep we may continue to receive multicasts
1022 // during that time, which would confuse mDNSCoreReceive, because as far
1023 // as it's concerned, we should have no active interfaces any more.
1024 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1026 InterfaceID = intf->ifinfo.InterfaceID;
1027 else if (mDNSAddrIsDNSMulticast(&destAddr))
1032 InterfaceID = FindMyInterface(&destAddr);
1035 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1036 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
1038 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
1039 // loop when that happens, or we may try to read from an invalid FD. We do this by
1040 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
1041 // if it closes the socketset.
1042 ss->closeFlag = &closed;
1046 m->p->UDPProxyCallback(&m->p->UDPProxy, &m->imsg.m, (unsigned char*)&m->imsg + err, &senderAddr,
1047 senderPort, &destAddr, ss->port, InterfaceID, NULL);
1051 mDNSCoreReceive(m, &m->imsg.m, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
1054 // if we didn't close, we can safely dereference the socketset, and should to
1055 // reset the closeFlag, since it points to something on the stack
1056 if (!closed) ss->closeFlag = mDNSNULL;
1059 // If a client application's sockets are marked as defunct
1060 // sockets we have delegated to it with SO_DELEGATED will also go defunct.
1061 // We get an ENOTCONN error for defunct sockets and should just close the socket in that case.
1062 if (err < 0 && errno == ENOTCONN)
1064 LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
1069 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
1071 // Something is busted here.
1072 // kqueue says there is a packet, but myrecvfrom says there is not.
1073 // Try calling select() to get another opinion.
1074 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1075 // All of this is racy, as data may have arrived after the call to select()
1076 static unsigned int numLogMessages = 0;
1077 const int save_errno = errno;
1081 socklen_t solen = sizeof(int);
1083 struct timeval timeout;
1086 FD_SET(s1, &readfds);
1088 timeout.tv_usec = 0;
1089 selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
1090 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
1091 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
1092 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
1093 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
1094 if (ioctl(s1, FIONREAD, &fionread) == -1)
1095 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
1096 if (numLogMessages++ < 100)
1097 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1098 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
1099 if (numLogMessages > 5)
1100 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1101 "Congratulations, you've reproduced an elusive bug.\r"
1102 "Please send email to radar-3387020@group.apple.com.)\r"
1103 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1105 sleep(1); // After logging this error, rate limit so we don't flood syslog
1109 mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
1111 mDNSBool c = !sock->connected;
1112 sock->connected = mDNStrue;
1113 sock->callback(sock, sock->context, c, sock->err);
1114 // Note: the callback may call CloseConnection here, which frees the context structure!
1117 #ifndef NO_SECURITYFRAMEWORK
1119 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
1121 int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1122 if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1123 if (ret >= 0) { *dataLength = ret; return(noErr); }
1125 if (errno == EAGAIN ) return(errSSLWouldBlock);
1126 if (errno == ENOENT ) return(errSSLClosedGraceful);
1127 if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
1128 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
1129 return(errSSLClosedAbort);
1132 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
1134 int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1135 if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1136 if (ret > 0) { *dataLength = ret; return(noErr); }
1138 if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
1139 if ( errno == EAGAIN ) return(errSSLWouldBlock);
1140 if ( errno == ECONNRESET) return(errSSLClosedAbort);
1141 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
1142 return(errSSLClosedAbort);
1145 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConnectionType ctype)
1147 char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
1149 sock->tlsContext = SSLCreateContext(kCFAllocatorDefault, pside, ctype);
1150 if (!sock->tlsContext)
1152 LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
1153 return(mStatus_UnknownErr);
1156 mStatus err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
1159 LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err);
1163 err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
1166 LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err);
1170 // Set the default ciphersuite configuration
1171 err = SSLSetSessionConfig(sock->tlsContext, CFSTR("default"));
1174 LogMsg("ERROR: tlsSetupSock: SSLSetSessionConfig failed with error code: %d", err);
1178 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
1179 // (error not in OSStatus space) is okay.
1180 if (!sock->hostname.c[0])
1182 LogMsg("ERROR: tlsSetupSock: hostname NULL");
1187 ConvertDomainNameToCString(&sock->hostname, domname_cstr);
1188 err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
1191 LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err);
1198 if (sock->tlsContext)
1199 CFRelease(sock->tlsContext);
1203 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1204 mDNSlocal void doSSLHandshake(TCPSocket *sock)
1206 mStatus err = SSLHandshake(sock->tlsContext);
1208 //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
1209 //defined, KQueueLock is a noop. Hence we need to serialize here
1211 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
1212 //We need the rest of the logic also. Otherwise, we can enable the READ
1213 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
1214 //ConnFailed which means we are going to free the tcpInfo. While it
1215 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
1216 //and potentially call doTCPCallback with error which can close the fd and free the
1217 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
1220 dispatch_async(dispatch_get_main_queue(), ^{
1222 LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1224 if (sock->handshake == handshake_to_be_closed)
1226 LogInfo("SSLHandshake completed after close");
1227 mDNSPlatformTCPCloseConnection(sock);
1231 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1232 else LogMsg("doSSLHandshake: sock->fd is -1");
1234 if (err == errSSLWouldBlock)
1235 sock->handshake = handshake_required;
1240 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1241 CFRelease(sock->tlsContext);
1242 sock->tlsContext = NULL;
1245 sock->err = err ? mStatus_ConnFailed : 0;
1246 sock->handshake = handshake_completed;
1248 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1249 doTcpSocketCallback(sock);
1253 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1257 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1258 mDNSlocal void *doSSLHandshake(TCPSocket *sock)
1260 // Warning: Touching sock without the kqueue lock!
1261 // We're protected because sock->handshake == handshake_in_progress
1262 mStatus err = SSLHandshake(sock->tlsContext);
1265 debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1267 if (sock->handshake == handshake_to_be_closed)
1269 LogInfo("SSLHandshake completed after close");
1270 mDNSPlatformTCPCloseConnection(sock);
1274 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1275 else LogMsg("doSSLHandshake: sock->fd is -1");
1277 if (err == errSSLWouldBlock)
1278 sock->handshake = handshake_required;
1283 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1284 CFRelease(sock->tlsContext);
1285 sock->tlsContext = NULL;
1288 sock->err = err ? mStatus_ConnFailed : 0;
1289 sock->handshake = handshake_completed;
1291 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1292 doTcpSocketCallback(sock);
1296 debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1297 KQueueUnlock("doSSLHandshake");
1300 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1302 mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
1304 debugf("spawnSSLHandshake %p: entry", sock);
1306 if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
1307 sock->handshake = handshake_in_progress;
1308 KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
1310 // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
1311 // to limit the number of threads used for SSLHandshake
1312 dispatch_async(SSLqueue, ^{doSSLHandshake(sock);});
1314 debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
1317 #endif /* NO_SECURITYFRAMEWORK */
1319 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context, __unused mDNSBool encounteredEOF)
1321 TCPSocket *sock = context;
1322 sock->err = mStatus_NoError;
1324 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1325 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1326 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1327 if (filter == EVFILT_WRITE)
1328 KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
1330 if (sock->flags & kTCPSocketFlags_UseTLS)
1332 #ifndef NO_SECURITYFRAMEWORK
1335 sock->setup = mDNStrue;
1336 sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
1339 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
1343 if (sock->handshake == handshake_required)
1345 spawnSSLHandshake(sock);
1348 else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
1352 else if (sock->handshake != handshake_completed)
1355 sock->err = mStatus_UnknownErr;
1356 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
1358 #else /* NO_SECURITYFRAMEWORK */
1359 sock->err = mStatus_UnsupportedErr;
1360 #endif /* NO_SECURITYFRAMEWORK */
1363 doTcpSocketCallback(sock);
1366 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1367 mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef)
1369 dispatch_queue_t queue = dispatch_get_main_queue();
1370 dispatch_source_t source;
1371 if (flags == EV_DELETE)
1373 if (filter == EVFILT_READ)
1375 dispatch_source_cancel(entryRef->readSource);
1376 dispatch_release(entryRef->readSource);
1377 entryRef->readSource = mDNSNULL;
1378 debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource);
1380 else if (filter == EVFILT_WRITE)
1382 dispatch_source_cancel(entryRef->writeSource);
1383 dispatch_release(entryRef->writeSource);
1384 entryRef->writeSource = mDNSNULL;
1385 debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource);
1388 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
1391 if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
1393 if (filter == EVFILT_READ)
1395 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
1397 else if (filter == EVFILT_WRITE)
1399 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
1403 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
1406 if (!source) return -1;
1407 dispatch_source_set_event_handler(source, ^{
1409 mDNSs32 stime = mDNSPlatformRawTime();
1410 entryRef->KQcallback(fd, filter, entryRef->KQcontext);
1411 mDNSs32 etime = mDNSPlatformRawTime();
1412 if (etime - stime >= WatchDogReportingThreshold)
1413 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime);
1415 // Trigger the event delivery to the application. Even though we trigger the
1416 // event completion after handling every event source, these all will hopefully
1418 TriggerEventCompletion();
1421 dispatch_source_set_cancel_handler(source, ^{
1422 if (entryRef->fdClosed)
1424 //LogMsg("CancelHandler: closing fd %d", fd);
1428 dispatch_resume(source);
1429 if (filter == EVFILT_READ)
1430 entryRef->readSource = source;
1432 entryRef->writeSource = source;
1437 mDNSexport void KQueueLock()
1440 mDNSexport void KQueueUnlock(const char const *task)
1442 (void)task; //unused
1445 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
1447 struct kevent new_event;
1448 EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
1449 return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
1452 mDNSexport void KQueueLock()
1454 mDNS *const m = &mDNSStorage;
1455 pthread_mutex_lock(&m->p->BigMutex);
1456 m->p->BigMutexStartTime = mDNSPlatformRawTime();
1459 mDNSexport void KQueueUnlock(const char* task)
1461 mDNS *const m = &mDNSStorage;
1462 mDNSs32 end = mDNSPlatformRawTime();
1464 if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
1465 LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
1467 pthread_mutex_unlock(&m->p->BigMutex);
1470 if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
1471 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
1475 mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
1477 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1481 dispatch_source_cancel(kq->readSource);
1482 kq->readSource = mDNSNULL;
1484 if (kq->writeSource)
1486 dispatch_source_cancel(kq->writeSource);
1487 kq->writeSource = mDNSNULL;
1489 // Close happens in the cancellation handler
1490 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
1491 kq->fdClosed = mDNStrue;
1498 mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
1500 KQSocketSet *cp = &sock->ss;
1501 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
1502 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
1503 const int on = 1; // "on" for setsockopt
1506 int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
1507 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
1509 // for TCP sockets, the traffic class is set once and not changed
1510 setTrafficClass(skt, useBackgroundTrafficClass);
1512 if (sa_family == AF_INET)
1515 struct sockaddr_in addr;
1516 mDNSPlatformMemZero(&addr, sizeof(addr));
1517 addr.sin_family = AF_INET;
1518 addr.sin_port = port->NotAnInteger;
1519 err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
1520 if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); close(skt); return err; }
1522 // Receive interface identifiers
1523 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
1524 if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); close(skt); return err; }
1526 mDNSPlatformMemZero(&addr, sizeof(addr));
1527 socklen_t len = sizeof(addr);
1528 err = getsockname(skt, (struct sockaddr*) &addr, &len);
1529 if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); close(skt); return err; }
1531 port->NotAnInteger = addr.sin_port;
1536 struct sockaddr_in6 addr6;
1537 mDNSPlatformMemZero(&addr6, sizeof(addr6));
1538 addr6.sin6_family = AF_INET6;
1539 addr6.sin6_port = port->NotAnInteger;
1540 err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
1541 if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); close(skt); return err; }
1543 // We want to receive destination addresses and receive interface identifiers
1544 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
1545 if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); close(skt); return err; }
1547 mDNSPlatformMemZero(&addr6, sizeof(addr6));
1548 socklen_t len = sizeof(addr6);
1549 err = getsockname(skt, (struct sockaddr *) &addr6, &len);
1550 if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); close(skt); return err; }
1552 port->NotAnInteger = addr6.sin6_port;
1556 k->KQcallback = tcpKQSocketCallback;
1557 k->KQcontext = sock;
1558 k->KQtask = "mDNSPlatformTCPSocket";
1559 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1560 k->readSource = mDNSNULL;
1561 k->writeSource = mDNSNULL;
1562 k->fdClosed = mDNSfalse;
1564 return mStatus_NoError;
1567 mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
1571 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
1572 if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
1574 mDNSPlatformMemZero(sock, sizeof(TCPSocket));
1576 sock->ss.m = &mDNSStorage;
1577 sock->ss.sktv4 = -1;
1578 sock->ss.sktv6 = -1;
1579 err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
1583 err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass);
1584 if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
1588 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
1589 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
1592 // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
1593 sock->fd = sock->ss.sktv4;
1594 sock->callback = mDNSNULL;
1595 sock->flags = flags;
1596 sock->context = mDNSNULL;
1597 sock->setup = mDNSfalse;
1598 sock->connected = mDNSfalse;
1599 sock->handshake = handshake_required;
1600 sock->m = &mDNSStorage;
1601 sock->err = mStatus_NoError;
1606 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
1608 KQSocketSet *cp = &sock->ss;
1609 int *s = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
1610 KQueueEntry *k = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
1611 mStatus err = mStatus_NoError;
1612 struct sockaddr_storage ss;
1614 sock->callback = callback;
1615 sock->context = context;
1616 sock->setup = mDNSfalse;
1617 sock->connected = mDNSfalse;
1618 sock->handshake = handshake_required;
1619 sock->err = mStatus_NoError;
1621 if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
1623 if (dst->type == mDNSAddrType_IPv4)
1625 struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
1626 mDNSPlatformMemZero(saddr, sizeof(*saddr));
1627 saddr->sin_family = AF_INET;
1628 saddr->sin_port = dstport.NotAnInteger;
1629 saddr->sin_len = sizeof(*saddr);
1630 saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1634 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss;
1635 mDNSPlatformMemZero(saddr6, sizeof(*saddr6));
1636 saddr6->sin6_family = AF_INET6;
1637 saddr6->sin6_port = dstport.NotAnInteger;
1638 saddr6->sin6_len = sizeof(*saddr6);
1639 saddr6->sin6_addr = *(struct in6_addr *)&dst->ip.v6;
1642 // Watch for connect complete (write is ready)
1643 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1644 if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
1646 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1650 // Watch for incoming data
1651 if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
1653 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1657 if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
1659 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
1660 return mStatus_UnknownErr;
1663 // We bind to the interface and all subsequent packets including the SYN will be sent out
1664 // on this interface
1666 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
1667 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
1668 if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
1670 NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(InterfaceID);
1671 if (dst->type == mDNSAddrType_IPv4)
1674 if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1675 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
1677 (void)InterfaceID; // Unused
1678 (void)info; // Unused
1683 #ifdef IPV6_BOUND_IF
1684 if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1685 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
1687 (void)InterfaceID; // Unused
1688 (void)info; // Unused
1693 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
1694 // from which we can infer the destination address family. Hence we need to remember that here.
1695 // Instead of remembering the address family, we remember the right fd.
1698 // initiate connection wth peer
1699 if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
1701 if (errno == EINPROGRESS) return mStatus_ConnPending;
1702 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
1703 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
1705 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
1706 return mStatus_ConnFailed;
1709 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1710 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1714 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1715 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
1717 mStatus err = mStatus_NoError;
1719 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
1720 if (!sock) return(mDNSNULL);
1722 mDNSPlatformMemZero(sock, sizeof(*sock));
1724 sock->flags = flags;
1726 if (flags & kTCPSocketFlags_UseTLS)
1728 #ifndef NO_SECURITYFRAMEWORK
1729 if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
1731 err = tlsSetupSock(sock, kSSLServerSide, kSSLStreamType);
1732 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
1734 err = SSLSetCertificate(sock->tlsContext, ServerCerts);
1735 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
1737 err = mStatus_UnsupportedErr;
1738 #endif /* NO_SECURITYFRAMEWORK */
1740 #ifndef NO_SECURITYFRAMEWORK
1744 if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
1748 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
1755 port = sock->ss.port.NotAnInteger;
1760 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
1762 if (ss->sktv4 != -1)
1764 mDNSPlatformCloseFD(&ss->kqsv4, ss->sktv4);
1767 if (ss->sktv6 != -1)
1769 mDNSPlatformCloseFD(&ss->kqsv6, ss->sktv6);
1772 if (ss->closeFlag) *ss->closeFlag = 1;
1775 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
1779 #ifndef NO_SECURITYFRAMEWORK
1780 if (sock->tlsContext)
1782 if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
1784 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
1785 // When we come back from SSLHandshake, we will notice that a close was here and
1786 // call this function again which will do the cleanup then.
1787 sock->handshake = handshake_to_be_closed;
1791 SSLClose(sock->tlsContext);
1792 CFRelease(sock->tlsContext);
1793 sock->tlsContext = NULL;
1795 #endif /* NO_SECURITYFRAMEWORK */
1796 if (sock->ss.sktv4 != -1)
1797 shutdown(sock->ss.sktv4, 2);
1798 if (sock->ss.sktv6 != -1)
1799 shutdown(sock->ss.sktv6, 2);
1800 CloseSocketSet(&sock->ss);
1803 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
1807 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
1810 *closed = mDNSfalse;
1812 if (sock->flags & kTCPSocketFlags_UseTLS)
1814 #ifndef NO_SECURITYFRAMEWORK
1815 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
1816 else if (sock->handshake == handshake_in_progress) return 0;
1817 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
1819 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
1820 mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t *)&nread);
1821 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
1822 if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
1823 else if (err && err != errSSLWouldBlock)
1824 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
1828 #endif /* NO_SECURITYFRAMEWORK */
1832 static int CLOSEDcount = 0;
1833 static int EAGAINcount = 0;
1834 nread = recv(sock->fd, buf, buflen, 0);
1840 } // On success, clear our error counters
1841 else if (nread == 0)
1844 if ((++CLOSEDcount % 1000) == 0)
1846 LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount);
1847 assert(CLOSEDcount < 1000);
1848 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
1849 // crash mDNSResponder using assert() and restart fresh. See advantages below:
1850 // 1.Better User Experience
1851 // 2.CrashLogs frequency can be monitored
1852 // 3.StackTrace can be used for more info
1855 // else nread is negative -- see what kind of error we got
1856 else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
1857 else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
1858 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
1861 if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
1868 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
1872 if (sock->flags & kTCPSocketFlags_UseTLS)
1874 #ifndef NO_SECURITYFRAMEWORK
1876 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
1877 if (sock->handshake == handshake_in_progress) return 0;
1878 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
1880 mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
1882 if (!err) nsent = (int) processed;
1883 else if (err == errSSLWouldBlock) nsent = 0;
1884 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
1887 #endif /* NO_SECURITYFRAMEWORK */
1891 nsent = send(sock->fd, msg, len, 0);
1894 if (errno == EAGAIN) nsent = 0;
1895 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
1902 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
1907 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1908 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1909 mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
1911 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
1912 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
1914 const int twofivefive = 255;
1915 mStatus err = mStatus_NoError;
1916 char *errstr = mDNSNULL;
1920 cp->closeFlag = mDNSNULL;
1922 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
1923 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
1925 // set default traffic class
1926 setTrafficClass(skt, mDNSfalse);
1928 #ifdef SO_RECV_ANYIF
1929 // Enable inbound packets on IFEF_AWDL interface.
1930 // Only done for multicast sockets, since we don't expect unicast socket operations
1931 // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
1932 if (mDNSSameIPPort(port, MulticastDNSPort))
1934 err = setsockopt(skt, SOL_SOCKET, SO_RECV_ANYIF, &on, sizeof(on));
1935 if (err < 0) { errstr = "setsockopt - SO_RECV_ANYIF"; goto fail; }
1937 #endif // SO_RECV_ANYIF
1939 // ... with a shared UDP port, if it's for multicast receiving
1940 if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort))
1942 err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
1943 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
1946 // Don't want to wake from sleep for inbound packets on the mDNS sockets
1947 if (mDNSSameIPPort(port, MulticastDNSPort))
1950 if (setsockopt(skt, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
1951 LogInfo("SetupSocket: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
1954 if (sa_family == AF_INET)
1956 // We want to receive destination addresses
1957 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
1958 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
1960 // We want to receive interface identifiers
1961 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
1962 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
1964 // We want to receive packet TTL value so we can check it
1965 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
1966 if (err < 0) { errstr = "setsockopt - IP_RECVTTL"; goto fail; }
1968 // Send unicast packets with TTL 255
1969 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
1970 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
1972 // And multicast packets with TTL 255 too
1973 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
1974 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
1976 // And start listening for packets
1977 struct sockaddr_in listening_sockaddr;
1978 listening_sockaddr.sin_family = AF_INET;
1979 listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
1980 listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0;
1981 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
1982 if (err) { errstr = "bind"; goto fail; }
1983 if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
1985 else if (sa_family == AF_INET6)
1987 // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
1988 if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; close(skt); return mStatus_NoError; }
1990 // We want to receive destination addresses and receive interface identifiers
1991 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
1992 if (err < 0) { errstr = "setsockopt - IPV6_RECVPKTINFO"; goto fail; }
1994 // We want to receive packet hop count value so we can check it
1995 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
1996 if (err < 0) { errstr = "setsockopt - IPV6_RECVHOPLIMIT"; goto fail; }
1998 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
1999 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
2000 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
2001 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
2003 // Send unicast packets with TTL 255
2004 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
2005 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
2007 // And multicast packets with TTL 255 too
2008 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
2009 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
2011 // Want to receive our own packets
2012 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
2013 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
2015 // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
2016 err = setsockopt(skt, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &mtu, sizeof(mtu));
2017 if (err < 0) // Since it is an optimization if we fail just log the err, no need to close the skt
2018 LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
2019 skt, err, errno, strerror(errno));
2021 // And start listening for packets
2022 struct sockaddr_in6 listening_sockaddr6;
2023 mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
2024 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
2025 listening_sockaddr6.sin6_family = AF_INET6;
2026 listening_sockaddr6.sin6_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
2027 listening_sockaddr6.sin6_flowinfo = 0;
2028 listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
2029 listening_sockaddr6.sin6_scope_id = 0;
2030 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
2031 if (err) { errstr = "bind"; goto fail; }
2032 if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
2035 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
2036 fcntl(skt, F_SETFD, 1); // set close-on-exec
2038 k->KQcallback = myKQSocketCallBack;
2040 k->KQtask = "UDP packet reception";
2041 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2042 k->readSource = mDNSNULL;
2043 k->writeSource = mDNSNULL;
2044 k->fdClosed = mDNSfalse;
2046 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
2048 return(mStatus_NoError);
2051 saved_errno = errno;
2052 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
2053 if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
2054 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, saved_errno, strerror(saved_errno));
2056 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
2057 if (!strcmp(errstr, "bind") && saved_errno == EADDRINUSE)
2060 if (mDNSSameIPPort(port, MulticastDNSPort))
2061 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
2062 "Congratulations, you've reproduced an elusive bug.\r"
2063 "Please contact the current assignee of <rdar://problem/3814904>.\r"
2064 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2065 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2068 mDNSPlatformCloseFD(k, skt);
2072 mDNSexport UDPSocket *mDNSPlatformUDPSocket(const mDNSIPPort requestedport)
2075 mDNSIPPort port = requestedport;
2076 mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
2077 int i = 10000; // Try at most 10000 times to get a unique random port
2078 UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
2079 if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
2080 mDNSPlatformMemZero(p, sizeof(UDPSocket));
2081 p->ss.port = zeroIPPort;
2082 p->ss.m = &mDNSStorage;
2085 p->ss.proxy = mDNSfalse;
2089 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
2090 if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
2091 err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
2094 err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
2095 if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
2098 } while (err == EADDRINUSE && randomizePort && i);
2102 // In customer builds we don't want to log failures with port 5351, because this is a known issue
2103 // of failing to bind to this port when Internet Sharing has already bound to it
2104 // We also don't want to log about port 5350, due to a known bug when some other
2105 // process is bound to it.
2106 if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
2107 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2108 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2109 freeL("UDPSocket", p);
2118 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
2120 CloseSocketSet(&sock->ss);
2121 freeL("UDPSocket", sock);
2125 mDNSexport mDNSBool mDNSPlatformUDPSocketEncounteredEOF(const UDPSocket *sock)
2127 return (sock->ss.sktv4EOF || sock->ss.sktv6EOF);
2130 #if COMPILER_LIKES_PRAGMA_MARK
2132 #pragma mark - BPF Raw packet sending/receiving
2135 #if APPLE_OSX_mDNSResponder
2137 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
2139 if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2140 NetworkInterfaceInfoOSX *info;
2142 info = IfindexToInterfaceInfoOSX(InterfaceID);
2145 LogMsg("mDNSPlatformSendRawPacket: Invalid interface index %p", InterfaceID);
2148 if (info->BPF_fd < 0)
2149 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
2152 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
2153 if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
2154 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
2158 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
2160 if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
2161 NetworkInterfaceInfoOSX *info;
2162 info = IfindexToInterfaceInfoOSX(InterfaceID);
2163 if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; }
2164 // Manually inject an entry into our local ARP cache.
2165 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
2166 if (!mDNS_AddressIsLocalSubnet(&mDNSStorage, InterfaceID, tpa))
2167 LogSPS("Don't need address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
2170 int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b);
2171 if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
2172 else LogSPS("Set local address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
2176 mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
2178 LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
2179 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2180 // close will happen in the cancel handler
2181 dispatch_source_cancel(i->BPF_source);
2184 // Note: MUST NOT close() the underlying native BSD sockets.
2185 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
2186 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
2187 CFRunLoopRemoveSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode);
2188 CFRelease(i->BPF_rls);
2189 CFSocketInvalidate(i->BPF_cfs);
2190 CFRelease(i->BPF_cfs);
2193 if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
2196 mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
2200 // Now we've got the lock, make sure the kqueue thread didn't close the fd out from under us (will not be a problem once the OS X
2201 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
2202 if (info->BPF_fd < 0) goto exit;
2204 ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
2205 const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
2206 const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
2207 debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
2211 /* <rdar://problem/10287386>
2212 * sometimes there can be a race condition btw when the bpf socket
2213 * gets data and the callback get scheduled and when we call BIOCSETF (which
2214 * clears the socket). this can cause the read to hang for a really long time
2215 * and effectively prevent us from responding to requests for long periods of time.
2216 * to prevent this make the socket non blocking and just bail if we dont get anything
2218 if (errno == EAGAIN)
2220 LogMsg("bpf_callback got EAGAIN bailing");
2223 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
2230 const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr;
2231 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
2232 info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen,
2233 ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
2234 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
2235 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
2236 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
2237 mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
2238 ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
2241 KQueueUnlock("bpf_callback");
2243 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2244 mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
2246 bpf_callback_common(info);
2249 mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
2255 bpf_callback_common((NetworkInterfaceInfoOSX *)context);
2259 mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
2261 LogMsg("mDNSPlatformSendKeepalive called\n");
2262 mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win);
2265 mDNSexport mStatus mDNSPlatformClearSPSData(void)
2267 CFStringRef spsAddressKey = NULL;
2268 CFStringRef ownerOPTRecKey = NULL;
2269 SCDynamicStoreRef addrStore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SPSAddresses"), NULL, NULL);
2270 SCDynamicStoreRef optStore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SPSOPTRecord"), NULL, NULL);
2272 spsAddressKey = SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyAddress"));
2273 if (spsAddressKey != NULL)
2275 CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, spsAddressKey);
2276 if (keyList != NULL)
2278 if (SCDynamicStoreSetMultiple(addrStore, NULL, keyList, NULL) == false)
2279 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr( spsAddressKey, kCFStringEncodingASCII), SCErrorString(SCError()));
2281 if (keyList) CFRelease(keyList);
2283 ownerOPTRecKey= SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyOPTRecord"));
2284 if(ownerOPTRecKey != NULL)
2286 CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, ownerOPTRecKey);
2287 if (keyList != NULL)
2289 if (SCDynamicStoreSetMultiple(optStore, NULL, keyList, NULL) == false)
2290 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr(ownerOPTRecKey, kCFStringEncodingASCII), SCErrorString(SCError()));
2292 if (keyList) CFRelease(keyList);
2295 if (addrStore) CFRelease(addrStore);
2296 if (optStore) CFRelease(optStore);
2297 if (spsAddressKey) CFRelease(spsAddressKey);
2298 if (ownerOPTRecKey) CFRelease(ownerOPTRecKey);
2299 return KERN_SUCCESS;
2302 mDNSlocal int getMACAddress(int family, v6addr_t raddr, v6addr_t gaddr, int *gfamily, ethaddr_t eth)
2306 struct rt_msghdr m_rtm;
2310 struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
2311 char *cp = m_rtmsg.m_space;
2312 int seq = 6367, sock, rlen, i;
2313 struct sockaddr_in *sin = NULL;
2314 struct sockaddr_in6 *sin6 = NULL;
2315 struct sockaddr_dl *sdl = NULL;
2316 struct sockaddr_storage sins;
2317 struct sockaddr_dl sdl_m;
2319 #define NEXTADDR(w, s, len) \
2320 if (rtm->rtm_addrs & (w)) \
2322 bcopy((char *)s, cp, len); \
2326 bzero(&sins, sizeof(struct sockaddr_storage));
2327 bzero(&sdl_m, sizeof(struct sockaddr_dl));
2328 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
2330 sock = socket(PF_ROUTE, SOCK_RAW, 0);
2333 const int socket_errno = errno;
2334 LogMsg("getMACAddress: Can not open the socket - %s", strerror(socket_errno));
2335 return socket_errno;
2338 rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY;
2339 rtm->rtm_type = RTM_GET;
2341 rtm->rtm_version = RTM_VERSION;
2342 rtm->rtm_seq = ++seq;
2344 sdl_m.sdl_len = sizeof(sdl_m);
2345 sdl_m.sdl_family = AF_LINK;
2346 if (family == AF_INET)
2348 sin = (struct sockaddr_in*)&sins;
2349 sin->sin_family = AF_INET;
2350 sin->sin_len = sizeof(struct sockaddr_in);
2351 memcpy(&sin->sin_addr, raddr, sizeof(struct in_addr));
2352 NEXTADDR(RTA_DST, sin, sin->sin_len);
2354 else if (family == AF_INET6)
2356 sin6 = (struct sockaddr_in6 *)&sins;
2357 sin6->sin6_len = sizeof(struct sockaddr_in6);
2358 sin6->sin6_family = AF_INET6;
2359 memcpy(&sin6->sin6_addr, raddr, sizeof(struct in6_addr));
2360 NEXTADDR(RTA_DST, sin6, sin6->sin6_len);
2362 NEXTADDR(RTA_GATEWAY, &sdl_m, sdl_m.sdl_len);
2363 rtm->rtm_msglen = rlen = cp - (char *)&m_rtmsg;
2365 if (write(sock, (char *)&m_rtmsg, rlen) < 0)
2367 const int write_errno = errno;
2368 LogMsg("getMACAddress: writing to routing socket: %s", strerror(write_errno));
2375 rlen = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
2377 while (rlen > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid()));
2380 LogMsg("getMACAddress: Read from routing socket failed");
2382 if (family == AF_INET)
2384 sin = (struct sockaddr_in *) (rtm + 1);
2385 sdl = (struct sockaddr_dl *) (sin->sin_len + (char *) sin);
2387 else if (family == AF_INET6)
2389 sin6 = (struct sockaddr_in6 *) (rtm +1);
2390 sdl = (struct sockaddr_dl *) (sin6->sin6_len + (char *) sin6);
2395 LogMsg("getMACAddress: sdl is NULL for family %d", family);
2400 // If the address is not on the local net, we get the IP address of the gateway.
2401 // We would have to repeat the process to get the MAC address of the gateway
2402 *gfamily = sdl->sdl_family;
2403 if (sdl->sdl_family == AF_INET)
2407 struct sockaddr_in *new_sin = (struct sockaddr_in *)(sin->sin_len +(char*) sin);
2408 memcpy(gaddr, &new_sin->sin_addr, sizeof(struct in_addr));
2412 LogMsg("getMACAddress: sin is NULL");
2417 else if (sdl->sdl_family == AF_INET6)
2421 struct sockaddr_in6 *new_sin6 = (struct sockaddr_in6 *)(sin6->sin6_len +(char*) sin6);
2422 memcpy(gaddr, &new_sin6->sin6_addr, sizeof(struct in6_addr));
2426 LogMsg("getMACAddress: sin6 is NULL");
2432 unsigned char *ptr = (unsigned char *)LLADDR(sdl);
2433 for (i = 0; i < ETHER_ADDR_LEN; i++)
2434 (eth)[i] = *(ptr +i);
2438 return KERN_SUCCESS;
2441 mDNSlocal int GetRemoteMacinternal(int family, v6addr_t raddr, ethaddr_t eth)
2450 ret = getMACAddress(family, raddr, gateway, &gfamily, eth);
2453 memcpy(raddr, gateway, sizeof(family));
2458 while ((ret == -1) && (count < 5));
2462 mDNSlocal int StoreSPSMACAddressinternal(int family, v6addr_t spsaddr, const char *ifname)
2465 char spsip[INET6_ADDRSTRLEN];
2467 CFStringRef sckey = NULL;
2468 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL, NULL);
2469 SCDynamicStoreRef ipstore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL, NULL);
2470 CFMutableDictionaryRef dict = NULL;
2471 CFStringRef entityname = NULL;
2472 CFDictionaryRef ipdict = NULL;
2473 CFArrayRef addrs = NULL;
2475 if ((store == NULL) || (ipstore == NULL))
2477 LogMsg("StoreSPSMACAddressinternal: Unable to accesss SC Dynamic Store");
2482 // Get the MAC address of the Sleep Proxy Server
2483 memset(eth, 0, sizeof(eth));
2484 ret = GetRemoteMacinternal(family, spsaddr, eth);
2487 LogMsg("StoreSPSMACAddressinternal: Failed to determine the MAC address");
2491 // Create/Update the dynamic store entry for the specified interface
2492 sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyAddress");
2493 dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2496 LogMsg("StoreSPSMACAddressinternal: SPSCreateDict() Could not create CFDictionary dict");
2501 CFStringRef macaddr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
2502 CFDictionarySetValue(dict, CFSTR("MACAddress"), macaddr);
2503 if (NULL != macaddr)
2506 if( NULL == inet_ntop(family, (void *)spsaddr, spsip, sizeof(spsip)))
2508 LogMsg("StoreSPSMACAddressinternal: inet_ntop failed: %s", strerror(errno));
2513 CFStringRef ipaddr = CFStringCreateWithCString(NULL, spsip, kCFStringEncodingUTF8);
2514 CFDictionarySetValue(dict, CFSTR("IPAddress"), ipaddr);
2518 // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup
2519 if ((entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/IPv6"), ifname)) != NULL)
2521 if ((ipdict = SCDynamicStoreCopyValue(ipstore, entityname)) != NULL)
2523 if((addrs = CFDictionaryGetValue(ipdict, CFSTR("Addresses"))) != NULL)
2525 addrs = CFRetain(addrs);
2526 CFDictionarySetValue(dict, CFSTR("RegisteredAddresses"), addrs);
2530 SCDynamicStoreSetValue(store, sckey, dict);
2533 if (store) CFRelease(store);
2534 if (ipstore) CFRelease(ipstore);
2535 if (sckey) CFRelease(sckey);
2536 if (dict) CFRelease(dict);
2537 if (ipdict) CFRelease(ipdict);
2538 if (entityname) CFRelease(entityname);
2539 if (addrs) CFRelease(addrs);
2544 mDNSlocal void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname)
2552 mDNSPlatformMemCopy(addr.saddr, spsaddr, sizeof(v6addr_t));
2554 err = StoreSPSMACAddressinternal(family, (uint8_t *)addr.saddr, ifname);
2556 LogMsg("mDNSStoreSPSMACAddress : failed");
2559 mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
2561 int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2563 LogInfo("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname);
2564 mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname);
2566 return KERN_SUCCESS;
2570 mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage* msg, int length)
2573 CFStringRef sckey = NULL;
2574 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreOwnerOPTRecord"), NULL, NULL);
2575 CFMutableDictionaryRef dict = NULL;
2579 LogMsg("mDNSPlatformStoreOwnerOptRecord: Unable to accesss SC Dynamic Store");
2584 // Create/Update the dynamic store entry for the specified interface
2585 sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyOPTRecord");
2586 dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2589 LogMsg("mDNSPlatformStoreOwnerOptRecord: Could not create CFDictionary dictionary to store OPT Record");
2594 CFDataRef optRec = NULL;
2595 optRec = CFDataCreate(NULL, (const uint8_t *)msg, (CFIndex)length);
2596 CFDictionarySetValue(dict, CFSTR("OwnerOPTRecord"), optRec);
2597 if (NULL != optRec) CFRelease(optRec);
2599 SCDynamicStoreSetValue(store, sckey, dict);
2602 if (NULL != store) CFRelease(store);
2603 if (NULL != sckey) CFRelease(sckey);
2604 if (NULL != dict) CFRelease(dict);
2608 mDNSlocal void mDNSGet_RemoteMAC(int family, v6addr_t raddr)
2611 IPAddressMACMapping *addrMapping;
2612 int kr = KERN_FAILURE;
2618 bzero(eth, sizeof(ethaddr_t));
2619 mDNSPlatformMemCopy(dst.addr, raddr, sizeof(v6addr_t));
2621 kr = GetRemoteMacinternal(family, (uint8_t *)dst.addr, eth);
2623 // If the call to get the remote MAC address succeeds, allocate and copy
2624 // the values and schedule a task to update the MAC address in the TCP Keepalive record.
2627 addrMapping = mDNSPlatformMemAllocate(sizeof(IPAddressMACMapping));
2628 snprintf(addrMapping->ethaddr, sizeof(addrMapping->ethaddr), "%02x:%02x:%02x:%02x:%02x:%02x",
2629 eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
2630 if (family == AF_INET)
2632 addrMapping->ipaddr.type = mDNSAddrType_IPv4;
2633 mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, raddr, sizeof(v6addr_t));
2637 addrMapping->ipaddr.type = mDNSAddrType_IPv6;
2638 mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v6.b, raddr, sizeof(v6addr_t));
2640 UpdateRMAC(&mDNSStorage, addrMapping);
2644 mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr)
2646 int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2648 LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC");
2649 mDNSGet_RemoteMAC(family, raddr->ip.v6.b);
2651 return KERN_SUCCESS;
2654 mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
2658 int family = (laddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2660 error = mDNSRetrieveTCPInfo(family, laddr->ip.v6.b, lport->NotAnInteger, raddr->ip.v6.b, rport->NotAnInteger, (uint32_t *)&(mti->seq), (uint32_t *)&(mti->ack), (uint16_t *)&(mti->window), (int32_t*)&intfid);
2661 if (error != KERN_SUCCESS)
2663 LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error);
2666 mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, intfid);
2670 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2672 mDNSlocal int CountProxyTargets(NetworkInterfaceInfoOSX *x, int *p4, int *p6)
2674 int numv4 = 0, numv6 = 0;
2677 for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
2678 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2680 if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
2684 for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
2685 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2687 if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
2691 if (p4) *p4 = numv4;
2692 if (p6) *p6 = numv6;
2693 return(numv4 + numv6);
2696 mDNSexport void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)
2698 mDNS *const m = &mDNSStorage;
2699 NetworkInterfaceInfoOSX *x;
2701 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
2702 for (x = m->p->InterfaceList; x; x = x->next) if ((x->ifinfo.InterfaceID == InterfaceID) && (x->BPF_fd >= 0)) break;
2704 if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
2706 #define MAX_BPF_ADDRS 250
2707 int numv4 = 0, numv6 = 0;
2709 if (CountProxyTargets(x, &numv4, &numv6) > MAX_BPF_ADDRS)
2711 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
2712 if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
2713 numv6 = MAX_BPF_ADDRS - numv4;
2716 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
2718 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
2719 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
2720 static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
2722 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13)
2724 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
2725 BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP
2727 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
2729 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
2730 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
2731 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
2732 BPF_STMT(BPF_RET + BPF_K, 86), // 7 Return 86-byte ND
2734 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
2735 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
2738 // Special filter program to use when there are no address proxy records
2739 static struct bpf_insn nullfilter[] =
2741 BPF_STMT(BPF_RET | BPF_K, 0) // 0 Match no packets and return size 0
2744 struct bpf_program prog;
2745 if (!numv4 && !numv6)
2747 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
2748 if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
2750 // Cancel any previous ND group memberships we had
2751 if (x->BPF_mcfd >= 0)
2757 // Schedule check to see if we can close this BPF_fd now
2758 if (!m->NetworkChanged) m->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
2759 if (x->BPF_fd < 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
2761 prog.bf_insns = nullfilter;
2765 struct bpf_insn *pc = &filter[9];
2766 struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0"
2767 struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks
2768 struct bpf_insn *ret4 = fail + 1;
2769 struct bpf_insn *ret6 = ret4 + 4;
2771 static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing
2773 static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
2775 static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20)
2776 static const struct bpf_insn r4b = BPF_STMT(BPF_LD + BPF_IMM, 54); // A = 54 (14-byte Ethernet plus 20-byte TCP + 20 bytes spare)
2777 static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length
2778 static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
2780 static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
2782 BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail
2783 BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check
2785 // BPF Byte-Order Note
2786 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
2787 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
2788 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
2789 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
2790 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
2791 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
2792 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
2793 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
2794 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
2795 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
2797 // IPSEC capture size notes:
2798 // 8 bytes UDP header
2799 // 4 bytes Non-ESP Marker
2800 // 28 bytes IKE Header
2802 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
2805 for (rr = m->ResourceRecords; rr; rr=rr->next)
2806 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2808 mDNSv4Addr a = rr->AddressProxy.ip.v4;
2809 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2810 BPF_SetOffset(pc, jt, ret4);
2812 pc->k = (bpf_u_int32)a.b[0] << 24 | (bpf_u_int32)a.b[1] << 16 | (bpf_u_int32)a.b[2] << 8 | (bpf_u_int32)a.b[3];
2817 if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
2818 *pc++ = g6; // chk6 points here
2820 // First cancel any previous ND group memberships we had, then create a fresh socket
2821 if (x->BPF_mcfd >= 0) close(x->BPF_mcfd);
2822 x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0);
2824 for (rr = m->ResourceRecords; rr; rr=rr->next)
2825 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2827 const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
2828 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2829 BPF_SetOffset(pc, jt, ret6);
2831 pc->k = (bpf_u_int32)a->b[0x0C] << 24 | (bpf_u_int32)a->b[0x0D] << 16 | (bpf_u_int32)a->b[0x0E] << 8 | (bpf_u_int32)a->b[0x0F];
2834 struct ipv6_mreq i6mr;
2835 i6mr.ipv6mr_interface = x->scope_id;
2836 i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix;
2837 i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD];
2838 i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE];
2839 i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF];
2841 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
2842 mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
2843 if (err < 0 && (errno != EADDRNOTAVAIL))
2844 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2846 err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
2847 if (err < 0 && (errno != EADDRINUSE)) // Joining same group twice can give "Address already in use" error -- no need to report that
2848 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2850 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
2853 if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
2854 *pc++ = rf; // fail points here
2856 if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
2857 *pc++ = r4a; // ret4 points here
2862 if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
2863 *pc++ = r6a; // ret6 points here
2865 // For debugging BPF filter program
2867 for (q=0; q<prog.bf_len; q++)
2868 LogSPS("mDNSPlatformUpdateProxyList: %2d { 0x%02x, %d, %d, 0x%08x },", q, prog.bf_insns[q].code, prog.bf_insns[q].jt, prog.bf_insns[q].jf, prog.bf_insns[q].k);
2870 prog.bf_len = (u_int)(pc - filter);
2871 prog.bf_insns = filter;
2874 if (ioctl(x->BPF_fd, BIOCSETFNR, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
2875 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog.bf_len);
2878 mDNSexport void mDNSPlatformReceiveBPF_fd(int fd)
2880 mDNS *const m = &mDNSStorage;
2883 NetworkInterfaceInfoOSX *i;
2884 for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
2885 if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
2888 LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd);
2890 struct bpf_version v;
2891 if (ioctl(fd, BIOCVERSION, &v) < 0)
2892 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2893 else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
2894 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
2895 fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
2897 if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
2898 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2900 if (i->BPF_len > sizeof(m->imsg))
2902 i->BPF_len = sizeof(m->imsg);
2903 if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
2904 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2906 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd, i->ifinfo.ifname, i->BPF_len);
2909 static const u_int opt_one = 1;
2910 if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0)
2911 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2913 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
2914 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2916 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
2917 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2919 /* <rdar://problem/10287386>
2920 * make socket non blocking see comments in bpf_callback_common for more info
2922 if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
2924 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2928 mDNSPlatformMemZero(&ifr, sizeof(ifr));
2929 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
2930 if (ioctl(fd, BIOCSETIF, &ifr) < 0)
2931 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
2934 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2936 i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());
2937 if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
2938 dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);});
2939 dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);});
2940 dispatch_resume(i->BPF_source);
2942 CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
2944 i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
2945 i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
2946 CFRunLoopAddSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode);
2948 mDNSPlatformUpdateProxyList(i->ifinfo.InterfaceID);
2955 #endif // APPLE_OSX_mDNSResponder
2957 #if COMPILER_LIKES_PRAGMA_MARK
2959 #pragma mark - Key Management
2962 #ifndef NO_SECURITYFRAMEWORK
2963 mDNSlocal CFArrayRef CopyCertChain(SecIdentityRef identity)
2965 CFMutableArrayRef certChain = NULL;
2966 if (!identity) { LogMsg("CopyCertChain: identity is NULL"); return(NULL); }
2967 SecCertificateRef cert;
2968 OSStatus err = SecIdentityCopyCertificate(identity, &cert);
2969 if (err || !cert) LogMsg("CopyCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
2972 #pragma clang diagnostic push
2973 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2974 SecPolicySearchRef searchRef;
2975 err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
2976 if (err || !searchRef) LogMsg("CopyCertChain: SecPolicySearchCreate() returned %d", (int) err);
2979 SecPolicyRef policy;
2980 err = SecPolicySearchCopyNext(searchRef, &policy);
2981 if (err || !policy) LogMsg("CopyCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
2984 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
2985 if (!wrappedCert) LogMsg("CopyCertChain: wrappedCert is NULL");
2989 err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
2990 if (err || !trust) LogMsg("CopyCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
2993 err = SecTrustEvaluate(trust, NULL);
2994 if (err) LogMsg("CopyCertChain: SecTrustEvaluate() returned %d", (int) err);
2997 CFArrayRef rawCertChain;
2998 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
2999 err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
3000 if (err || !rawCertChain || !statusChain) LogMsg("CopyCertChain: SecTrustGetResult() returned %d", (int) err);
3003 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
3004 if (!certChain) LogMsg("CopyCertChain: certChain is NULL");
3007 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
3008 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
3009 CFArraySetValueAtIndex(certChain, 0, identity);
3010 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
3011 if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
3013 CFRelease(rawCertChain);
3014 // Do not free statusChain:
3015 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
3016 // certChain: Call the CFRelease function to release this object when you are finished with it.
3017 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
3022 CFRelease(wrappedCert);
3026 CFRelease(searchRef);
3028 #pragma clang diagnostic pop
3033 #endif /* NO_SECURITYFRAMEWORK */
3035 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
3037 #ifdef NO_SECURITYFRAMEWORK
3038 return mStatus_UnsupportedErr;
3040 SecIdentityRef identity = nil;
3041 SecIdentitySearchRef srchRef = nil;
3044 #pragma clang diagnostic push
3045 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3046 // search for "any" identity matching specified key use
3047 // In this app, we expect there to be exactly one
3048 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
3049 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
3051 err = SecIdentitySearchCopyNext(srchRef, &identity);
3052 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
3053 #pragma clang diagnostic pop
3055 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
3056 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
3058 // Found one. Call CopyCertChain to create the correct certificate chain.
3059 ServerCerts = CopyCertChain(identity);
3060 if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: CopyCertChain error"); return mStatus_UnknownErr; }
3062 return mStatus_NoError;
3063 #endif /* NO_SECURITYFRAMEWORK */
3066 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
3068 #ifndef NO_SECURITYFRAMEWORK
3069 if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
3070 #endif /* NO_SECURITYFRAMEWORK */
3073 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
3074 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
3076 CFStringEncoding encoding = kCFStringEncodingUTF8;
3077 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
3080 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3085 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
3086 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
3088 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
3091 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3096 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
3099 CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
3100 if (!state) return mDNSfalse;
3101 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
3102 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
3103 return val ? mDNStrue : mDNSfalse;
3106 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
3108 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
3110 if (sa->sa_family == AF_INET)
3112 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
3113 ip->type = mDNSAddrType_IPv4;
3114 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
3115 return(mStatus_NoError);
3118 if (sa->sa_family == AF_INET6)
3120 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
3121 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
3122 // value into the second word of the IPv6 link-local address, so they can just
3123 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
3124 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
3125 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
3126 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
3127 ip->type = mDNSAddrType_IPv6;
3128 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
3129 return(mStatus_NoError);
3132 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
3133 return(mStatus_Invalid);
3136 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
3138 mDNSEthAddr eth = zeroEthAddr;
3140 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
3143 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, entityname);
3146 CFRange range = { 0, 6 }; // Offset, length
3147 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
3148 if (data && CFDataGetLength(data) == 6)
3149 CFDataGetBytes(data, range, eth.b);
3152 CFRelease(entityname);
3158 mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
3160 struct ifaddrs *ifa;
3161 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
3162 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
3164 const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
3165 if (sdl->sdl_index == ifindex)
3166 { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
3172 #ifndef SIOCGIFWAKEFLAGS
3173 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
3176 #ifndef IF_WAKE_ON_MAGIC_PACKET
3177 #define IF_WAKE_ON_MAGIC_PACKET 0x01
3180 #ifndef ifr_wake_flags
3181 #define ifr_wake_flags ifr_ifru.ifru_intval
3184 mDNSlocal mDNSBool CheckInterfaceSupport(NetworkInterfaceInfo *const intf, const char *key)
3186 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
3189 LogSPS("CheckInterfaceSupport: No service for interface %s", intf->ifname);
3194 IOObjectGetClass(service, n1);
3195 io_object_t parent = IO_OBJECT_NULL;
3196 mDNSBool ret = mDNSfalse;
3198 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
3199 if (kr == KERN_SUCCESS)
3201 CFStringRef keystr = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
3202 IOObjectGetClass(parent, n2);
3203 LogSPS("CheckInterfaceSupport: Interface %s service %s parent %s", intf->ifname, n1, n2);
3204 CFTypeRef ref = mDNSNULL;
3206 // Currently, the key can be in a different part of the IOKit hierarchy on the AppleTV.
3207 // TODO: revist if it is ok to have the same call for all platforms.
3209 ref = IORegistryEntrySearchCFProperty(parent, kIOServicePlane, keystr, kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively);
3211 ref = IORegistryEntryCreateCFProperty(parent, keystr, kCFAllocatorDefault, mDNSNULL);
3215 LogSPS("CheckInterfaceSupport: No %s for interface %s/%s/%s", key, intf->ifname, n1, n2);
3223 IOObjectRelease(parent);
3228 LogSPS("CheckInterfaceSupport: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
3232 IOObjectRelease(service);
3237 mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
3239 return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
3242 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
3244 // We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D.
3245 if (!MulticastInterface(i) || (i->ifa_flags & IFF_LOOPBACK) || i->D2DInterface)
3247 LogSPS("NetWakeInterface: returning false for %s", i->ifinfo.ifname);
3251 // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
3252 // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
3253 // when the power source is not AC Power.
3254 if (InterfaceSupportsKeepAlive(&i->ifinfo))
3256 LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i->ifinfo.ifname);
3260 int s = socket(AF_INET, SOCK_DGRAM, 0);
3261 if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); }
3264 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3265 if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
3267 const int ioctl_errno = errno;
3268 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
3269 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
3270 // error code is being returned from the kernel, we need to use the kernel version.
3271 #define KERNEL_EOPNOTSUPP 102
3272 if (ioctl_errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
3273 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, ioctl_errno, strerror(ioctl_errno));
3274 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
3275 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
3276 ifr.ifr_wake_flags = (ioctl_errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
3281 // ifr.ifr_wake_flags = IF_WAKE_ON_MAGIC_PACKET; // For testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
3283 LogSPS("NetWakeInterface: %-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
3285 return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
3288 mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
3293 sockFD = socket(AF_INET, SOCK_DGRAM, 0);
3296 LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno, strerror(errno));
3300 ifr.ifr_addr.sa_family = AF_INET;
3301 strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
3303 if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
3305 LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno));
3310 return ifr.ifr_eflags;
3313 #if TARGET_OS_IPHONE
3315 // Function pointers for the routines we use in the MobileWiFi framework.
3316 static WiFiManagerClientRef (*WiFiManagerClientCreate_p)(CFAllocatorRef allocator, WiFiClientType type) = mDNSNULL;
3317 static CFArrayRef (*WiFiManagerClientCopyDevices_p)(WiFiManagerClientRef manager) = mDNSNULL;
3318 static WiFiNetworkRef (*WiFiDeviceClientCopyCurrentNetwork_p)(WiFiDeviceClientRef device) = mDNSNULL;
3319 static bool (*WiFiNetworkIsCarPlay_p)(WiFiNetworkRef network) = mDNSNULL;
3321 mDNSlocal mDNSBool MobileWiFiLibLoad(void)
3323 static mDNSBool isInitialized = mDNSfalse;
3324 static void *MobileWiFiLib_p = mDNSNULL;
3325 static const char path[] = "/System/Library/PrivateFrameworks/MobileWiFi.framework/MobileWiFi";
3329 if (!MobileWiFiLib_p)
3331 MobileWiFiLib_p = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
3332 if (!MobileWiFiLib_p)
3334 LogInfo("MobileWiFiLibLoad: dlopen() failed.");
3339 if (!WiFiManagerClientCreate_p)
3341 WiFiManagerClientCreate_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCreate");
3342 if (!WiFiManagerClientCreate_p)
3344 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCreate symbol failed.");
3349 if (!WiFiManagerClientCopyDevices_p)
3351 WiFiManagerClientCopyDevices_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCopyDevices");
3352 if (!WiFiManagerClientCopyDevices_p)
3354 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCopyDevices symbol failed.");
3359 if (!WiFiDeviceClientCopyCurrentNetwork_p)
3361 WiFiDeviceClientCopyCurrentNetwork_p = dlsym(MobileWiFiLib_p, "WiFiDeviceClientCopyCurrentNetwork");
3362 if (!WiFiDeviceClientCopyCurrentNetwork_p)
3364 LogInfo("MobileWiFiLibLoad: load of WiFiDeviceClientCopyCurrentNetwork symbol failed.");
3369 if (!WiFiNetworkIsCarPlay_p)
3371 WiFiNetworkIsCarPlay_p = dlsym(MobileWiFiLib_p, "WiFiNetworkIsCarPlay");
3372 if (!WiFiNetworkIsCarPlay_p)
3374 LogInfo("MobileWiFiLibLoad: load of WiFiNetworkIsCarPlay symbol failed.");
3379 isInitialized = mDNStrue;
3383 return isInitialized;
3386 #define CARPLAY_DEBUG 0
3388 // Return true if the interface is associate to a CarPlay hosted SSID.
3389 // If we have associated with a CarPlay hosted SSID, then use the same
3390 // optimizations that are used when an interface has the IFEF_DIRECTLINK flag set.
3391 mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
3393 static WiFiManagerClientRef manager = NULL;
3395 WiFiDeviceClientRef device;
3396 WiFiNetworkRef network;
3397 mDNSBool rvalue = mDNSfalse;
3399 if (!MobileWiFiLibLoad())
3401 LogInfo("IsCarPlaySSID: MobileWiFiLibLoad() failed!");
3405 // Cache the WiFiManagerClientRef.
3406 if (manager == NULL)
3407 manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
3409 if (manager == NULL)
3411 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3415 devices = WiFiManagerClientCopyDevices_p(manager);
3417 // If the first call fails, update the cached WiFiManagerClientRef pointer and try again.
3418 if (devices == NULL)
3420 LogInfo("IsCarPlaySSID: First call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
3422 // Release the previously cached WiFiManagerClientRef which is apparently now stale.
3424 manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
3425 if (manager == NULL)
3427 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3430 devices = WiFiManagerClientCopyDevices_p(manager);
3431 if (devices == NULL)
3433 LogInfo("IsCarPlaySSID: Second call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
3438 device = (WiFiDeviceClientRef)CFArrayGetValueAtIndex(devices, 0);
3439 network = WiFiDeviceClientCopyCurrentNetwork_p(device);
3440 if (network != NULL)
3442 if (WiFiNetworkIsCarPlay_p(network))
3444 LogInfo("IsCarPlaySSID: %s is CarPlay hosted", ifa_name);
3449 LogInfo("IsCarPlaySSID: %s is NOT CarPlay hosted", ifa_name);
3450 #endif // CARPLAY_DEBUG
3455 LogInfo("IsCarPlaySSID: WiFiDeviceClientCopyCurrentNetwork() returned NULL for %s", ifa_name);
3462 #else // TARGET_OS_IPHONE
3464 mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
3466 (void)ifa_name; // unused
3468 // OSX WifiManager currently does not implement WiFiNetworkIsCarPlay()
3472 #endif // TARGET_OS_IPHONE
3474 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
3475 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
3476 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
3477 // (e.g. sa_family not AF_INET or AF_INET6)
3478 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(struct ifaddrs *ifa, mDNSs32 utc)
3480 mDNS *const m = &mDNSStorage;
3481 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
3482 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
3483 u_int64_t eflags = getExtendedFlags(ifa->ifa_name);
3486 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
3487 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
3489 NetworkInterfaceInfoOSX **p;
3490 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
3491 if (scope_id == (*p)->scope_id &&
3492 mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
3493 mDNSSameEthAddress(&bssid, &(*p)->BSSID))
3495 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p, ifname before %s, after %s", scope_id, &bssid, &ip, *p, (*p)->ifinfo.ifname, ifa->ifa_name);
3496 // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
3497 // When interfaces are created with same MAC address, kernel resurrects the old interface.
3498 // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
3499 // we get the corresponding name for the interface index on which the packet was received and check against
3500 // the InterfaceList for a matching name. So, keep the name in sync
3501 strlcpy((*p)->ifinfo.ifname, ifa->ifa_name, sizeof((*p)->ifinfo.ifname));
3502 (*p)->Exists = mDNStrue;
3503 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
3504 if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
3506 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
3507 // we may need to start or stop or sleep proxy browse operation
3508 const mDNSBool NetWake = NetWakeInterface(*p);
3509 if ((*p)->ifinfo.NetWake != NetWake)
3511 (*p)->ifinfo.NetWake = NetWake;
3512 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
3513 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
3514 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
3515 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
3516 if ((*p)->Registered)
3519 if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo);
3520 else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
3524 // Reset the flag if it has changed this time.
3525 (*p)->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
3530 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
3531 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
3532 if (!i) return(mDNSNULL);
3533 mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
3534 i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
3536 i->ifinfo.mask = mask;
3537 strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
3538 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
3539 // We can be configured to disable multicast advertisement, but we want to to support
3540 // local-only services, which need a loopback address record.
3541 i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
3542 i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
3543 i->ifinfo.Loopback = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse;
3544 i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
3546 // Setting DirectLink indicates we can do the optimization of skipping the probe phase
3547 // for the interface address records since they should be unique.
3548 // Unfortunately, the legacy p2p* interfaces do not set the IFEF_LOCALNET_PRIVATE
3549 // or IFEF_DIRECTLINK flags, so we have to match against the name.
3550 if ((eflags & (IFEF_DIRECTLINK | IFEF_AWDL)) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0))
3551 i->ifinfo.DirectLink = mDNStrue;
3553 i->ifinfo.DirectLink = IsCarPlaySSID(ifa->ifa_name);
3555 if (i->ifinfo.DirectLink)
3556 LogInfo("AddInterfaceToList: DirectLink set for %s", ifa->ifa_name);
3560 i->Exists = mDNStrue;
3561 i->Flashing = mDNSfalse;
3562 i->Occulting = mDNSfalse;
3564 i->D2DInterface = ((eflags & IFEF_LOCALNET_PRIVATE) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0)) ? mDNStrue: mDNSfalse;
3565 if (i->D2DInterface)
3566 LogInfo("AddInterfaceToList: D2DInterface set for %s", ifa->ifa_name);
3568 i->isExpensive = (eflags & IFEF_EXPENSIVE) ? mDNStrue: mDNSfalse;
3569 if (eflags & IFEF_AWDL)
3571 // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
3572 // limited AWDL resources so we don't set the kDNSQClass_UnicastResponse bit in
3573 // Bonjour requests over the AWDL interface.
3574 i->ifinfo.SupportsUnicastMDNSResponse = mDNSfalse;
3575 AWDLInterfaceID = i->ifinfo.InterfaceID;
3576 LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
3580 i->ifinfo.SupportsUnicastMDNSResponse = mDNStrue;
3582 i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
3584 i->ifa_flags = ifa->ifa_flags;
3585 i->scope_id = scope_id;
3587 i->sa_family = ifa->ifa_addr->sa_family;
3591 i->Registered = mDNSNULL;
3593 // Do this AFTER i->BSSID has been set up
3594 i->ifinfo.NetWake = (eflags & IFEF_EXPENSIVE)? mDNSfalse : NetWakeInterface(i);
3595 GetMAC(&i->ifinfo.MAC, scope_id);
3596 if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
3597 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
3603 #if APPLE_OSX_mDNSResponder
3605 #if COMPILER_LIKES_PRAGMA_MARK
3607 #pragma mark - AutoTunnel
3610 #define kRacoonPort 4500
3612 static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
3614 #ifndef NO_SECURITYFRAMEWORK
3616 static CFMutableDictionaryRef domainStatusDict = NULL;
3618 mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
3622 if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
3623 return mStatus_NoSuchRecord;
3624 else if (q->state == LLQ_Poll)
3625 return mStatus_PollingMode;
3626 else if (q->state != LLQ_Established && !q->DuplicateOf)
3627 return mStatus_TransientErr;
3630 return mStatus_NoError;
3633 mDNSlocal mStatus UpdateLLQStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
3635 mStatus status = mStatus_NoError;
3636 DNSQuestion* q, *worst_q = mDNSNULL;
3637 for (q = mDNSStorage.Questions; q; q=q->next)
3638 if (q->AuthInfo == info)
3640 mStatus newStatus = CheckQuestionForStatus(q);
3641 if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
3642 else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; }
3643 else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
3646 if (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success");
3647 else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
3648 else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
3649 else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
3653 mDNSlocal mStatus UpdateRRStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
3657 if (info->deltime) return mStatus_NoError;
3658 for (r = mDNSStorage.ResourceRecords; r; r = r->next)
3660 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
3661 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
3662 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
3663 // has already checked
3664 const domainname *n = r->resrec.name;
3667 DomainAuthInfo *ptr;
3668 for (ptr = mDNSStorage.AuthInfoList; ptr; ptr = ptr->next)
3669 if (SameDomainName(&ptr->domain, n))
3671 if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime))
3673 mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
3674 return r->updateError;
3677 n = (const domainname *)(n->c + 1 + n->c[0]);
3680 return mStatus_NoError;
3683 #endif // ndef NO_SECURITYFRAMEWORK
3685 // MUST be called with lock held
3686 mDNSlocal void UpdateAutoTunnelDomainStatus(const DomainAuthInfo *const info)
3688 #ifdef NO_SECURITYFRAMEWORK
3691 // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
3692 // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
3693 mDNS *const m = &mDNSStorage;
3694 const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL;
3695 const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL;
3697 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3698 CFStringRef domain = NULL;
3699 CFStringRef tmp = NULL;
3700 CFNumberRef num = NULL;
3701 mStatus status = mStatus_NoError;
3702 mStatus llqStatus = mStatus_NoError;
3703 char llqBuffer[1024];
3707 if (!domainStatusDict)
3709 domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3710 if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
3713 if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
3715 mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c);
3716 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3717 if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3721 if (CFDictionaryContainsKey(domainStatusDict, domain))
3723 CFDictionaryRemoveValue(domainStatusDict, domain);
3724 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3732 mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
3733 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3735 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
3738 CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
3744 mDNSu32 port = mDNSVal16(llq->ExternalPort);
3746 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3748 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
3751 CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
3757 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
3759 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
3762 CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
3770 mDNSu32 port = mDNSVal16(tun->ExternalPort);
3772 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3774 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
3777 CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
3781 mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress);
3782 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3784 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
3787 CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
3793 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
3795 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
3798 CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
3805 mDNSu32 code = m->LastNATMapResultCode;
3807 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
3809 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
3812 CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
3817 mDNS_snprintf(buffer, sizeof(buffer), "Success");
3818 llqStatus = UpdateLLQStatus(llqBuffer, sizeof(llqBuffer), info);
3819 status = UpdateRRStatus(buffer, sizeof(buffer), info);
3821 // If we have a bad signature error updating a RR, it overrides any error as it needs to be
3822 // reported so that it can be fixed automatically (or the user needs to be notified)
3823 if (status != mStatus_NoError)
3825 LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer);
3827 else if (m->Router.type == mDNSAddrType_None)
3829 status = mStatus_NoRouter;
3830 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
3832 else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
3834 status = mStatus_NoRouter;
3835 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
3837 else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress))
3839 status = mStatus_ServiceNotRunning;
3840 mDNS_snprintf(buffer, sizeof(buffer), "No inner address");
3842 else if (!llq && !tun)
3844 status = mStatus_NotInitializedErr;
3845 mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
3847 else if (llqStatus == mStatus_NoSuchRecord)
3850 mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
3852 else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
3854 status = mStatus_DoubleNAT;
3855 mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address");
3857 else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) ||
3858 (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
3859 (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
3861 status = mStatus_NATPortMappingDisabled;
3862 mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router");
3864 else if ((llq && llq->Result) || (tun && tun->Result))
3866 status = mStatus_NATTraversal;
3867 mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
3869 else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
3871 status = mStatus_NATTraversal;
3872 mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
3877 mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
3878 LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer);
3881 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
3883 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
3886 CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
3890 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3892 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
3895 CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
3899 if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
3900 !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
3902 CFDictionarySetValue(domainStatusDict, domain, dict);
3903 if (!m->ShutdownTime)
3905 LogInfo("UpdateAutoTunnelDomainStatus: %s status %d", status ? "failure" : "success", status);
3906 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3913 debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
3914 #endif // def NO_SECURITYFRAMEWORK
3917 // MUST be called with lock held
3918 mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
3920 #ifdef NO_SECURITYFRAMEWORK
3924 DomainAuthInfo* info;
3925 for (info = m->AuthInfoList; info; info = info->next)
3926 if (info->AutoTunnel && !info->deltime)
3927 UpdateAutoTunnelDomainStatus(info);
3928 #endif // def NO_SECURITYFRAMEWORK
3931 mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we need racoon to accept incoming connections
3933 DomainAuthInfo *info;
3935 for (info = m->AuthInfoList; info; info = info->next)
3936 if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
3939 if (info != AnonymousRacoonConfig)
3941 AnonymousRacoonConfig = info;
3942 LogInfo("UpdateAnonymousRacoonConfig need not be done in mDNSResponder");
3946 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
3948 // Caller must hold the lock
3949 mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record)
3953 LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c);
3955 if (record->resrec.RecordType > kDNSRecordTypeDeregistering)
3957 mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal);
3960 record->resrec.RecordType = kDNSRecordTypeUnregistered;
3961 LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c);
3964 else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
3966 else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType);
3971 // Caller must hold the lock
3972 mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
3974 if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord))
3976 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
3977 m->NextSRVUpdate = NonZeroTime(m->timenow);
3981 // Caller must hold the lock
3982 mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
3985 mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result;
3989 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem))
3991 LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
3992 info->domain.c, info->AutoTunnelServiceStarted, info->deltime, &info->AutoTunnelInnerAddress, m->SleepState);
3993 DeregisterAutoTunnelHostRecord(m, info);
3995 else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
3997 mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
3998 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
3999 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
4000 AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
4001 AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
4002 info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = info->AutoTunnelInnerAddress;
4003 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
4005 err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
4006 if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c);
4009 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
4010 m->NextSRVUpdate = NonZeroTime(m->timenow);
4011 LogInfo("UpdateAutoTunnelHostRecord registering %##s", info->AutoTunnelHostRecord.namestorage.c);
4014 else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType);
4017 // Caller must hold the lock
4018 mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4020 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
4022 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget);
4023 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService);
4024 UpdateAutoTunnelHostRecord(m, info);
4027 // Caller must hold the lock
4028 mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4032 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)
4034 LogInfo("UpdateAutoTunnelServiceRecords: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) ExtPort(%d) NATResult(%d)", info->domain.c, info->AutoTunnelServiceStarted, info->deltime, mDNSVal16(m->AutoTunnelNAT.ExternalPort), m->AutoTunnelNAT.Result);
4035 DeregisterAutoTunnelServiceRecords(m, info);
4039 if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
4041 // 1. Set up our address record for the external tunnel address
4042 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
4043 mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL,
4044 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4045 AssignDomainName (&info->AutoTunnelTarget.namestorage, (const domainname*) "\x0B" "_autotunnel");
4046 AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->hostlabel);
4047 AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
4048 info->AutoTunnelTarget.resrec.rdata->u.ipv4 = m->AutoTunnelNAT.ExternalAddress;
4049 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
4051 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelTarget);
4052 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelTarget.namestorage.c);
4053 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelTarget.namestorage.c);
4055 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType);
4057 if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
4059 // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
4060 mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL,
4061 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4062 AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4063 AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
4064 AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
4065 info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
4066 info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
4067 info->AutoTunnelService.resrec.rdata->u.srv.port = m->AutoTunnelNAT.ExternalPort;
4068 AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
4069 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
4071 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelService);
4072 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelService.namestorage.c);
4073 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelService.namestorage.c);
4075 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType);
4077 UpdateAutoTunnelHostRecord(m, info);
4079 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
4080 info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(m->AutoTunnelNAT.IntPort),
4081 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4086 // Caller must hold the lock
4087 mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4089 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo);
4092 // Caller must hold the lock
4093 mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4097 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime)
4098 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4099 else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
4101 mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4102 ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
4104 info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data);
4105 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
4107 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
4108 if (err) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
4109 else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info->AutoTunnelDeviceInfo.namestorage.c);
4112 LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType);
4115 // Caller must hold the lock
4116 mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4118 LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
4120 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
4121 UpdateAutoTunnelHostRecord(m, info);
4122 UpdateAutoTunnelDomainStatus(info);
4125 // Caller must hold the lock
4126 mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4130 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr) || m->SleepState != SleepState_Awake)
4131 DeregisterAutoTunnel6Record(m, info);
4132 else if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
4134 mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
4135 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4136 AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
4137 AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
4138 AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
4139 info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr;
4140 info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
4142 mStatus err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
4143 if (err) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err, info->AutoTunnel6Record.namestorage.c);
4144 else LogInfo("UpdateAutoTunnel6Record registering %##s", info->AutoTunnel6Record.namestorage.c);
4146 UpdateAutoTunnelHostRecord(m, info);
4148 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
4149 info->AutoTunnel6Record.namestorage.c, &m->AutoTunnelRelayAddr,
4150 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4153 else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType);
4156 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
4158 DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
4159 if (result == mStatus_MemFree)
4161 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
4165 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
4166 if (rr == &info->AutoTunnelHostRecord)
4168 rr->namestorage.c[0] = 0;
4169 m->NextSRVUpdate = NonZeroTime(m->timenow);
4170 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4172 if (m->ShutdownTime)
4174 LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
4178 if (rr == &info->AutoTunnelHostRecord)
4180 LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
4181 UpdateAutoTunnelHostRecord(m,info);
4183 else if (rr == &info->AutoTunnelDeviceInfo)
4185 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
4186 UpdateAutoTunnelDeviceInfoRecord(m,info);
4188 else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
4190 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
4191 UpdateAutoTunnelServiceRecords(m,info);
4193 else if (rr == &info->AutoTunnel6Record)
4195 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
4196 UpdateAutoTunnel6Record(m,info);
4203 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
4205 DomainAuthInfo *info;
4207 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
4208 n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort));
4212 m->NextSRVUpdate = NonZeroTime(m->timenow);
4213 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4215 for (info = m->AuthInfoList; info; info = info->next)
4216 if (info->AutoTunnel)
4217 UpdateAutoTunnelServiceRecords(m, info);
4219 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
4221 UpdateAutoTunnelDomainStatuses(m);
4226 mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
4228 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
4231 // We forcibly deregister the records that are based on the hostname.
4232 // When deregistration of each completes, the MemFree callback will make the
4233 // appropriate Update* call to use the new name to reregister.
4234 DeregisterAutoTunnelHostRecord(m, info);
4235 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4236 DeregisterAutoTunnelServiceRecords(m, info);
4237 DeregisterAutoTunnel6Record(m, info);
4238 m->NextSRVUpdate = NonZeroTime(m->timenow);
4242 // Must be called with the lock held
4243 mDNSexport void StartServerTunnel(DomainAuthInfo *const info)
4245 mDNS *const m = &mDNSStorage;
4246 if (info->deltime) return;
4248 if (info->AutoTunnelServiceStarted)
4250 // On wake from sleep, this function will be called when determining SRV targets,
4251 // and needs to re-register the host record for the target to be set correctly
4252 UpdateAutoTunnelHostRecord(m, info);
4256 info->AutoTunnelServiceStarted = mDNStrue;
4258 // Now that we have a service in this domain, we need to try to register the
4259 // AutoTunnel records, because the relay connection & NAT-T may have already been
4260 // started for another domain. If the relay connection is not up or the NAT-T has not
4261 // yet succeeded, the Update* functions are smart enough to not register the records.
4262 // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
4263 // decide whether to register the AutoTunnel records in the calls below.
4264 UpdateAutoTunnelServiceRecords(m, info);
4265 UpdateAutoTunnel6Record(m, info);
4266 UpdateAutoTunnelDeviceInfoRecord(m, info);
4267 UpdateAutoTunnelHostRecord(m, info);
4269 // If the global AutoTunnel NAT-T is not yet started, start it.
4270 if (!m->AutoTunnelNAT.clientContext)
4272 m->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
4273 m->AutoTunnelNAT.clientContext = (void*)1; // Means AutoTunnelNAT Traversal is active;
4274 m->AutoTunnelNAT.Protocol = NATOp_MapUDP;
4275 m->AutoTunnelNAT.IntPort = IPSECPort;
4276 m->AutoTunnelNAT.RequestedPort = IPSECPort;
4277 m->AutoTunnelNAT.NATLease = 0;
4278 mStatus err = mDNS_StartNATOperation_internal(m, &m->AutoTunnelNAT);
4279 if (err) LogMsg("StartServerTunnel: error %d starting NAT mapping", err);
4283 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
4285 mDNSv6Addr loc_outer6;
4286 mDNSv6Addr rmt_outer6;
4288 // When we are tunneling over IPv6 Relay address, the port number is zero
4289 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4291 loc_outer6 = tun->loc_outer6;
4292 rmt_outer6 = tun->rmt_outer6;
4296 loc_outer6 = zerov6Addr;
4297 loc_outer6.b[0] = tun->loc_outer.b[0];
4298 loc_outer6.b[1] = tun->loc_outer.b[1];
4299 loc_outer6.b[2] = tun->loc_outer.b[2];
4300 loc_outer6.b[3] = tun->loc_outer.b[3];
4302 rmt_outer6 = zerov6Addr;
4303 rmt_outer6.b[0] = tun->rmt_outer.b[0];
4304 rmt_outer6.b[1] = tun->rmt_outer.b[1];
4305 rmt_outer6.b[2] = tun->rmt_outer.b[2];
4306 rmt_outer6.b[3] = tun->rmt_outer.b[3];
4309 return(mDNSAutoTunnelSetKeys(AddNew ? kmDNSAutoTunnelSetKeysReplace : kmDNSAutoTunnelSetKeysDelete, tun->loc_inner.b, loc_outer6.b, kRacoonPort, tun->rmt_inner.b, rmt_outer6.b, mDNSVal16(tun->rmt_outer_port), btmmprefix, SkipLeadingLabels(&tun->dstname, 1)));
4312 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
4313 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
4315 mDNSlocal void ReissueBlockedQuestionWithType(domainname *d, mDNSBool success, mDNSu16 qtype)
4317 mDNS *const m = &mDNSStorage;
4318 DNSQuestion *q = m->Questions;
4321 if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
4323 LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4324 mDNSQuestionCallback *tmp = q->QuestionCallback;
4325 q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
4326 mDNS_StopQuery(m, q);
4327 mDNS_StartQuery(m, q);
4328 q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
4329 if (!success) q->NoAnswer = NoAnswer_Fail;
4330 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
4331 // In general we have to assume that the question list might have changed in arbitrary ways.
4332 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
4333 // already in use. The safest solution is just to go back to the start of the list and start again.
4334 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
4335 // just one suspended question, so it's really a 2n algorithm.
4343 mDNSlocal void ReissueBlockedQuestions(domainname *d, mDNSBool success)
4345 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
4346 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
4347 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
4348 // 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.
4349 // 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.
4350 ReissueBlockedQuestionWithType(d, success, kDNSType_AAAA);
4351 ReissueBlockedQuestionWithType(d, mDNStrue, kDNSType_A);
4354 mDNSlocal void UnlinkAndReissueBlockedQuestions(ClientTunnel *tun, mDNSBool success)
4356 mDNS *const m = &mDNSStorage;
4357 ClientTunnel **p = &m->TunnelClients;
4358 while (*p != tun && *p) p = &(*p)->next;
4359 if (*p) *p = tun->next;
4360 ReissueBlockedQuestions(&tun->dstname, success);
4361 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
4362 freeL("ClientTunnel", tun);
4365 mDNSlocal mDNSBool TunnelClientDeleteMatching(ClientTunnel *tun, mDNSBool v6Tunnel)
4367 mDNS *const m = &mDNSStorage;
4369 mDNSBool needSetKeys = mDNStrue;
4374 // Is this a tunnel to the same host that we are trying to setup now?
4375 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4378 ClientTunnel *old = *p;
4381 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4382 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4383 if (old->q.ThisQInterval >= 0)
4385 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4386 mDNS_StopQuery(m, &old->q);
4388 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4389 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4390 !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
4391 !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
4393 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4394 // the other parameters of the tunnel are different
4395 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4396 AutoTunnelSetKeys(old, mDNSfalse);
4400 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4401 // as "tun" and "old" are identical
4402 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
4404 needSetKeys = mDNSfalse;
4409 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4410 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4411 if (old->q.ThisQInterval >= 0)
4413 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4414 mDNS_StopQuery(m, &old->q);
4416 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4417 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4418 !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
4419 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
4420 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
4422 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4423 // the other parameters of the tunnel are different
4424 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4425 AutoTunnelSetKeys(old, mDNSfalse);
4429 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4430 // as "tun" and "old" are identical
4431 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
4433 needSetKeys = mDNSfalse;
4438 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
4439 freeL("ClientTunnel", old);
4445 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
4446 // tunnel will be deleted
4447 mDNSlocal void TunnelClientDeleteAny(ClientTunnel *tun, mDNSBool v6Tunnel)
4454 // If there is more than one client tunnel to the same host, delete all of them.
4455 // We do this by just checking against the EUI64 rather than the full address
4456 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4459 ClientTunnel *old = *p;
4462 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4463 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4467 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4468 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4470 if (old->q.ThisQInterval >= 0)
4472 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4473 mDNS_StopQuery(&mDNSStorage, &old->q);
4477 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4478 AutoTunnelSetKeys(old, mDNSfalse);
4481 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
4482 freeL("ClientTunnel", old);
4487 mDNSlocal void TunnelClientFinish(DNSQuestion *question, const ResourceRecord *const answer)
4489 mDNS *const m = &mDNSStorage;
4490 mDNSBool needSetKeys = mDNStrue;
4491 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4492 mDNSBool v6Tunnel = mDNSfalse;
4493 DomainAuthInfo *info;
4495 // If the port is zero, then we have a relay address of the peer
4496 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4497 v6Tunnel = mDNStrue;
4501 LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
4502 tun->rmt_outer6 = answer->rdata->u.ipv6;
4503 tun->loc_outer6 = m->AutoTunnelRelayAddr;
4507 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
4508 tun->rmt_outer = answer->rdata->u.ipv4;
4509 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
4510 tmpDst.ip.v4 = tun->rmt_outer;
4511 mDNSAddr tmpSrc = zeroAddr;
4512 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
4513 if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
4514 else tun->loc_outer = m->AdvertisedV4.ip.v4;
4517 question->ThisQInterval = -1; // So we know this tunnel setup has completed
4519 info = GetAuthInfoForName(m, &tun->dstname);
4522 LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
4523 ReissueBlockedQuestions(&tun->dstname, mDNSfalse);
4527 tun->loc_inner = info->AutoTunnelInnerAddress;
4529 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
4530 // look for existing tunnels to see whether they have the same information for our peer.
4531 // If not, delete them and need to create a new tunnel. If they are same, just use the
4532 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
4533 TunnelClientDeleteAny(tun, !v6Tunnel);
4534 needSetKeys = TunnelClientDeleteMatching(tun, v6Tunnel);
4536 if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
4537 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
4539 mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
4540 LogInfo("TunnelClientFinish: Tunnel setup result %d", result);
4541 // Kick off any questions that were held pending this tunnel setup
4542 ReissueBlockedQuestions(&tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
4545 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
4547 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4548 DomainAuthInfo *info;
4550 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
4552 if (!AddRecord) return;
4553 mDNS_StopQuery(m, question);
4555 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
4556 // The code below will look for _autotunnel._udp SRV record followed by A record
4557 if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
4559 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
4560 UnlinkAndReissueBlockedQuestions(tun, mDNSfalse);
4564 switch (tun->tc_state)
4566 case TC_STATE_AAAA_PEER:
4567 if (question->qtype != kDNSType_AAAA)
4569 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
4571 info = GetAuthInfoForName(m, &tun->dstname);
4574 LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
4575 UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4578 if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
4580 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
4581 UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4584 if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
4586 LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6);
4587 UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4590 tun->rmt_inner = answer->rdata->u.ipv6;
4591 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
4592 if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
4594 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
4595 tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
4596 question->qtype = kDNSType_AAAA;
4597 AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
4601 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
4602 tun->tc_state = TC_STATE_SRV_PEER;
4603 question->qtype = kDNSType_SRV;
4604 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4606 AppendDomainName(&question->qname, &tun->dstname);
4607 mDNS_StartQuery(m, &tun->q);
4609 case TC_STATE_AAAA_PEER_RELAY:
4610 if (question->qtype != kDNSType_AAAA)
4612 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
4614 // If it failed, look for the SRV record.
4615 if (!answer->rdlength)
4617 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
4618 tun->tc_state = TC_STATE_SRV_PEER;
4619 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4620 AppendDomainName(&question->qname, &tun->dstname);
4621 question->qtype = kDNSType_SRV;
4622 mDNS_StartQuery(m, &tun->q);
4625 TunnelClientFinish(question, answer);
4627 case TC_STATE_SRV_PEER:
4628 if (question->qtype != kDNSType_SRV)
4630 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
4632 LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
4633 tun->tc_state = TC_STATE_ADDR_PEER;
4634 AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
4635 tun->rmt_outer_port = answer->rdata->u.srv.port;
4636 question->qtype = kDNSType_A;
4637 mDNS_StartQuery(m, &tun->q);
4639 case TC_STATE_ADDR_PEER:
4640 if (question->qtype != kDNSType_A)
4642 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
4644 TunnelClientFinish(question, answer);
4647 LogMsg("AutoTunnelCallback: Unknown question %p", question);
4651 // Must be called with the lock held
4652 mDNSexport void AddNewClientTunnel(DNSQuestion *const q)
4654 mDNS *const m = &mDNSStorage;
4655 ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
4657 AssignDomainName(&p->dstname, &q->qname);
4658 p->MarkedForDeletion = mDNSfalse;
4659 p->loc_inner = zerov6Addr;
4660 p->loc_outer = zerov4Addr;
4661 p->loc_outer6 = zerov6Addr;
4662 p->rmt_inner = zerov6Addr;
4663 p->rmt_outer = zerov4Addr;
4664 p->rmt_outer6 = zerov6Addr;
4665 p->rmt_outer_port = zeroIPPort;
4666 p->tc_state = TC_STATE_AAAA_PEER;
4667 p->next = m->TunnelClients;
4668 m->TunnelClients = p; // We intentionally build list in reverse order
4670 p->q.InterfaceID = mDNSInterface_Any;
4672 p->q.Target = zeroAddr;
4673 AssignDomainName(&p->q.qname, &q->qname);
4674 p->q.qtype = kDNSType_AAAA;
4675 p->q.qclass = kDNSClass_IN;
4676 p->q.LongLived = mDNSfalse;
4677 p->q.ExpectUnique = mDNStrue;
4678 p->q.ForceMCast = mDNSfalse;
4679 p->q.ReturnIntermed = mDNStrue;
4680 p->q.SuppressUnusable = mDNSfalse;
4681 p->q.SearchListIndex = 0;
4682 p->q.AppendSearchDomains = 0;
4683 p->q.RetryWithSearchDomains = mDNSfalse;
4684 p->q.TimeoutQuestion = 0;
4685 p->q.WakeOnResolve = 0;
4686 p->q.UseBackgroundTrafficClass = mDNSfalse;
4687 p->q.ValidationRequired = 0;
4688 p->q.ValidatingResponse = 0;
4689 p->q.ProxyQuestion = 0;
4690 p->q.qnameOrig = mDNSNULL;
4691 p->q.AnonInfo = mDNSNULL;
4692 p->q.pid = mDNSPlatformGetPID();
4694 p->q.QuestionCallback = AutoTunnelCallback;
4695 p->q.QuestionContext = p;
4697 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
4698 mDNS_StartQuery_internal(m, &p->q);
4701 #endif // APPLE_OSX_mDNSResponder
4703 #if COMPILER_LIKES_PRAGMA_MARK
4705 #pragma mark - Power State & Configuration Change Management
4708 mDNSlocal mStatus ReorderInterfaceList()
4710 // Disable Reorder lists till <rdar://problem/30071012> is fixed to prevent spurious name conflicts
4711 return (mStatus_NoError);
4713 mDNS *const m = &mDNSStorage;
4714 nwi_state_t state = nwi_state_copy();
4716 if (state == mDNSNULL)
4718 LogMsg("NWI State is NULL!");
4719 return (mStatus_Invalid);
4722 // Get the count of interfaces
4723 mDNSu32 count = nwi_state_get_interface_names(state, mDNSNULL, 0);
4726 LogMsg("Unable to get the ordered list of interface names");
4727 nwi_state_release(state);
4728 return (mStatus_Invalid);
4731 // Get the ordered interface list
4733 const char *names[count];
4734 count = nwi_state_get_interface_names(state, names, count);
4736 NetworkInterfaceInfo *newList = mDNSNULL;
4737 for (i = count-1; i >= 0; i--)
4738 { // Build a new ordered interface list
4739 NetworkInterfaceInfo **ptr = &m->HostInterfaces;
4740 while (*ptr != mDNSNULL )
4742 if (strcmp((*ptr)->ifname, names[i]) == 0)
4744 NetworkInterfaceInfo *node = *ptr;
4745 *ptr = (*ptr)->next;
4746 node->next = newList;
4750 ptr = &((*ptr)->next);
4754 // Get to the end of the list
4755 NetworkInterfaceInfo *newListEnd = newList;
4756 while (newListEnd != mDNSNULL && newListEnd->next != mDNSNULL)
4757 newListEnd = newListEnd->next;
4759 // Add any remaing interfaces to the end of the sorted list
4760 if (newListEnd != mDNSNULL)
4761 newListEnd->next = m->HostInterfaces;
4763 // If we have a valid new list, point to that now
4764 if (newList != mDNSNULL)
4765 m->HostInterfaces = newList;
4767 nwi_state_release(state);
4768 return (mStatus_NoError);
4771 mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
4773 mDNS *const m = &mDNSStorage;
4774 mDNSBool foundav4 = mDNSfalse;
4775 mDNSBool foundav6 = mDNSfalse;
4776 struct ifaddrs *ifa = myGetIfAddrs(0);
4777 struct ifaddrs *v4Loopback = NULL;
4778 struct ifaddrs *v6Loopback = NULL;
4779 char defaultname[64];
4780 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
4781 if (InfoSocket < 3 && errno != EAFNOSUPPORT)
4782 LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
4784 if (m->SleepState == SleepState_Sleeping) ifa = NULL;
4788 #if LIST_ALL_INTERFACES
4791 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
4792 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
4793 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4794 else if (ifa->ifa_addr->sa_family == AF_LINK)
4795 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
4796 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4797 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
4798 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
4799 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4802 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X ifa_addr is NOT set",
4803 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags);
4805 if (!(ifa->ifa_flags & IFF_UP))
4806 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
4807 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4808 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4809 if (!(ifa->ifa_flags & IFF_MULTICAST))
4810 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
4811 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4812 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4813 if (ifa->ifa_flags & IFF_POINTOPOINT)
4814 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
4815 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4816 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4817 if (ifa->ifa_flags & IFF_LOOPBACK)
4818 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
4819 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4820 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4823 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
4825 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
4826 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
4827 mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
4830 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
4831 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
4833 if (!ifa->ifa_netmask)
4836 SetupAddr(&ip, ifa->ifa_addr);
4837 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
4838 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
4840 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
4841 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4842 else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0)
4845 SetupAddr(&ip, ifa->ifa_addr);
4846 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
4847 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
4849 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
4850 else if ((int)if_nametoindex(ifa->ifa_name) <= 0)
4852 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
4856 // Make sure ifa_netmask->sa_family is set correctly
4857 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4858 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
4859 int ifru_flags6 = 0;
4861 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
4862 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
4864 struct in6_ifreq ifr6;
4865 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
4866 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
4867 ifr6.ifr_addr = *sin6;
4868 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
4869 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
4870 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
4873 if (!(ifru_flags6 & (IN6_IFF_TENTATIVE | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
4875 if (ifa->ifa_flags & IFF_LOOPBACK)
4877 if (ifa->ifa_addr->sa_family == AF_INET)
4879 else if (sin6->sin6_addr.s6_addr[0] != 0xFD)
4884 NetworkInterfaceInfoOSX *i = AddInterfaceToList(ifa, utc);
4885 if (i && MulticastInterface(i) && i->ifinfo.Advertise)
4887 if (ifa->ifa_addr->sa_family == AF_INET)
4888 foundav4 = mDNStrue;
4890 foundav6 = mDNStrue;
4896 ifa = ifa->ifa_next;
4899 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
4900 if (!foundav4 && v4Loopback) AddInterfaceToList(v4Loopback, utc);
4901 if (!foundav6 && v6Loopback) AddInterfaceToList(v6Loopback, utc);
4903 // Now the list is complete, set the McastTxRx setting for each interface.
4904 NetworkInterfaceInfoOSX *i;
4905 for (i = m->p->InterfaceList; i; i = i->next)
4908 mDNSBool txrx = MulticastInterface(i);
4909 if (i->ifinfo.McastTxRx != txrx)
4911 i->ifinfo.McastTxRx = txrx;
4912 i->Exists = MulticastStateChanged; // State change; need to deregister and reregister this interface
4916 if (InfoSocket >= 0)
4919 mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
4920 m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
4922 // Set up the nice label
4923 domainlabel nicelabel;
4925 GetUserSpecifiedFriendlyComputerName(&nicelabel);
4926 if (nicelabel.c[0] == 0)
4928 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
4929 MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
4932 // Set up the RFC 1034-compliant label
4933 domainlabel hostlabel;
4935 GetUserSpecifiedLocalHostName(&hostlabel);
4936 if (hostlabel.c[0] == 0)
4938 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
4939 MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
4942 mDNSBool namechange = mDNSfalse;
4944 // We use a case-sensitive comparison here because even though changing the capitalization
4945 // of the name alone is not significant to DNS, it's still a change from the user's point of view
4946 if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
4947 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
4950 if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
4951 LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
4952 m->p->usernicelabel = m->nicelabel = nicelabel;
4953 namechange = mDNStrue;
4956 if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
4957 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
4960 if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
4961 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
4962 m->p->userhostlabel = m->hostlabel = hostlabel;
4964 namechange = mDNStrue;
4967 if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
4969 #if APPLE_OSX_mDNSResponder
4970 DomainAuthInfo *info;
4971 for (info = m->AuthInfoList; info; info = info->next)
4972 if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
4973 #endif // APPLE_OSX_mDNSResponder
4976 return(mStatus_NoError);
4979 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
4980 // Returns -1 if all the one-bits are not contiguous
4981 mDNSlocal int CountMaskBits(mDNSAddr *mask)
4983 int i = 0, bits = 0;
4984 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
4987 mDNSu8 b = mask->ip.v6.b[i++];
4988 while (b & 0x80) { bits++; b <<= 1; }
4991 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
4995 // Returns count of non-link local V4 addresses registered (why? -- SC)
4996 mDNSlocal int SetupActiveInterfaces(mDNSs32 utc)
4998 mDNS *const m = &mDNSStorage;
4999 NetworkInterfaceInfoOSX *i;
5002 // Recalculate SuppressProbes time based on the current set of active interfaces.
5003 m->SuppressProbes = 0;
5004 for (i = m->p->InterfaceList; i; i = i->next)
5007 NetworkInterfaceInfo *const n = &i->ifinfo;
5008 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
5009 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
5011 if (i->Registered && i->Registered != primary) // Sanity check
5013 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
5014 i->Registered = mDNSNULL;
5019 InterfaceActivationSpeed activationSpeed;
5021 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5022 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5023 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it.
5024 i->Registered = primary;
5026 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
5027 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
5028 // 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.
5029 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
5031 // The "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
5032 // every time a new interface is created. We think it is a duplicate and hence consider it
5033 // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
5034 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
5035 // logs a warning message to system.log noting frequent interface transitions.
5036 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
5037 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
5039 activationSpeed = FastActivation;
5040 LogInfo("SetupActiveInterfaces: %s DirectLink interface registering", i->ifinfo.ifname);
5042 else if (i->Flashing && i->Occulting)
5044 activationSpeed = SlowActivation;
5048 activationSpeed = NormalActivation;
5051 mDNS_RegisterInterface(m, n, activationSpeed);
5053 if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
5054 LogInfo("SetupActiveInterfaces: Registered %7s(%u) BSSID %.6a Struct addr %p, primary %p, %#a/%d%s%s%s",
5055 i->ifinfo.ifname, i->scope_id, &i->BSSID, i, primary, &n->ip, CountMaskBits(&n->mask),
5056 i->Flashing ? " (Flashing)" : "",
5057 i->Occulting ? " (Occulting)" : "",
5058 n->InterfaceActive ? " (Primary)" : "");
5062 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, &n->ip);
5063 #if TARGET_OS_EMBEDDED
5064 // We join the Bonjour multicast group on Apple embedded platforms ONLY when a client request is active,
5065 // so we leave the multicast group here to clear any residual group membership.
5066 if (i->sa_family == AF_INET)
5069 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
5070 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
5071 imr.imr_interface = primary->ifa_v4addr;
5073 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET) == i)
5075 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
5076 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
5077 if (err < 0 && (errno != EADDRNOTAVAIL))
5078 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
5081 if (i->sa_family == AF_INET6)
5083 struct ipv6_mreq i6mr;
5084 i6mr.ipv6mr_interface = primary->scope_id;
5085 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
5087 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET6) == i)
5089 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IPV6_LEAVE_GROUP for %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5090 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
5091 if (err < 0 && (errno != EADDRNOTAVAIL))
5092 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5095 #endif // TARGET_OS_EMBEDDED
5099 if (i->sa_family == AF_INET)
5102 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
5103 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
5104 imr.imr_interface = primary->ifa_v4addr;
5106 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
5107 // before trying to join the group, to clear out stale kernel state which may be lingering.
5108 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
5109 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
5110 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
5111 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
5112 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
5113 // because by the time we get the configuration change notification, the interface is already gone,
5114 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
5115 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
5116 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET) == i)
5118 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
5119 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
5120 if (err < 0 && (errno != EADDRNOTAVAIL))
5121 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
5124 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
5125 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
5126 // Joining same group twice can give "Address already in use" error -- no need to report that
5127 if (err < 0 && (errno != EADDRINUSE))
5128 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
5130 if (i->sa_family == AF_INET6)
5132 struct ipv6_mreq i6mr;
5133 i6mr.ipv6mr_interface = primary->scope_id;
5134 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
5136 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET6) == i)
5138 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5139 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
5140 if (err < 0 && (errno != EADDRNOTAVAIL))
5141 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5144 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5145 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
5146 // Joining same group twice can give "Address already in use" error -- no need to report that
5147 if (err < 0 && (errno != EADDRINUSE))
5148 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5157 mDNSlocal void MarkAllInterfacesInactive(mDNSs32 utc)
5159 NetworkInterfaceInfoOSX *i;
5160 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
5162 if (i->Exists) i->LastSeen = utc;
5163 i->Exists = mDNSfalse;
5167 // Returns count of non-link local V4 addresses deregistered (why? -- SC)
5168 mDNSlocal int ClearInactiveInterfaces(mDNSs32 utc)
5170 mDNS *const m = &mDNSStorage;
5172 // If an interface is going away, then deregister this from the mDNSCore.
5173 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
5174 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
5175 // it refers to has gone away we'll crash.
5176 NetworkInterfaceInfoOSX *i;
5178 for (i = m->p->InterfaceList; i; i = i->next)
5180 // If this interface is no longer active, or its InterfaceID is changing, deregister it
5181 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
5183 if (i->Exists == 0 || i->Exists == MulticastStateChanged || i->Registered != primary)
5185 InterfaceActivationSpeed activationSpeed;
5187 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
5188 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5189 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary,
5190 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
5191 i->Flashing ? " (Flashing)" : "",
5192 i->Occulting ? " (Occulting)" : "",
5193 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5195 // "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
5196 // every time it creates a new interface. We think it is a duplicate and hence consider it
5197 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
5198 // stale data returned to the application even after the interface is removed. The application
5199 // then starts to send data but the new interface is not yet created.
5200 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
5201 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
5203 activationSpeed = FastActivation;
5204 LogInfo("ClearInactiveInterfaces: %s DirectLink interface deregistering", i->ifinfo.ifname);
5206 else if (i->Flashing && i->Occulting)
5208 activationSpeed = SlowActivation;
5212 activationSpeed = NormalActivation;
5214 mDNS_DeregisterInterface(m, &i->ifinfo, activationSpeed);
5216 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
5217 i->Registered = mDNSNULL;
5218 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5219 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5220 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
5222 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
5223 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
5228 // Now that everything that's going to deregister has done so, we can clean up and free the memory
5229 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
5233 // If no longer active, delete interface from list and free memory
5236 if (i->LastSeen == utc) i->LastSeen = utc - 1;
5237 mDNSBool delete = (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0) && (utc - i->LastSeen >= 60);
5238 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
5239 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
5240 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
5241 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5242 #if APPLE_OSX_mDNSResponder
5243 if (i->BPF_fd >= 0) CloseBPF(i);
5244 #endif // APPLE_OSX_mDNSResponder
5248 freeL("NetworkInterfaceInfoOSX", i);
5249 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
5257 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
5259 DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
5260 if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
5263 dnle->next = mDNSNULL;
5265 AssignDomainName(&dnle->name, name);
5267 *List = &dnle->next;
5271 mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
5273 dns_resolver_t *a = *(dns_resolver_t**)aa;
5274 dns_resolver_t *b = *(dns_resolver_t**)bb;
5276 return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
5279 mDNSlocal void UpdateSearchDomainHash(MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID)
5281 mDNS *const m = &mDNSStorage;
5283 mDNSu32 scopeid = 0;
5289 // Hash the search domain name followed by the InterfaceID.
5290 // As we have scoped search domains, we also included InterfaceID. If either of them change,
5291 // we will detect it. Even if the order of them change, we will detect it.
5293 // Note: We have to handle a few of these tricky cases.
5295 // 1) Current: com, apple.com Changing to: comapple.com
5296 // 2) Current: a.com,b.com Changing to a.comb.com
5297 // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
5298 // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
5300 // There are more variants of the above. The key thing is if we include the null in each case
5301 // at the end of name and the InterfaceID, it will prevent a new name (which can't include
5302 // NULL as part of the name) to be mistakenly thought of as a old name.
5304 scopeid = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
5305 // mDNS_snprintf always null terminates
5306 if (mDNS_snprintf(ifid_buf, sizeof(ifid_buf), "%u", scopeid) >= sizeof(ifid_buf))
5307 LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid);
5309 LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf, ifid_buf);
5310 MD5_Update(sdc, buf, strlen(buf) + 1);
5311 MD5_Update(sdc, ifid_buf, strlen(ifid_buf) + 1);
5314 mDNSlocal void FinalizeSearchDomainHash(MD5_CTX *sdc)
5316 mDNS *const m = &mDNSStorage;
5317 mDNSu8 md5_hash[MD5_LEN];
5319 MD5_Final(md5_hash, sdc);
5321 if (memcmp(md5_hash, m->SearchDomainsHash, MD5_LEN))
5323 // If the hash is different, either the search domains have changed or
5324 // the ordering between them has changed. Restart the questions that
5325 // would be affected by this.
5326 LogInfo("FinalizeSearchDomains: The hash is different");
5327 memcpy(m->SearchDomainsHash, md5_hash, MD5_LEN);
5328 RetrySearchDomainQuestions(m);
5330 else { LogInfo("FinalizeSearchDomains: The hash is same"); }
5333 mDNSexport const char *DNSScopeToString(mDNSu32 scope)
5339 case kScopeInterfaceID:
5340 return "InterfaceScoped";
5341 case kScopeServiceID:
5342 return "ServiceScoped";
5348 mDNSlocal void ConfigSearchDomains(dns_resolver_t *resolver, mDNSInterfaceID interfaceId, mDNSu32 scope, MD5_CTX *sdc, uint64_t generation)
5350 const char *scopeString = DNSScopeToString(scope);
5354 if (scope == kScopeNone)
5355 interfaceId = mDNSInterface_Any;
5357 if (scope == kScopeNone || scope == kScopeInterfaceID)
5359 for (j = 0; j < resolver->n_search; j++)
5361 if (MakeDomainNameFromDNSNameString(&d, resolver->search[j]) != NULL)
5363 static char interface_buf[32];
5364 mDNS_snprintf(interface_buf, sizeof(interface_buf), "for interface %s", InterfaceNameForID(&mDNSStorage, interfaceId));
5365 LogInfo("ConfigSearchDomains: (%s) configuring search domain %s %s (generation= %llu)", scopeString,
5366 resolver->search[j], (interfaceId == mDNSInterface_Any) ? "" : interface_buf, generation);
5367 UpdateSearchDomainHash(sdc, resolver->search[j], interfaceId);
5368 mDNS_AddSearchDomain_CString(resolver->search[j], interfaceId);
5372 LogInfo("ConfigSearchDomains: An invalid search domain was detected for %s domain %s n_nameserver %d, (generation= %llu)",
5373 DNSScopeToString(scope), resolver->domain, resolver->n_nameserver, generation);
5379 LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString, InterfaceNameForID(&mDNSStorage, interfaceId));
5383 mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNSu32 ifindex)
5385 NetworkInterfaceInfoOSX *ni;
5386 mDNSInterfaceID interface;
5388 for (ni = mDNSStorage.p->InterfaceList; ni; ni = ni->next)
5390 if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex)
5395 interface = ni->ifinfo.InterfaceID;
5399 // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
5400 // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
5401 // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
5402 // As the caller is going to ack the configuration always, we have to add all the DNS servers
5403 // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
5405 LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex);
5407 // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
5408 interface = (mDNSInterfaceID)(unsigned long)ifindex;
5413 mDNSlocal void ConfigNonUnicastResolver(dns_resolver_t *r)
5415 char *opt = r->options;
5418 if (opt && !strncmp(opt, "mdns", strlen(opt)))
5420 if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5422 LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain);
5425 mDNS_AddMcastResolver(&mDNSStorage, &d, mDNSInterface_Any, r->timeout);
5429 mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID)
5434 mDNSBool cellIntf = mDNSfalse;
5435 mDNSBool reqA, reqAAAA;
5436 NetworkInterfaceInfoOSX *info;
5437 mDNSBool isExpensive;
5439 if (!r->domain || !*r->domain)
5443 else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5445 LogMsg("ConfigDNSServers: bad domain %s", r->domain);
5448 // Parse the resolver specific attributes that affects all the DNS servers.
5449 if (scope == kScopeServiceID)
5451 serviceID = r->service_identifier;
5454 #if TARGET_OS_IPHONE
5455 cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
5457 reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse);
5458 reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
5459 info = IfindexToInterfaceInfoOSX(interface);
5460 isExpensive = info ? info->isExpensive : mDNSfalse;
5462 for (n = 0; n < r->n_nameserver; n++)
5467 if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6)
5470 if (SetupAddr(&saddr, r->nameserver[n]))
5472 LogMsg("ConfigDNSServers: Bad address");
5476 // The timeout value is for all the DNS servers in a given resolver, hence we pass
5477 // the timeout value only for the first DNSServer. If we don't have a value in the
5478 // resolver, then use the core's default value
5480 // Note: this assumes that when the core picks a list of DNSServers for a question,
5481 // it takes the sum of all the timeout values for all DNS servers. By doing this, it
5482 // tries all the DNS servers in a specified timeout
5483 s = mDNS_AddDNSServer(&mDNSStorage, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope,
5484 (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, isExpensive, resGroupID, reqA, reqAAAA, mDNStrue);
5487 LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c);
5492 // ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
5493 // Service scope resolvers. This is indicated by the scope argument.
5495 // "resolver" has entries that should only be used for unscoped questions.
5497 // "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
5498 // interface index (q->InterfaceID)
5500 // "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
5501 // a service identifier (q->ServiceID)
5503 mDNSlocal void ConfigResolvers(dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc, mDNSu16 resGroupID)
5506 dns_resolver_t **resolver;
5508 const char *scopeString = DNSScopeToString(scope);
5509 mDNSInterfaceID interface;
5514 resolver = config->resolver;
5515 nresolvers = config->n_resolver;
5517 case kScopeInterfaceID:
5518 resolver = config->scoped_resolver;
5519 nresolvers = config->n_scoped_resolver;
5521 case kScopeServiceID:
5522 resolver = config->service_specific_resolver;
5523 nresolvers = config->n_service_specific_resolver;
5528 qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
5530 for (i = 0; i < nresolvers; i++)
5532 dns_resolver_t *r = resolver[i];
5534 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString, i, r->domain, r->n_nameserver);
5536 interface = mDNSInterface_Any;
5538 // Parse the interface index
5539 if (r->if_index != 0)
5541 interface = ConfigParseInterfaceID(r->if_index);
5546 ConfigSearchDomains(resolver[i], interface, scope, sdc, config->generation);
5548 // Parse other scoped resolvers for search lists
5553 if (r->port == 5353 || r->n_nameserver == 0)
5555 ConfigNonUnicastResolver(r);
5559 // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the
5560 // scoped resolver are not used by other non-scoped or scoped resolvers.
5561 if (scope != kScopeNone)
5564 ConfigDNSServers(r, interface, scope, resGroupID);
5569 #if APPLE_OSX_mDNSResponder
5570 mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
5572 if (QuerySuppressed(q))
5574 debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5577 if (mDNSOpaque16IsZero(q->TargetQID))
5579 debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5582 // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
5584 if (q->LOAddressAnswers)
5586 debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5593 // This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
5594 // We set our state appropriately so that if we start receiving answers, trigger the
5595 // upper layer to retry DNS questions.
5596 #if APPLE_OSX_mDNSResponder
5597 mDNSexport void mDNSPlatformUpdateDNSStatus(DNSQuestion *q)
5599 mDNS *const m = &mDNSStorage;
5600 if (!QuestionValidForDNSTrigger(q))
5603 // Ignore applications that start and stop queries for no reason before we ever talk
5604 // to any DNS server.
5605 if (!q->triedAllServersOnce)
5607 LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q->qname.c, DNSTypeName(q->qtype));
5610 if (q->qtype == kDNSType_A)
5611 m->p->v4answers = 0;
5612 if (q->qtype == kDNSType_AAAA)
5613 m->p->v6answers = 0;
5614 if (!m->p->v4answers || !m->p->v6answers)
5616 LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, question %##s (%s)", m->p->v4answers, m->p->v6answers, q->qname.c,
5617 DNSTypeName(q->qtype));
5622 mDNSlocal void AckConfigd(dns_config_t *config)
5624 mDNS_CheckLock(&mDNSStorage);
5626 // Acking the configuration triggers configd to reissue the reachability queries
5627 mDNSStorage.p->DNSTrigger = NonZeroTime(mDNSStorage.timenow);
5628 _dns_configuration_ack(config, "com.apple.mDNSResponder");
5631 // If v4q is non-NULL, it means we have received some answers for "A" type questions
5632 // If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
5633 #if APPLE_OSX_mDNSResponder
5634 mDNSexport void mDNSPlatformTriggerDNSRetry(DNSQuestion *v4q, DNSQuestion *v6q)
5636 mDNS *const m = &mDNSStorage;
5637 mDNSBool trigger = mDNSfalse;
5640 // Don't send triggers too often.
5641 // If we have started delivering answers to questions, we should send a trigger
5642 // if the time permits. If we are delivering answers, we should set the state
5643 // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know
5644 // whether the answers that are being delivered currently is for configd or some
5645 // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
5646 // then we won't deliver the trigger later when it is okay to send one as the
5647 // "answers" are already set to 1. Hence, don't affect the state of v4answers and
5648 // v6answers if we are not delivering triggers.
5650 timenow = m->timenow;
5651 if (m->p->DNSTrigger && (timenow - m->p->DNSTrigger) < DNS_TRIGGER_INTERVAL)
5653 if (!m->p->v4answers || !m->p->v6answers)
5655 debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
5656 (timenow - m->p->DNSTrigger), m->p->v4answers, m->p->v6answers);
5662 if (v4q != NULL && QuestionValidForDNSTrigger(v4q))
5664 int old = m->p->v4answers;
5666 m->p->v4answers = 1;
5668 // If there are IPv4 answers now and previously we did not have
5669 // any answers, trigger a DNS change so that reachability
5670 // can retry the queries again.
5673 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
5674 v4q->qname.c, DNSTypeName(v4q->qtype));
5678 if (v6q != NULL && QuestionValidForDNSTrigger(v6q))
5680 int old = m->p->v6answers;
5682 m->p->v6answers = 1;
5683 // If there are IPv6 answers now and previously we did not have
5684 // any answers, trigger a DNS change so that reachability
5685 // can retry the queries again.
5688 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
5689 v6q->qname.c, DNSTypeName(v6q->qtype));
5695 dns_config_t *config = dns_configuration_copy();
5701 dns_configuration_free(config);
5705 LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
5710 mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
5712 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
5713 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
5714 if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver &&
5715 config->resolver[0]->nameserver[0])
5717 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
5721 ActiveDirectoryPrimaryDomain.c[0] = 0;
5724 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
5725 ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
5726 if (config->n_resolver && config->resolver[0]->n_nameserver &&
5727 SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
5729 SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
5733 AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
5734 ActiveDirectoryPrimaryDomainLabelCount = 0;
5735 ActiveDirectoryPrimaryDomainServer = zeroAddr;
5740 mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
5743 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NULL
5746 CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_DynamicDNS);
5751 CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
5752 if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
5754 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
5755 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
5756 if (fqdnDict && DictionaryIsEnabled(fqdnDict))
5758 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
5761 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5762 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
5763 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
5765 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
5772 CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
5773 if (regArray && CFArrayGetCount(regArray) > 0)
5775 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
5776 if (regDict && DictionaryIsEnabled(regDict))
5778 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
5781 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5782 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
5783 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
5786 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
5787 AppendDNameListElem(&RegDomains, 0, &d);
5795 CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
5798 for (i = 0; i < CFArrayGetCount(browseArray); i++)
5800 CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
5801 if (browseDict && DictionaryIsEnabled(browseDict))
5803 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
5806 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5807 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
5808 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
5811 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
5812 AppendDNameListElem(&BrowseDomains, 0, &d);
5819 CFRelease(ddnsdict);
5823 CFDictionaryRef btmm = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BackToMyMac);
5826 CFIndex size = CFDictionaryGetCount(btmm);
5827 const void *key[size];
5828 const void *val[size];
5829 CFDictionaryGetKeysAndValues(btmm, key, val);
5830 for (i = 0; i < size; i++)
5832 LogInfo("BackToMyMac %d", i);
5833 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
5834 LogMsg("Can't read BackToMyMac %d key %s", i, buf);
5837 mDNSu32 uid = atoi(buf);
5838 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
5839 LogMsg("Can't read BackToMyMac %d val %s", i, buf);
5840 else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
5842 LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
5843 AppendDNameListElem(&RegDomains, uid, &d);
5853 // Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
5854 mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
5855 DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
5857 mDNS *const m = &mDNSStorage;
5858 MD5_CTX sdc; // search domain context
5859 static mDNSu16 resolverGroupID = 0;
5861 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
5862 if (fqdn ) fqdn->c[0] = 0;
5863 if (RegDomains ) *RegDomains = NULL;
5864 if (BrowseDomains) *BrowseDomains = NULL;
5866 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
5867 setservers ? " setservers" : "",
5868 setsearch ? " setsearch" : "",
5869 fqdn ? " fqdn" : "",
5870 RegDomains ? " RegDomains" : "",
5871 BrowseDomains ? " BrowseDomains" : "");
5873 if (setsearch) MD5_Init(&sdc);
5875 // Add the inferred address-based configuration discovery domains
5876 // (should really be in core code I think, not platform-specific)
5879 struct ifaddrs *ifa = mDNSNULL;
5880 struct sockaddr_in saddr;
5881 mDNSPlatformMemZero(&saddr, sizeof(saddr));
5882 saddr.sin_len = sizeof(saddr);
5883 saddr.sin_family = AF_INET;
5885 saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
5887 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
5888 if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1);
5895 if (ifa->ifa_addr->sa_family == AF_INET &&
5897 !(ifa->ifa_flags & IFF_LOOPBACK) &&
5898 !SetupAddr(&a, ifa->ifa_addr) &&
5899 !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
5901 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be incorrect, so we explicitly fix it here before calling SetupAddr
5902 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5903 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; // Make sure ifa_netmask->sa_family is set correctly
5904 SetupAddr(&n, ifa->ifa_netmask);
5905 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
5906 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
5907 a.ip.v4.b[2] & n.ip.v4.b[2],
5908 a.ip.v4.b[1] & n.ip.v4.b[1],
5909 a.ip.v4.b[0] & n.ip.v4.b[0]);
5910 UpdateSearchDomainHash(&sdc, buf, NULL);
5911 mDNS_AddSearchDomain_CString(buf, mDNSNULL);
5913 ifa = ifa->ifa_next;
5917 #ifndef MDNS_NO_DNSINFO
5918 if (setservers || setsearch)
5920 dns_config_t *config = dns_configuration_copy();
5923 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
5924 // Apparently this is expected behaviour -- "not a bug".
5925 // Accordingly, we suppress syslog messages for the first three minutes after boot.
5926 // If we are still getting failures after three minutes, then we log them.
5927 if ((mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
5928 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
5932 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config->n_resolver, config->generation, m->p->LastConfigGeneration);
5934 // For every network change, mDNSPlatformSetDNSConfig is called twice. First,
5935 // to update the search domain list (in which case, the setsearch bool is set);
5936 // and second, to update the DNS server list (in which case, the setservers bool
5937 // is set). The code assumes only one of these flags, setsearch or setserver,
5938 // will be set when mDNSPlatformSetDNSConfig is called to handle a network change.
5939 // The mDNSPlatformSetDNSConfig function also assumes that ackCfg will be set
5940 // when setservers is set.
5942 // The search domains update occurs on every network change to avoid sync issues
5943 // that may occur if a network change happens during the processing
5944 // of a network change. The dns servers update occurs when the DNS config
5945 // changes. The dns servers stay in sync by saving the config's generation number
5946 // on every update; and only updating when the generation number changes.
5948 // If this is a DNS server update and the configuration hasn't changed, then skip update
5949 if (setservers && m->p->LastConfigGeneration == config->generation)
5951 LogInfo("mDNSPlatformSetDNSConfig(setservers): generation number %llu same, not processing", config->generation);
5952 dns_configuration_free(config);
5953 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
5956 #if APPLE_OSX_mDNSResponder
5957 SetupActiveDirectoryDomain(config);
5960 // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry
5961 // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need
5962 // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between
5963 // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the
5964 // same resolverGroupID.
5966 // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally.
5967 ConfigResolvers(config, kScopeNone, setsearch, setservers, &sdc, ++resolverGroupID);
5968 resolverGroupID += config->n_resolver;
5970 ConfigResolvers(config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID);
5971 resolverGroupID += config->n_scoped_resolver;
5973 ConfigResolvers(config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID);
5975 // Acking provides a hint to other processes that the current DNS configuration has completed
5976 // its update. When configd receives the ack, it publishes a notification.
5977 // Applications monitoring the notification then know when to re-issue their DNS queries
5978 // after a network change occurs.
5981 // Note: We have to set the generation number here when we are acking.
5982 // For every DNS configuration change, we do the following:
5984 // 1) Copy dns configuration, handle search domains change
5985 // 2) Copy dns configuration, handle dns server change
5987 // If we update the generation number at step (1), we won't process the
5988 // DNS servers the second time because generation number would be the same.
5989 // As we ack only when we process dns servers, we set the generation number
5991 m->p->LastConfigGeneration = config->generation;
5992 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers, setsearch);
5995 dns_configuration_free(config);
5996 if (setsearch) FinalizeSearchDomainHash(&sdc);
5999 #endif // MDNS_NO_DNSINFO
6000 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6005 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
6009 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_IPv4);
6012 r->type = mDNSAddrType_IPv4;
6013 r->ip.v4 = zerov4Addr;
6014 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
6017 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
6018 LogMsg("Could not convert router to CString");
6021 struct sockaddr_in saddr;
6022 saddr.sin_len = sizeof(saddr);
6023 saddr.sin_family = AF_INET;
6025 inet_aton(buf, &saddr.sin_addr);
6026 *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
6029 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
6032 mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
6033 struct ifaddrs *ifa = myGetIfAddrs(1);
6034 *v4 = *v6 = zeroAddr;
6036 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
6038 LogMsg("Could not convert router to CString");
6041 // find primary interface in list
6042 while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
6046 LogMsg("Skip interface, %s, since ifa_addr is not set.", (ifa->ifa_name) ? ifa->ifa_name: "name not found");
6047 ifa = ifa->ifa_next;
6050 mDNSAddr tmp6 = zeroAddr;
6051 if (!strcmp(buf, ifa->ifa_name))
6053 if (ifa->ifa_addr->sa_family == AF_INET)
6055 if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4))
6056 SetupAddr(v4, ifa->ifa_addr);
6058 else if (ifa->ifa_addr->sa_family == AF_INET6)
6060 SetupAddr(&tmp6, ifa->ifa_addr);
6061 if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
6063 HavePrimaryGlobalv6 = mDNStrue;
6070 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
6071 if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
6073 SetupAddr(&tmp6, ifa->ifa_addr);
6074 if (tmp6.ip.v6.b[0] >> 5 == 1)
6078 ifa = ifa->ifa_next;
6080 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
6081 // V4 to communicate w/ our DNS server
6087 return mStatus_NoError;
6090 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
6092 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
6093 char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6094 ConvertDomainNameToCString(dname, uname);
6100 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
6104 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
6105 // That single entity is a CFDictionary with name "HostNames".
6106 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
6107 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
6108 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
6109 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
6110 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
6112 const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
6113 const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
6114 const CFStringRef StatusKeys[1] = { CFSTR("Status") };
6115 if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
6118 const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
6119 if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
6122 const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6125 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6128 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6131 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
6132 CFRelease(StateDict);
6134 CFRelease(StateVals[0]);
6136 CFRelease(HostVals[0]);
6138 CFRelease(StatusVals[0]);
6140 CFRelease(HostKeys[0]);
6144 #if APPLE_OSX_mDNSResponder
6147 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
6148 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
6150 mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
6152 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
6155 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6158 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
6161 CFIndex size = CFDictionaryGetCount(btmm);
6162 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6163 const void *key[size];
6164 const void *val[size];
6167 CFDictionaryGetKeysAndValues(btmm, key, val);
6168 for (i = 0; i < size; i++)
6170 LogInfo("BackToMyMac %d", i);
6171 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6172 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
6175 mDNSu32 uid = atoi(buf);
6176 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6177 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
6178 else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
6180 if (SameDomainName(&dom, d))
6182 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
6193 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
6197 // Appends data to the buffer
6198 mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
6202 len = strlcpy(buf + *currlen, data, bufsz - *currlen);
6203 if (len >= (bufsz - *currlen))
6205 // if we have exceeded the space in buf, it has already been NULL terminated
6206 // and we have nothing more to do. Set currlen to the last byte so that the caller
6207 // knows to do the right thing
6208 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
6209 *currlen = bufsz - 1;
6212 else { (*currlen) += len; }
6214 buf[*currlen] = ',';
6215 if (*currlen >= bufsz)
6217 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
6218 *currlen = bufsz - 1;
6222 // if we have filled up the buffer exactly, then there is no more work to do
6223 if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
6228 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
6229 // BTMM domains, then bring down the connection to the relay.
6230 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6232 DomainAuthInfo *BTMMDomain = mDNSNULL;
6233 DomainAuthInfo *FoundInList;
6234 static mDNSBool AWACSDConnected = mDNSfalse;
6235 char AllUsers[1024]; // maximum size of mach message
6236 char AllPass[1024]; // maximum size of mach message
6237 char username[MAX_DOMAIN_LABEL + 1];
6241 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
6242 // we may not be able to send the dns queries over the relay connection which may be needed
6243 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
6244 // need to make sure that we send the disconnect before attempting the next connect as the
6245 // awacs connections are redirected based on usernames.
6247 // For now we send a disconnect immediately. When we start sending dns queries over the relay
6248 // connection, we will need to fix this.
6250 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6251 if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
6253 // We need the passwd from the first domain.
6254 BTMMDomain = FoundInList;
6255 ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
6256 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
6257 if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
6258 if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
6263 // In the normal case (where we neither exceed the buffer size nor write bytes that
6264 // fit exactly into the buffer), currulen/currplen should be a different size than
6265 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
6267 if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
6268 if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
6270 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
6271 AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
6272 AWACSDConnected = mDNStrue;
6276 // Disconnect only if we connected previously
6277 if (AWACSDConnected)
6279 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
6281 AWACSDConnected = mDNSfalse;
6283 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
6286 #elif !TARGET_OS_EMBEDDED
6287 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6290 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
6292 #endif // ! NO_AWACS
6294 #if !TARGET_OS_EMBEDDED
6295 mDNSlocal void ProcessConndConfigChanges(void);
6298 #endif // APPLE_OSX_mDNSResponder
6300 // MUST be called holding the lock
6301 mDNSlocal void SetDomainSecrets_internal(mDNS *m)
6303 #ifdef NO_SECURITYFRAMEWORK
6305 LogMsg("Note: SetDomainSecrets: no keychain support");
6307 mDNSBool haveAutoTunnels = mDNSfalse;
6309 LogInfo("SetDomainSecrets");
6311 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
6312 // In the case where the user simultaneously removes their DDNS host name and the key
6313 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
6314 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
6315 // address records behind that we no longer have permission to delete.
6316 DomainAuthInfo *ptr;
6317 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
6318 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
6320 #if APPLE_OSX_mDNSResponder
6322 // Mark all TunnelClients for deletion
6323 ClientTunnel *client;
6324 for (client = m->TunnelClients; client; client = client->next)
6326 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
6327 client->MarkedForDeletion = mDNStrue;
6330 #endif // APPLE_OSX_mDNSResponder
6332 // String Array used to write list of private domains to Dynamic Store
6333 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6334 if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
6336 CFDataRef data = NULL;
6337 const int itemsPerEntry = 4; // domain name, key name, key value, Name value
6338 CFArrayRef secrets = NULL;
6339 int err = mDNSKeychainGetSecrets(&secrets);
6340 if (err || !secrets)
6341 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
6344 CFIndex ArrayCount = CFArrayGetCount(secrets);
6345 // Iterate through the secrets
6346 for (i = 0; i < ArrayCount; ++i)
6348 mDNSBool AutoTunnel;
6350 CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
6351 if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
6352 { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i, itemsPerEntry); continue; }
6353 for (j = 0; j < CFArrayGetCount(entry); ++j)
6354 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
6355 { LogMsg("SetDomainSecrets: malformed entry item %d", j); continue; }
6357 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
6359 // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
6360 // Get DNS domain this key is for (kmDNSKcWhere)
6361 char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(btmmprefix)];
6362 data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere);
6363 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6364 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
6365 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6366 stringbuf[CFDataGetLength(data)] = '\0';
6368 AutoTunnel = mDNSfalse;
6370 if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
6371 offset = strlen(dnsprefix);
6372 else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix)))
6374 AutoTunnel = mDNStrue;
6375 offset = strlen(btmmprefix);
6378 if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
6380 // Get key name (kmDNSKcAccount)
6381 data = CFArrayGetValueAtIndex(entry, kmDNSKcAccount);
6382 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6383 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
6384 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
6385 stringbuf[CFDataGetLength(data)] = '\0';
6388 if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
6390 // Get key data (kmDNSKcKey)
6391 data = CFArrayGetValueAtIndex(entry, kmDNSKcKey);
6392 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6394 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data));
6397 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6398 stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
6400 // Get the Name of the keychain entry (kmDNSKcName) host or host:port
6401 // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
6402 char hostbuf[MAX_ESCAPED_DOMAIN_NAME + 6]; // Max legal domainname as C-string, including terminating NUL
6403 data = CFArrayGetValueAtIndex(entry, kmDNSKcName);
6404 if (CFDataGetLength(data) >= (int)sizeof(hostbuf))
6406 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data));
6409 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)hostbuf);
6410 hostbuf[CFDataGetLength(data)] = '\0';
6412 domainname hostname;
6415 hptr = strchr(hostbuf, ':');
6417 port.NotAnInteger = 0;
6424 while(hptr && *hptr != 0)
6426 if (*hptr < '0' || *hptr > '9')
6427 { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr, val); val = 0; break;}
6428 val = val * 10 + *hptr - '0';
6433 port.NotAnInteger = p[0] << 8 | p[1];
6435 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
6436 hptr = strchr(hostbuf, '@');
6441 if (!MakeDomainNameFromDNSNameString(&hostname, hptr)) { LogMsg("SetDomainSecrets: bad host name %s", hptr); continue; }
6443 DomainAuthInfo *FoundInList;
6444 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6445 if (SameDomainName(&FoundInList->domain, &domain)) break;
6447 #if APPLE_OSX_mDNSResponder
6450 // If any client tunnel destination is in this domain, set deletion flag to false
6451 ClientTunnel *client;
6452 for (client = m->TunnelClients; client; client = client->next)
6453 if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
6455 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
6456 client->MarkedForDeletion = mDNSfalse;
6460 #endif // APPLE_OSX_mDNSResponder
6462 // Uncomment the line below to view the keys as they're read out of the system keychain
6463 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
6464 //LogInfo("SetDomainSecrets: domain %##s keyname %##s key %s hostname %##s port %d", &domain.c, &keyname.c, stringbuf, hostname.c, (port.b[0] << 8 | port.b[1]));
6465 LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain.c, &keyname.c, hostname.c, (port.b[0] << 8 | port.b[1]));
6467 // If didn't find desired domain in the list, make a new entry
6469 if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
6472 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
6473 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
6476 //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
6478 // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
6479 if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port, AutoTunnel) == mStatus_BadParamErr)
6481 if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
6485 ConvertDomainNameToCString(&domain, stringbuf);
6486 CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
6487 if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
6492 if (!privateDnsArray || !CFEqual(privateDnsArray, sa))
6494 if (privateDnsArray)
6495 CFRelease(privateDnsArray);
6497 privateDnsArray = sa;
6498 CFRetain(privateDnsArray);
6499 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
6503 #if APPLE_OSX_mDNSResponder
6505 // clean up ClientTunnels
6506 ClientTunnel **pp = &m->TunnelClients;
6509 if ((*pp)->MarkedForDeletion)
6511 ClientTunnel *cur = *pp;
6512 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
6513 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
6514 AutoTunnelSetKeys(cur, mDNSfalse);
6516 freeL("ClientTunnel", cur);
6522 mDNSBool needAutoTunnelNAT = mDNSfalse;
6523 DomainAuthInfo *info;
6524 for (info = m->AuthInfoList; info; info = info->next)
6526 if (info->AutoTunnel)
6528 UpdateAutoTunnelDeviceInfoRecord(m, info);
6529 UpdateAutoTunnelHostRecord(m, info);
6530 UpdateAutoTunnelServiceRecords(m, info);
6531 UpdateAutoTunnel6Record(m, info);
6534 if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse;
6536 else if (info->AutoTunnelServiceStarted)
6537 needAutoTunnelNAT = true;
6539 UpdateAutoTunnelDomainStatus(info);
6543 // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
6544 if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext)
6546 // stop the NAT operation, reset port, cleanup state
6547 mDNS_StopNATOperation_internal(m, &m->AutoTunnelNAT);
6548 m->AutoTunnelNAT.ExternalAddress = zerov4Addr;
6549 m->AutoTunnelNAT.NewAddress = zerov4Addr;
6550 m->AutoTunnelNAT.ExternalPort = zeroIPPort;
6551 m->AutoTunnelNAT.RequestedPort = zeroIPPort;
6552 m->AutoTunnelNAT.Lifetime = 0;
6553 m->AutoTunnelNAT.Result = mStatus_NoError;
6554 m->AutoTunnelNAT.clientContext = mDNSNULL;
6557 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
6558 ProcessConndConfigChanges(); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
6560 #endif // APPLE_OSX_mDNSResponder
6562 CheckSuppressUnusableQuestions(m);
6564 #endif /* NO_SECURITYFRAMEWORK */
6567 mDNSexport void SetDomainSecrets(mDNS *m)
6570 // Don't get secrets for BTMM if running in debug mode
6571 if (!IsDebugSocketInUse())
6573 SetDomainSecrets_internal(m);
6576 mDNSlocal void SetLocalDomains(void)
6578 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6579 if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
6581 CFArrayAppendValue(sa, CFSTR("local"));
6582 CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
6583 CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
6584 CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
6585 CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
6586 CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
6588 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
6592 mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
6595 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_PowerSettings);
6598 LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
6602 CFNumberRef number = CFDictionaryGetValue(dict, name);
6603 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
6610 #if APPLE_OSX_mDNSResponder
6612 static CFMutableDictionaryRef spsStatusDict = NULL;
6613 static const CFStringRef kMetricRef = CFSTR("Metric");
6615 mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
6617 mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
6618 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
6620 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
6623 CFDictionarySetValue(dict, key, num);
6628 mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
6630 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6631 if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
6634 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
6635 CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
6636 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
6637 CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
6640 if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
6641 if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
6642 if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
6643 if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
6645 mDNSu32 tmp = SPSMetric(ptr);
6646 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
6648 LogMsg("SPSCreateDict: Could not create CFNumber");
6651 CFDictionarySetValue(dict, kMetricRef, num);
6657 memcpy(buffer, ptr + 13, ptr[0] - 12);
6658 buffer[ptr[0] - 12] = 0;
6659 spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
6660 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
6663 CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
6671 mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
6674 return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
6675 (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
6679 mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
6681 NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
6682 debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
6685 mDNS_UpdateAllowSleep(m);
6688 if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names
6692 spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6693 if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
6696 CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
6697 if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
6699 CFMutableArrayRef array = NULL;
6701 if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
6703 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6704 if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
6705 CFDictionarySetValue(spsStatusDict, ifname, array);
6706 CFRelease(array); // let go of our reference, now that the dict has one
6709 if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
6711 if (!answer) // special call that means the question has been stopped (because the interface is going away)
6712 CFArrayRemoveAllValues(array);
6715 CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
6716 if (!dict) { CFRelease(ifname); return; }
6720 if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
6723 for (i=0; i<CFArrayGetCount(array); i++)
6724 if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
6726 CFArrayInsertValueAtIndex(array, i, dict);
6728 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
6732 CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
6733 if (i != -1) CFArrayRemoveValueAtIndex(array, i);
6734 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
6740 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
6745 mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
6748 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
6750 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6753 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
6756 CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
6757 if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
6765 mDNSlocal void SetSPS(mDNS *const m)
6768 // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
6769 mDNSu8 sps = (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware : 0;
6771 // For devices that are not running NAT, but are set to never sleep, we may choose to act
6772 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
6773 //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
6775 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
6777 // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
6778 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
6779 // We rate such a device as metric 70 ("Incidentally Available Hardware")
6780 if (SPMetricMarginalPower <= 60 && !sps) sps = mDNSSleepProxyMetric_IncidentalHardware;
6782 // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
6783 // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
6784 if (sps && OfferSleepProxyService && OfferSleepProxyService < 100) sps = OfferSleepProxyService;
6786 #ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI
6787 // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active.
6790 NetworkInterfaceInfo *intf = mDNSNULL;
6791 mDNSEthAddr bssid = zeroEthAddr;
6792 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
6794 if (intf->InterfaceID == AWDLInterfaceID) continue;
6795 bssid = GetBSSID(intf->ifname);
6796 if (!mDNSSameEthAddress(&bssid, &zeroEthAddr))
6798 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
6804 #endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI
6806 mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
6809 // The definitions below should eventually come from some externally-supplied header file.
6810 // However, since these definitions can't really be changed without breaking binary compatibility,
6811 // they should never change, so in practice it should not be a big problem to have them defined here.
6814 { // commands from the daemon to the driver
6815 cmd_mDNSOffloadRR = 21, // give the mdns update buffer to the driver
6818 typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr;
6821 { // cmd_mDNSOffloadRR structure
6822 uint32_t command; // set to OffloadRR
6823 uint32_t rrBufferSize; // number of bytes of RR records
6824 uint32_t numUDPPorts; // number of SRV UDP ports
6825 uint32_t numTCPPorts; // number of SRV TCP ports
6826 uint32_t numRRRecords; // number of RR records
6827 uint32_t compression; // rrRecords - compression is base for compressed strings
6828 FatPtr rrRecords; // address of array of pointers to the rr records
6829 FatPtr udpPorts; // address of udp port list (SRV)
6830 FatPtr tcpPorts; // address of tcp port list (SRV)
6833 #include <IOKit/IOKitLib.h>
6834 #include <dns_util.h>
6836 mDNSlocal mDNSu16 GetPortArray(int trans, mDNSIPPort *portarray)
6838 mDNS *const m = &mDNSStorage;
6839 const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
6843 for (rr = m->ResourceRecords; rr; rr=rr->next)
6845 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c))
6852 for (i = 0; i < count; i++)
6853 if (mDNSSameIPPort(portarray[i], rr->resrec.rdata->u.srv.port))
6856 // Add it into the port list only if it not already present in the list
6858 portarray[count++] = rr->resrec.rdata->u.srv.port;
6863 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
6864 if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext)
6866 LogSPS("GetPortArray Back to My Mac at %d", count);
6867 if (portarray) portarray[count] = IPSECPort;
6873 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6874 mDNSlocal mDNSBool SupportsTCPKeepAlive()
6876 IOReturn ret = kIOReturnSuccess;
6877 CFTypeRef obj = NULL;
6878 mDNSBool supports = mDNSfalse;
6880 ret = IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj);
6881 if ((kIOReturnSuccess == ret) && (obj != NULL))
6883 supports = (obj == kCFBooleanTrue)? mDNStrue : mDNSfalse;
6886 LogSPS("%s: The hardware %s TCP Keep Alive", __func__, (supports ? "supports" : "does not support"));
6890 mDNSlocal mDNSBool OnBattery(void)
6892 CFTypeRef powerInfo = IOPSCopyPowerSourcesInfo();
6893 CFTypeRef powerSrc = IOPSGetProvidingPowerSourceType(powerInfo);
6894 mDNSBool result = mDNSfalse;
6896 if (powerInfo != NULL)
6898 result = CFEqual(CFSTR(kIOPSBatteryPowerValue), powerSrc);
6899 CFRelease(powerInfo);
6901 LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
6905 #endif // !TARGET_OS_EMBEDDED
6907 #define TfrRecordToNIC(RR) \
6908 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
6910 mDNSlocal mDNSu32 CountProxyRecords(uint32_t *const numbytes, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
6912 mDNS *const m = &mDNSStorage;
6918 for (rr = m->ResourceRecords; rr; rr=rr->next)
6920 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
6922 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6923 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
6924 // Skip over all other records if we are registering TCP KeepAlive records only
6925 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
6926 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
6929 // Update the record before calculating the number of bytes required
6930 // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
6931 // attempt to update the record again.
6932 if (isKeepAliveRecord && (UpdateKeepaliveRData(m, rr, intf, mDNSfalse, mDNSNULL) != mStatus_NoError))
6933 LogSPS("CountProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m, rr));
6935 // Offload only Valid Keepalive records
6936 if (isKeepAliveRecord && !mDNSValidKeepAliveRecord(rr))
6939 (void) TCPKAOnly; // unused
6940 (void) supportsTCPKA; // unused
6941 (void) intf; // unused
6942 #endif // APPLE_OSX_mDNSResponder
6943 if (TfrRecordToNIC(rr))
6945 *numbytes += DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate;
6946 LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
6947 count, DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate, *numbytes, ARDisplayString(m,rr));
6955 mDNSlocal void GetProxyRecords(DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
6957 mDNS *const m = &mDNSStorage;
6958 mDNSu8 *p = msg->data;
6959 const mDNSu8 *const limit = p + *numbytes;
6960 InitializeDNSMessage(&msg->h, zeroID, zeroID);
6965 for (rr = m->ResourceRecords; rr; rr=rr->next)
6967 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
6969 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6970 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
6972 // Skip over all other records if we are registering TCP KeepAlive records only
6973 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
6974 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
6977 // Offload only Valid Keepalive records
6978 if (isKeepAliveRecord && !mDNSValidKeepAliveRecord(rr))
6981 (void) TCPKAOnly; // unused
6982 (void) supportsTCPKA; // unused
6983 #endif // APPLE_OSX_mDNSResponder
6985 if (TfrRecordToNIC(rr))
6987 records[count].sixtyfourbits = zeroOpaque64;
6988 records[count].ptr = p;
6989 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
6990 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it
6991 p = PutResourceRecordTTLWithLimit(msg, p, &msg->h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
6992 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state
6993 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
6994 count, records[count].ptr, p, p - (mDNSu8 *)records[count].ptr, p - msg->data, ARDisplayString(m,rr));
6999 *numbytes = p - msg->data;
7002 mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf)
7004 if(!UseInternalSleepProxy)
7006 LogMsg("SupportsInNICProxy: Internal Sleep Proxy is disabled");
7009 return CheckInterfaceSupport(intf, mDNS_IOREG_KEY);
7012 mDNSexport mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool *keepaliveOnly) // Called with the lock held
7014 mStatus result = mStatus_UnknownErr;
7015 mDNSBool TCPKAOnly = mDNSfalse;
7016 mDNSBool supportsTCPKA = mDNSfalse;
7017 mDNSBool onbattery = mDNSfalse;
7018 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
7020 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7021 onbattery = OnBattery();
7022 // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
7023 supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive());
7025 // Only TCP Keepalive records are to be offloaded if
7026 // - The system is on battery
7027 // - OR wake for network access is not set but powernap is enabled
7028 TCPKAOnly = supportsTCPKA && ((mDNSStorage.SystemWakeOnLANEnabled == mDNS_WakeOnBattery) || onbattery);
7030 (void) onbattery; // unused;
7032 if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", intf->ifname); return(mStatus_UnknownErr); }
7035 IOObjectGetClass(service, n1);
7036 io_object_t parent = IO_OBJECT_NULL;
7038 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
7039 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
7042 CFTypeRef ref = mDNSNULL;
7047 ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
7050 IOObjectRelease(service);
7052 kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
7053 if (kr != KERN_SUCCESS)
7055 IOObjectGetClass(service, n1);
7056 LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
7057 parent = IO_OBJECT_NULL;
7058 result = mStatus_BadStateErr;
7064 IOObjectGetClass(parent, n2);
7065 LogSPS("ActivateLocalProxy: Found %s Interface %s parent %s", mDNS_IOREG_KEY, intf->ifname, n2);
7072 IOObjectGetClass(parent, n2);
7073 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf->ifname, n1, n2);
7074 ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
7077 if (!ref || parent == IO_OBJECT_NULL) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
7080 if (CFGetTypeID(ref) != CFStringGetTypeID() || !CFEqual(ref, CFSTR(mDNS_IOREG_VALUE)))
7081 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
7082 intf->ifname, n1, n2, CFStringGetCStringPtr(ref, mDNSNULL), mDNS_IOREG_VALUE);
7083 else if (!UseInternalSleepProxy)
7084 LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf->ifname);
7087 io_connect_t conObj;
7088 kr = IOServiceOpen(parent, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE, &conObj);
7089 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf->ifname, n1, n2, kr);
7093 mDNSPlatformMemZero(&cmd, sizeof(cmd)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
7094 cmd.command = cmd_mDNSOffloadRR;
7095 cmd.numUDPPorts = GetPortArray(mDNSTransport_UDP, mDNSNULL);
7096 cmd.numTCPPorts = GetPortArray(mDNSTransport_TCP, mDNSNULL);
7097 cmd.numRRRecords = CountProxyRecords(&cmd.rrBufferSize, intf, TCPKAOnly, supportsTCPKA);
7098 cmd.compression = sizeof(DNSMessageHeader);
7100 DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
7101 cmd.rrRecords.ptr = cmd.numRRRecords ? mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr)) : NULL;
7102 cmd.udpPorts.ptr = cmd.numUDPPorts ? mallocL("mDNSOffloadCmd udpPorts" , cmd.numUDPPorts * sizeof(mDNSIPPort)) : NULL;
7103 cmd.tcpPorts.ptr = cmd.numTCPPorts ? mallocL("mDNSOffloadCmd tcpPorts" , cmd.numTCPPorts * sizeof(mDNSIPPort)) : NULL;
7105 LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
7106 msg, cmd.rrBufferSize,
7107 cmd.rrRecords.ptr, cmd.numRRRecords,
7108 cmd.udpPorts.ptr, cmd.numUDPPorts,
7109 cmd.tcpPorts.ptr, cmd.numTCPPorts);
7111 if (msg && cmd.rrRecords.ptr) GetProxyRecords(msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA);
7112 if (cmd.udpPorts.ptr) cmd.numUDPPorts = GetPortArray(mDNSTransport_UDP, cmd.udpPorts.ptr);
7113 if (cmd.tcpPorts.ptr) cmd.numTCPPorts = GetPortArray(mDNSTransport_TCP, cmd.tcpPorts.ptr);
7116 size_t outputDataSize = sizeof(outputData);
7117 kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize);
7118 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr);
7119 if (kr == KERN_SUCCESS) result = mStatus_NoError;
7121 if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts.ptr);
7122 if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts.ptr);
7123 if (cmd.rrRecords.ptr) freeL("mDNSOffloadCmd rrRecords", cmd.rrRecords.ptr);
7124 if (msg) freeL("mDNSOffloadCmd msg", msg);
7125 IOServiceClose(conObj);
7130 if (parent != IO_OBJECT_NULL) IOObjectRelease(parent);
7132 if (service != IO_OBJECT_NULL) IOObjectRelease(service);
7133 *keepaliveOnly = TCPKAOnly;
7137 #endif // APPLE_OSX_mDNSResponder
7139 mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
7142 mDNSu8 ret = (mDNSu8)mDNS_NoWake;
7145 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7149 if (DisableSleepProxyClient)
7151 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7155 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
7157 ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
7159 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7160 // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
7161 // Further policy decisions on whether to offload the records is handled during sleep processing.
7162 if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive())
7163 ret = (mDNSu8)mDNS_WakeOnBattery;
7164 #endif // APPLE_OSX_mDNSResponder
7166 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret);
7170 mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
7173 // PrioritizeNetworkReachabilityOverSleep has been deprecated.
7174 // GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
7175 // Statically set the PrioritizeNetworkReachabilityOverSleep value to 1 for AppleTV
7178 return val != 0 ? mDNStrue : mDNSfalse;
7182 #if APPLE_OSX_mDNSResponder
7183 // When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
7184 // gets deregistered, so that older peers are forced to connect over direct UDP instead of
7187 // When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
7188 // service records are deregistered, so they do not appear in peers' Finder sidebars.
7189 // We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
7190 // depend on their associated SRV record and therefore will be deregistered together in a
7191 // single update with the SRV record.
7193 // Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
7194 // its presence shouldn't delay sleep.
7196 // Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
7197 // relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
7199 // Also note that returning false here will not delay sleep past the maximum of 10 seconds.
7200 mDNSexport mDNSBool RecordReadyForSleep(AuthRecord *rr)
7202 mDNS *const m = &mDNSStorage;
7203 if (!AuthRecord_uDNS(rr)) return mDNStrue;
7205 if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
7207 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7211 if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result))
7213 if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone
7214 && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel"))
7216 DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
7217 if (info && info->AutoTunnel)
7219 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7228 // Caller must hold the lock
7229 mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
7231 DomainAuthInfo *info;
7232 // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
7233 // deregister the record, and the MemFree callback won't re-register.
7234 m->AutoTunnelRelayAddr = zerov6Addr;
7235 for (info = m->AuthInfoList; info; info = info->next)
7236 if (info->AutoTunnel)
7237 UpdateAutoTunnel6Record(m, info);
7240 #if !TARGET_OS_EMBEDDED
7241 mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname)
7243 struct ifaddrs *ifa;
7244 struct ifaddrs *ifaddrs;
7247 if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;}
7249 if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;}
7251 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
7253 if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
7255 if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
7257 if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
7259 LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
7262 if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6))
7264 LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr);
7268 freeifaddrs(ifaddrs);
7272 mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf)
7275 struct addrinfo hints;
7276 struct addrinfo *res0;
7278 memset(&hints, 0, sizeof(hints));
7279 hints.ai_family = AF_INET6;
7280 hints.ai_flags = AI_NUMERICHOST;
7282 int err = getaddrinfo(buf, NULL, &hints, &res0);
7286 retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr;
7293 mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict()
7295 CFDictionaryRef connd = NULL;
7296 CFDictionaryRef BTMMDict = NULL;
7298 connd = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BTMMConnectivity);
7301 LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
7305 BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
7308 LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
7312 // Non-dictionary is treated as non-existent dictionary
7313 if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
7316 LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
7323 if (connd) CFRelease(connd);
7328 #define MAX_IPV6_TEXTUAL 40
7330 mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey)
7332 mDNSv6Addr retVal = zerov6Addr;
7333 CFTypeRef string = NULL;
7334 char ifname[IFNAMSIZ];
7335 char address[MAX_IPV6_TEXTUAL];
7340 if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string))
7342 LogInfo("ParseBackToMyMacAddr: interface key does not exist");
7346 if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8))
7348 LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
7352 if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string))
7354 LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
7358 if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8))
7360 LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
7364 retVal = IPv6AddressFromString(address);
7365 LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal);
7367 if (mDNSIPv6AddressIsZero(retVal))
7370 if (!IPv6AddressIsOnInterface(retVal, ifname))
7372 LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname);
7379 mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict)
7381 CFTypeRef zones = NULL;
7386 if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones))
7388 LogInfo("CopyBTMMZones: Zones key does not exist");
7395 mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info)
7397 mDNSv6Addr addr = zerov6Addr;
7398 char buffer[MAX_ESCAPED_DOMAIN_NAME];
7399 CFStringRef domain = NULL;
7400 CFTypeRef theZone = NULL;
7405 ConvertDomainNameToCString(&info->domain, buffer);
7406 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
7410 if (CFDictionaryGetValueIfPresent(zones, domain, &theZone))
7411 addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address"));
7418 mDNSlocal void SetupBackToMyMacInnerAddresses(CFDictionaryRef BTMMDict)
7420 mDNS *const m = &mDNSStorage;
7421 DomainAuthInfo* info;
7422 CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
7425 for (info = m->AuthInfoList; info; info = info->next)
7427 if (!info->AutoTunnel)
7430 newAddr = ParseBackToMyMacZone(zones, info);
7432 if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress))
7435 info->AutoTunnelInnerAddress = newAddr;
7436 DeregisterAutoTunnelHostRecord(m, info);
7437 UpdateAutoTunnelHostRecord(m, info);
7438 UpdateAutoTunnelDomainStatus(info);
7442 // MUST be called holding the lock
7443 mDNSlocal void ProcessConndConfigChanges(void)
7445 mDNS *const m = &mDNSStorage;
7446 CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
7448 LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
7449 mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
7451 LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
7453 SetupBackToMyMacInnerAddresses(dict);
7455 if (dict) CFRelease(dict);
7457 if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr))
7459 m->AutoTunnelRelayAddr = relayAddr;
7461 DomainAuthInfo* info;
7462 for (info = m->AuthInfoList; info; info = info->next)
7463 if (info->AutoTunnel)
7465 DeregisterAutoTunnel6Record(m, info);
7466 UpdateAutoTunnel6Record(m, info);
7467 UpdateAutoTunnelDomainStatus(info);
7470 // Determine whether we need racoon to accept incoming connections
7471 UpdateAnonymousRacoonConfig(m);
7474 // If awacsd crashes or exits for some reason, restart it
7475 UpdateBTMMRelayConnection(m);
7477 #endif // !TARGET_OS_EMBEDDED
7478 #endif /* APPLE_OSX_mDNSResponder */
7480 mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
7483 // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
7484 for (s = m->DNSServers; s; s = s->next)
7486 if (s->addr.ip.v4.b[0] == 17)
7488 LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s->domain.c, &s->addr);
7495 // Called with KQueueLock & mDNS lock
7496 // SetNetworkChanged is allowed to shorten (but not extend) the pause while we wait for configuration changes to settle
7497 mDNSlocal void SetNetworkChanged(mDNSs32 delay)
7499 mDNS *const m = &mDNSStorage;
7501 if (!m->NetworkChanged || m->NetworkChanged - NonZeroTime(m->timenow + delay) > 0)
7503 m->NetworkChanged = NonZeroTime(m->timenow + delay);
7504 LogInfo("SetNetworkChanged: Scheduling in %d ticks", delay);
7507 LogInfo("SetNetworkChanged: *NOT* increasing delay from %d to %d", m->NetworkChanged - m->timenow, delay);
7510 // Called with KQueueLock & mDNS lock
7511 mDNSlocal void SetKeyChainTimer(mDNSs32 delay)
7513 mDNS *const m = &mDNSStorage;
7514 // If it's not set or it needs to happen sooner than when it's currently set
7515 if (!m->p->KeyChainTimer || m->p->KeyChainTimer - NonZeroTime(m->timenow + delay) > 0)
7517 m->p->KeyChainTimer = NonZeroTime(m->timenow + delay);
7518 LogInfo("SetKeyChainTimer: %d", delay);
7522 mDNSexport void mDNSMacOSXNetworkChanged(void)
7524 mDNS *const m = &mDNSStorage;
7525 LogInfo("*** Network Configuration Change *** %d ticks late%s",
7526 m->NetworkChanged ? mDNS_TimeNow(m) - m->NetworkChanged : 0,
7527 m->NetworkChanged ? "" : " (no scheduled configuration change)");
7528 m->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
7530 // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring
7531 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
7534 mDNSBool tentative = mDNSfalse;
7535 struct ifaddrs *ifa = myGetIfAddrs(1);
7538 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6)
7540 struct in6_ifreq ifr6;
7541 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
7542 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
7543 ifr6.ifr_addr = *(struct sockaddr_in6 *)ifa->ifa_addr;
7544 // We need to check for IN6_IFF_TENTATIVE here, not IN6_IFF_NOTREADY, because
7545 // IN6_IFF_NOTREADY includes both IN6_IFF_TENTATIVE and IN6_IFF_DUPLICATED addresses.
7546 // We can expect that an IN6_IFF_TENTATIVE address will shortly become ready,
7547 // but an IN6_IFF_DUPLICATED address may not.
7548 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
7550 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
7552 LogInfo("*** Network Configuration Change *** IPv6 address %.16a TENTATIVE, will retry", &ifr6.ifr_addr.sin6_addr);
7553 tentative = mDNStrue;
7554 // no need to check other interfaces if we already found out that one interface is TENTATIVE
7559 ifa = ifa->ifa_next;
7565 SetNetworkChanged(mDNSPlatformOneSecond / 2);
7569 LogInfo("*** Network Configuration Change *** No IPv6 address TENTATIVE, will continue");
7572 mDNSs32 utc = mDNSPlatformUTC();
7573 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
7574 m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
7575 MarkAllInterfacesInactive(utc);
7576 UpdateInterfaceList(utc);
7577 ClearInactiveInterfaces(utc);
7578 SetupActiveInterfaces(utc);
7579 ReorderInterfaceList();
7581 #if APPLE_OSX_mDNSResponder
7582 #if !TARGET_OS_EMBEDDED
7584 ProcessConndConfigChanges();
7587 // Scan to find client tunnels whose questions have completed,
7588 // but whose local inner/outer addresses have changed since the tunnel was set up
7590 for (p = m->TunnelClients; p; p = p->next)
7591 if (p->q.ThisQInterval < 0)
7593 DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname);
7596 LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c);
7597 AutoTunnelSetKeys(p, mDNSfalse);
7601 mDNSv6Addr inner = info->AutoTunnelInnerAddress;
7603 if (!mDNSIPPortIsZero(p->rmt_outer_port))
7605 mDNSAddr tmpSrc = zeroAddr;
7606 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
7607 tmpDst.ip.v4 = p->rmt_outer;
7608 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
7609 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7610 !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
7612 AutoTunnelSetKeys(p, mDNSfalse);
7613 p->loc_inner = inner;
7614 p->loc_outer = tmpSrc.ip.v4;
7615 AutoTunnelSetKeys(p, mDNStrue);
7620 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7621 !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
7623 AutoTunnelSetKeys(p, mDNSfalse);
7624 p->loc_inner = inner;
7625 p->loc_outer6 = m->AutoTunnelRelayAddr;
7626 AutoTunnelSetKeys(p, mDNStrue);
7631 #endif //!TARGET_OS_EMBEDDED
7635 NetworkInterfaceInfoOSX *i;
7636 for (i = m->p->InterfaceList; i; i = i->next)
7638 if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
7640 if (i->BPF_fd >= 0 && CountProxyTargets(i, mDNSNULL, mDNSNULL) == 0)
7643 else // else, we're Sleep Proxy Server; open BPF fds
7645 if (i->Exists && (i->Registered == i) && SPSInterface(i) && i->BPF_fd == -1)
7647 LogMsg("%s mDNSMacOSXNetworkChanged: requesting BPF", i->ifinfo.ifname);
7654 #endif // APPLE_OSX_mDNSResponder
7656 uDNS_SetupDNSConfig(m);
7657 mDNS_ConfigChanged(m);
7659 if (IsAppleNetwork(m) != mDNS_McastTracingEnabled)
7661 mDNS_McastTracingEnabled = mDNS_McastTracingEnabled ? mDNSfalse : mDNStrue;
7662 LogInfo("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
7668 // Copy the fourth slash-delimited element from either:
7669 // State:/Network/Interface/<bsdname>/IPv4
7671 // Setup:/Network/Service/<servicename>/Interface
7672 mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
7675 CFStringRef name = NULL;
7677 a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
7678 if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
7679 if (a != NULL) CFRelease(a);
7684 // Whether a key from a network change notification corresponds to
7685 // an IP service that is explicitly configured for IPv4 Link Local
7686 mDNSlocal int ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
7688 CFDictionaryRef dict = NULL;
7689 CFMutableArrayRef a;
7690 const void **keys = NULL, **vals = NULL;
7691 CFStringRef pattern = NULL;
7695 jc = CFArrayGetCount(inkeys);
7698 a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7699 if (a == NULL) goto done;
7701 // Setup:/Network/Service/[^/]+/Interface
7702 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
7703 if (pattern == NULL) goto done;
7704 CFArrayAppendValue(a, pattern);
7707 // Setup:/Network/Service/[^/]+/IPv4
7708 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
7709 if (pattern == NULL) goto done;
7710 CFArrayAppendValue(a, pattern);
7713 dict = SCDynamicStoreCopyMultiple(NULL, NULL, a);
7718 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
7722 ic = CFDictionaryGetCount(dict);
7723 vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7724 keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7725 CFDictionaryGetKeysAndValues(dict, keys, vals);
7727 // For each key we were given...
7728 for (j = 0; j < jc; j++)
7730 CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
7731 CFStringRef ifname = NULL;
7735 // It would be nice to use a regex here
7736 if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
7738 if ((ifname = CopyNameFromKey(key)) == NULL) continue;
7739 if (mDNS_LoggingEnabled)
7741 if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7742 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
7745 // Loop over the interfaces to find matching the ifname, and see if that one has kSCValNetIPv4ConfigMethodLinkLocal
7746 for (i = 0; i < ic; i++)
7748 CFDictionaryRef ipv4dict;
7750 CFStringRef serviceid;
7751 CFStringRef configmethod;
7753 if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
7755 if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
7757 if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
7759 if (!CFEqual(ifname, name)) continue;
7761 if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
7762 if (mDNS_LoggingEnabled)
7764 if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7765 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
7768 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
7769 CFRelease(serviceid);
7770 if (pattern == NULL) continue;
7772 ipv4dict = CFDictionaryGetValue(dict, pattern);
7774 if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
7776 configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
7777 if (!configmethod) continue;
7779 if (mDNS_LoggingEnabled)
7781 if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7782 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
7785 if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found++; break; }
7792 if (vals != NULL) mDNSPlatformMemFree(vals);
7793 if (keys != NULL) mDNSPlatformMemFree(keys);
7794 if (dict != NULL) CFRelease(dict);
7799 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
7801 (void)store; // Parameter not used
7802 mDNS *const m = (mDNS *const)context;
7806 //mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
7807 const mDNSs32 delay = (mDNSPlatformOneSecond + 39) / 40; // 25 ms delay
7809 int c = CFArrayGetCount(changedKeys); // Count changes
7810 CFRange range = { 0, c };
7811 int c_host = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
7812 int c_comp = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
7813 int c_udns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0);
7814 int c_ddns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
7815 int c_btmm = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac ) != 0);
7816 int c_v4ll = ChangedKeysHaveIPv4LL(changedKeys);
7819 // Do immediate network changed processing for "p2p*" interfaces and
7820 // for interfaces with the IFEF_DIRECTLINK or IFEF_AWDL flag set or association with a CarPlay
7825 for (int i = 0; i < c; i++)
7827 CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i);
7829 // Only look at keys with prefix "State:/Network/Interface/"
7830 if (!CFStringHasPrefix(key, NetworkChangedKey_StateInterfacePrefix))
7833 // And suffix "IPv6" or "IPv4".
7834 if (!CFStringHasSuffix(key, kSCEntNetIPv6) && !CFStringHasSuffix(key, kSCEntNetIPv4))
7837 labels = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
7840 n = CFArrayGetCount(labels);
7842 // Interface changes will have keys of the form:
7843 // State:/Network/Interface/<interfaceName>/IPv6
7844 // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
7849 // The 4th label (index = 3) should be the interface name.
7850 if (CFStringGetCString(CFArrayGetValueAtIndex(labels, 3), buf, sizeof(buf), kCFStringEncodingUTF8)
7851 && (strstr(buf, "p2p") || (getExtendedFlags(buf) & (IFEF_DIRECTLINK | IFEF_AWDL)) || IsCarPlaySSID(buf)))
7853 LogInfo("NetworkChanged: interface %s qualifies for reduced change handling delay", buf);
7863 //if (c && c - c_host - c_comp - c_udns - c_ddns - c_btmm - c_v4ll - c_fast == 0)
7864 // delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
7866 if (mDNS_LoggingEnabled)
7872 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7873 LogInfo("*** Network Configuration Change *** SC key: %s", buf);
7875 LogInfo("*** Network Configuration Change *** %d change%s %s%s%s%s%s%s%sdelay %d%s",
7877 c_host ? "(Local Hostname) " : "",
7878 c_comp ? "(Computer Name) " : "",
7879 c_udns ? "(DNS) " : "",
7880 c_ddns ? "(DynamicDNS) " : "",
7881 c_btmm ? "(BTMM) " : "",
7882 c_v4ll ? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
7883 c_fast ? "(P2P/IFEF_DIRECTLINK/IFEF_AWDL/IsCarPlaySSID) " : "",
7885 (c_ddns || c_btmm) ? " + SetKeyChainTimer" : "");
7888 SetNetworkChanged(delay);
7890 // Other software might pick up these changes to register or browse in WAB or BTMM domains,
7891 // so in order for secure updates to be made to the server, make sure to read the keychain and
7892 // setup the DomainAuthInfo before handing the network change.
7893 // If we don't, then we will first try to register services in the clear, then later setup the
7894 // DomainAuthInfo, which is incorrect.
7895 if (c_ddns || c_btmm)
7896 SetKeyChainTimer(delay);
7898 // Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
7901 KQueueUnlock("NetworkChanged");
7904 #if APPLE_OSX_mDNSResponder
7905 mDNSlocal void RefreshSPSStatus(const void *key, const void *value, void *context)
7910 CFStringRef ifnameStr = (CFStringRef)key;
7911 CFArrayRef array = (CFArrayRef)value;
7912 if (!CFStringGetCString(ifnameStr, buf, sizeof(buf), kCFStringEncodingUTF8))
7915 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf, CFArrayGetCount(array));
7916 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, buf, value);
7920 mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
7922 mDNS *const m = (mDNS *const)info;
7925 KQueueLock(); // serialize with KQueueLoop()
7927 LogInfo("DynamicStoreReconnected: Reconnected");
7929 // State:/Network/MulticastDNS
7932 // State:/Network/DynamicDNS
7934 mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
7936 // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
7937 // as we receive network change notifications and thus not necessary. But we leave it here
7938 // so that if things are done differently in the future, this code still works.
7940 // State:/Network/PrivateDNS
7941 if (privateDnsArray)
7942 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
7944 #if APPLE_OSX_mDNSResponder
7945 // State:/Network/BackToMyMac
7946 UpdateAutoTunnelDomainStatuses(m);
7948 // State:/Network/Interface/en0/SleepProxyServers
7950 CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
7952 KQueueUnlock("DynamicStoreReconnected");
7955 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
7958 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
7959 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
7960 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7961 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
7962 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
7963 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7965 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
7966 if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
7968 CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
7969 CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
7970 CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
7971 CFArrayAppendValue(keys, NetworkChangedKey_Computername);
7972 CFArrayAppendValue(keys, NetworkChangedKey_DNS);
7973 CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
7974 CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
7975 CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings);
7976 CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
7977 CFArrayAppendValue(patterns, pattern1);
7978 CFArrayAppendValue(patterns, pattern2);
7979 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
7980 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
7981 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
7983 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
7984 if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()))
7985 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
7987 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
7988 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
7989 CFRunLoopAddSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode);
7991 SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected);
7992 m->p->Store = store;
7997 if (store) CFRelease(store);
8000 if (patterns) CFRelease(patterns);
8001 if (pattern2) CFRelease(pattern2);
8002 if (pattern1) CFRelease(pattern1);
8003 if (keys) CFRelease(keys);
8008 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8010 mDNSlocal void mDNSSetPacketFilterRules(char * ifname, const ResourceRecord *const excludeRecord)
8012 mDNS *const m = &mDNSStorage;
8014 pfArray_t portArray;
8015 pfArray_t protocolArray;
8018 for (rr = m->ResourceRecords; rr; rr=rr->next)
8020 if ((rr->resrec.rrtype == kDNSServiceType_SRV)
8021 && ((rr->ARType == AuthRecordAnyIncludeP2P) || (rr->ARType == AuthRecordAnyIncludeAWDLandP2P)))
8025 if (count >= PFPortArraySize)
8027 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize, ARDisplayString(m, rr));
8031 if (excludeRecord && IdenticalResourceRecord(&rr->resrec, excludeRecord))
8033 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m, rr));
8037 LogMsg("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr));
8039 portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger;
8041 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
8042 p = rr->resrec.name->c;
8044 // Skip to App Protocol
8048 // Skip to Transport Protocol
8052 if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp"))
8054 protocolArray[count] = IPPROTO_TCP;
8056 else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp"))
8058 protocolArray[count] = IPPROTO_UDP;
8062 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
8063 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m, rr));
8069 mDNSPacketFilterControl(PF_SET_RULES, ifname, count, portArray, protocolArray);
8072 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
8073 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8075 mDNS *const m = &mDNSStorage;
8077 NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
8080 if (strncmp(intf->ifname, "p2p", 3) == 0)
8082 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname);
8083 mDNSSetPacketFilterRules(intf->ifname, excludeRecord);
8086 intf = GetFirstActiveInterface(intf->next);
8090 #else // !TARGET_OS_EMBEDDED
8092 // Currently no packet filter setup required on embedded platforms.
8093 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8095 (void) excludeRecord; // unused
8098 #endif // !TARGET_OS_EMBEDDED
8100 // AWDL should no longer generate KEV_DL_MASTER_ELECTED events, so just log a message if we receive one.
8101 mDNSlocal void newMasterElected(struct net_event_data * ptr)
8103 char ifname[IFNAMSIZ];
8104 mDNSu32 interfaceIndex;
8106 snprintf(ifname, IFNAMSIZ, "%s%d", ptr->if_name, ptr->if_unit);
8107 interfaceIndex = if_nametoindex(ifname);
8109 if (!interfaceIndex)
8111 LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname);
8115 LogInfo("newMasterElected: KEV_DL_MASTER_ELECTED received on ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
8118 // An ssth array of all zeroes indicates the peer has no services registered.
8119 mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op)
8122 int *intp = (int *) op->ssth;
8124 // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
8125 // it's not, print an error message and return false so that
8126 // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
8128 if (MAX_SSTH_SIZE % sizeof(int))
8130 LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE);
8134 for (i = 0; i < (int)(MAX_SSTH_SIZE / sizeof(int)); i++, intp++)
8142 // Mark records from this peer for deletion from the cache.
8143 mDNSlocal void removeCachedPeerRecords(mDNSu32 ifindex, mDNSAddr *ap, bool purgeNow)
8145 mDNS *const m = &mDNSStorage;
8149 NetworkInterfaceInfoOSX *infoOSX;
8150 mDNSInterfaceID InterfaceID;
8152 // Using mDNSPlatformInterfaceIDfromInterfaceIndex() would lead to recursive
8153 // locking issues, see: <rdar://problem/21332983>
8154 infoOSX = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
8157 LogInfo("removeCachedPeerRecords: interface %d not yet active", ifindex);
8160 InterfaceID = infoOSX->ifinfo.InterfaceID;
8162 FORALL_CACHERECORDS(slot, cg, cr)
8164 if ((InterfaceID == cr->resrec.InterfaceID) && mDNSSameAddress(ap, & cr->sourceAddress))
8166 LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
8167 DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c);
8170 mDNS_PurgeCacheResourceRecord(m, cr);
8172 mDNS_Reconfirm_internal(m, cr, 0); // use default minimum reconfirm time
8177 // Handle KEV_DL_NODE_PRESENCE event.
8178 mDNSlocal void nodePresence(struct kev_dl_node_presence * p)
8180 char buf[INET6_ADDRSTRLEN];
8181 struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info;
8183 if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
8184 LogInfo("nodePresence: IPv6 address: %s, SUI %d", buf, op->SUI);
8186 LogInfo("nodePresence: inet_ntop() error");
8188 // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
8189 // all zeroes when a node is present and has no services registered.
8190 if (allZeroSSTH(op))
8194 peerAddr.type = mDNSAddrType_IPv6;
8195 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8197 LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer");
8198 removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, false);
8202 // Handle KEV_DL_NODE_ABSENCE event.
8203 mDNSlocal void nodeAbsence(struct kev_dl_node_absence * p)
8206 char buf[INET6_ADDRSTRLEN];
8208 if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
8209 LogInfo("nodeAbsence: IPv6 address: %s", buf);
8211 LogInfo("nodeAbsence: inet_ntop() error");
8213 peerAddr.type = mDNSAddrType_IPv6;
8214 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8216 LogInfo("nodeAbsence: immediately purge cached records from this peer");
8217 removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, true);
8220 mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context, __unused mDNSBool encounteredEOF)
8222 mDNS *const m = (mDNS *const)context;
8226 struct { struct kern_event_msg k; char extra[256]; } msg;
8227 int bytes = recv(s1, &msg, sizeof(msg), 0);
8229 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
8232 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
8233 bytes, msg.k.total_size,
8234 msg.k.vendor_code, msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?",
8235 msg.k.kev_class, msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
8236 msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?",
8237 msg.k.id, msg.k.event_code,
8238 msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" :
8239 msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" :
8240 msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" :
8241 msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" :
8242 msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" :
8243 msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" :
8244 msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" :
8245 msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" :
8246 msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" :
8247 msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" :
8248 msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" :
8249 msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" :
8250 msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" :
8251 msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" :
8252 msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" :
8253 msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
8254 msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" :
8255 msg.k.event_code == KEV_DL_IF_IDLE_ROUTE_REFCNT ? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
8256 msg.k.event_code == KEV_DL_IFCAP_CHANGED ? "KEV_DL_IFCAP_CHANGED" :
8257 msg.k.event_code == KEV_DL_LINK_QUALITY_METRIC_CHANGED ? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" :
8258 msg.k.event_code == KEV_DL_NODE_PRESENCE ? "KEV_DL_NODE_PRESENCE" :
8259 msg.k.event_code == KEV_DL_NODE_ABSENCE ? "KEV_DL_NODE_ABSENCE" :
8260 msg.k.event_code == KEV_DL_MASTER_ELECTED ? "KEV_DL_MASTER_ELECTED" :
8263 if (msg.k.event_code == KEV_DL_NODE_PRESENCE)
8264 nodePresence((struct kev_dl_node_presence *) &msg.k.event_data);
8266 if (msg.k.event_code == KEV_DL_NODE_ABSENCE)
8267 nodeAbsence((struct kev_dl_node_absence *) &msg.k.event_data);
8269 if (msg.k.event_code == KEV_DL_MASTER_ELECTED)
8270 newMasterElected((struct net_event_data *) &msg.k.event_data);
8272 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
8273 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
8274 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
8275 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
8276 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
8278 if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
8279 SetNetworkChanged(mDNSPlatformOneSecond * 2);
8281 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8283 // For p2p interfaces, need to open the advertised service port in the firewall.
8284 if (msg.k.event_code == KEV_DL_IF_ATTACHED)
8286 struct net_event_data * p;
8287 p = (struct net_event_data *) &msg.k.event_data;
8289 if (strncmp(p->if_name, "p2p", 3) == 0)
8291 char ifname[IFNAMSIZ];
8292 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8294 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8296 mDNSSetPacketFilterRules(ifname, NULL);
8300 // For p2p interfaces, need to clear the firewall rules on interface detach
8301 if (msg.k.event_code == KEV_DL_IF_DETACHED)
8303 struct net_event_data * p;
8304 p = (struct net_event_data *) &msg.k.event_data;
8306 if (strncmp(p->if_name, "p2p", 3) == 0)
8308 pfArray_t portArray, protocolArray; // not initialized since count is 0 for PF_CLEAR_RULES
8309 char ifname[IFNAMSIZ];
8310 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8312 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8314 mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
8317 #endif // !TARGET_OS_EMBEDDED
8324 mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
8326 m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
8327 if (m->p->SysEventNotifier < 0)
8328 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); }
8330 struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
8331 int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
8334 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno));
8335 close(m->p->SysEventNotifier);
8336 m->p->SysEventNotifier = -1;
8337 return(mStatus_UnknownErr);
8340 m->p->SysEventKQueue.KQcallback = SysEventCallBack;
8341 m->p->SysEventKQueue.KQcontext = m;
8342 m->p->SysEventKQueue.KQtask = "System Event Notifier";
8343 KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
8345 return(mStatus_NoError);
8348 #ifndef NO_SECURITYFRAMEWORK
8349 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
8351 LogInfo("*** Keychain Changed ***");
8352 mDNS *const m = (mDNS *const)context;
8354 OSStatus err = SecKeychainCopyDefault(&skc);
8357 if (info->keychain == skc)
8359 // For delete events, attempt to verify what item was deleted fail because the item is already gone, so we just assume they may be relevant
8360 mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
8363 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
8364 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
8365 SecKeychainAttributeList *a = NULL;
8366 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
8369 relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
8370 (a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))) ||
8371 (a->attr[1].length >= mDNSPlatformStrLen(btmmprefix) && (!strncasecmp(a->attr[1].data, btmmprefix, mDNSPlatformStrLen(btmmprefix)))));
8372 SecKeychainItemFreeAttributesAndData(a, NULL);
8377 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
8379 keychainEvent == kSecAddEvent ? "kSecAddEvent" :
8380 keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
8381 keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
8382 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
8386 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
8387 // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
8388 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
8390 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
8391 // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
8392 // a one second delay is ok, as we'll still converge to correctness, and there's no race
8393 // condition between the RegistrationDomain and the DomainAuthInfo.
8395 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
8396 // the timer here, as it will not get set by NetworkChanged().
8397 SetKeyChainTimer(mDNSPlatformOneSecond);
8400 KQueueUnlock("KeychainChanged");
8410 mDNSlocal void PowerOn(mDNS *const m)
8412 mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
8414 if (m->p->WakeAtUTC)
8416 long utc = mDNSPlatformUTC();
8417 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
8418 if (m->p->WakeAtUTC - utc > 30)
8420 LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
8422 else if (utc - m->p->WakeAtUTC > 30)
8424 LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
8426 else if (IsAppleTV())
8428 LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC);
8432 LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m->p->WakeAtUTC - utc);
8433 m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond;
8437 // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
8438 // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
8439 // We will clear this assertion as soon as we think the mainenance activities are done.
8440 mDNSPlatformPreventSleep(DARK_WAKE_TIME, "mDNSResponder:maintenance");
8444 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
8446 mDNS *const m = (mDNS *const)refcon;
8448 (void)service; // Parameter not used
8449 debugf("PowerChanged %X %lX", messageType, messageArgument);
8451 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8452 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8456 case kIOMessageCanSystemPowerOff: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
8457 case kIOMessageSystemWillPowerOff: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
8458 mDNSCoreMachineSleep(m, true);
8459 if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged();
8461 case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
8462 case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep"); break; // E0000270
8463 case kIOMessageSystemWillSleep: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
8464 mDNSCoreMachineSleep(m, true);
8466 case kIOMessageSystemWillNotSleep: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
8467 case kIOMessageSystemHasPoweredOn: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
8468 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
8471 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
8474 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
8475 // the System Configuration Framework "network changed" event that we expect
8476 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
8478 SetNetworkChanged(mDNSPlatformOneSecond * 2);
8482 case kIOMessageSystemWillRestart: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
8483 case kIOMessageSystemWillPowerOn: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
8485 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
8486 if (m->SleepState != SleepState_Sleeping)
8488 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
8489 m->SleepState = SleepState_Sleeping;
8490 mDNSMacOSXNetworkChanged();
8494 default: LogSPS("PowerChanged unknown message %X", messageType); break;
8497 if (messageType == kIOMessageSystemWillSleep)
8498 m->p->SleepCookie = (long)messageArgument;
8499 else if (messageType == kIOMessageCanSystemSleep)
8500 IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
8502 KQueueUnlock("PowerChanged Sleep/Wake");
8505 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
8506 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
8507 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
8508 mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
8510 mDNS *const m = (mDNS *const)refcon;
8512 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
8513 connection, token, eventDescriptor,
8514 eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "",
8515 eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "",
8516 eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "",
8517 eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
8518 eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : "");
8520 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8521 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8523 if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
8525 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
8526 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
8527 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
8528 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
8531 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8532 IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie);
8535 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8536 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
8537 if (m->SleepState != SleepState_Awake)
8540 // If the network notifications have already come before we got the wakeup, we ignored them and
8541 // in case we get no more, we need to trigger one.
8543 SetNetworkChanged(mDNSPlatformOneSecond * 2);
8546 IOPMConnectionAcknowledgeEvent(connection, token);
8550 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
8551 // we should hear nothing more until we're told that the CPU has started executing again.
8552 if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
8554 //mDNSMacOSXNetworkChanged(m);
8555 mDNSCoreMachineSleep(m, true);
8556 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
8557 m->p->SleepCookie = token;
8560 KQueueUnlock("SnowLeopardPowerChanged Sleep/Wake");
8564 #if COMPILER_LIKES_PRAGMA_MARK
8566 #pragma mark - /etc/hosts support
8569 // Implementation Notes
8571 // As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
8572 // 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
8573 // them into a hash table. The implementation need to be able to do the following things efficiently
8575 // 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
8576 // 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
8577 // 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
8578 // need to be able set the RRSet of a resource record to the first one in the list and also update when
8579 // one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
8581 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
8583 // CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
8584 // "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
8585 // of the core layer which does all of the above very efficiently
8587 #define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
8589 mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
8594 if (result == mStatus_MemFree)
8596 LogInfo("FreeEtcHosts: %s", ARDisplayString(m, rr));
8597 freeL("etchosts", rr);
8601 // Returns true on success and false on failure
8602 mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(const domainname *domain, const struct sockaddr *sa, const domainname *cname, char *ifname, AuthHash *auth)
8607 mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly;
8612 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
8617 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
8621 if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
8623 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa->sa_family);
8630 mDNSu32 ifindex = if_nametoindex(ifname);
8633 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain->c, ifname);
8636 InterfaceID = (mDNSInterfaceID)(uintptr_t)ifindex;
8640 rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA);
8642 rrtype = kDNSType_CNAME;
8644 // Check for duplicates. See whether we parsed an entry before like this ?
8645 namehash = DomainNameHashValue(domain);
8646 ag = AuthGroupForName(auth, namehash, domain);
8652 if (rr->resrec.rrtype == rrtype)
8654 if (rrtype == kDNSType_A)
8657 ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
8658 if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip))
8660 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c);
8664 else if (rrtype == kDNSType_AAAA)
8667 ip6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
8668 ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
8669 ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
8670 ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
8671 if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6))
8673 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c);
8677 else if (rrtype == kDNSType_CNAME)
8679 if (SameDomainName(&rr->resrec.rdata->u.name, cname))
8681 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname->c, domain->c);
8689 rr= mallocL("etchosts", sizeof(*rr));
8690 if (rr == NULL) return mDNSfalse;
8691 mDNSPlatformMemZero(rr, sizeof(*rr));
8692 mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
8693 AssignDomainName(&rr->namestorage, domain);
8697 rr->resrec.rdlength = sa->sa_family == AF_INET ? sizeof(mDNSv4Addr) : sizeof(mDNSv6Addr);
8698 if (sa->sa_family == AF_INET)
8699 rr->resrec.rdata->u.ipv4.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
8702 rr->resrec.rdata->u.ipv6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
8703 rr->resrec.rdata->u.ipv6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
8704 rr->resrec.rdata->u.ipv6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
8705 rr->resrec.rdata->u.ipv6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
8710 rr->resrec.rdlength = DomainNameLength(cname);
8711 rr->resrec.rdata->u.name.c[0] = 0;
8712 AssignDomainName(&rr->resrec.rdata->u.name, cname);
8714 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
8715 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
8716 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(&mDNSStorage, rr));
8717 InsertAuthRecord(&mDNSStorage, auth, rr);
8721 mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **name)
8726 for (i = start; i < length; i++)
8728 if (buffer[i] == '#')
8730 if (buffer[i] != ' ' && buffer[i] != ',' && buffer[i] != '\t')
8734 // Found the start of a name, find the end and null terminate
8735 for (i++; i < length; i++)
8737 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
8749 mDNSlocal void mDNSMacOSXParseEtcHostsLine(char *buffer, ssize_t length, AuthHash *auth)
8753 char *ifname = NULL;
8760 //Ignore leading whitespaces and tabs
8761 while (*buffer == ' ' || *buffer == '\t')
8767 // Find the end of the address string
8768 for (i = 0; i < length; i++)
8770 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t' || buffer[i] == '%')
8772 if (buffer[i] == '%')
8779 // Convert the address string to an address
8780 struct addrinfo hints;
8781 bzero(&hints, sizeof(hints));
8782 hints.ai_flags = AI_NUMERICHOST;
8783 struct addrinfo *gairesults = NULL;
8784 if (getaddrinfo(buffer, NULL, &hints, &gairesults) != 0)
8786 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
8792 // Parse the interface
8793 ifname = &buffer[ifStart];
8794 for (i = ifStart + 1; i < length; i++)
8796 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
8804 i = EtcHostsParseOneName(i + 1, length, buffer, &name1);
8807 // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
8808 if (!MakeDomainNameFromDNSNameString(&name1d, name1))
8810 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
8811 freeaddrinfo(gairesults);
8814 mDNSMacOSXCreateEtcHostsEntry(&name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
8819 // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
8820 // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
8821 // doing the right thing.
8823 if (!MakeDomainNameFromDNSNameString(&first, name1))
8825 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
8826 freeaddrinfo(gairesults);
8829 mDNSMacOSXCreateEtcHostsEntry(&first, gairesults->ai_addr, mDNSNULL, ifname, auth);
8831 // /etc/hosts alias discussion:
8833 // If the /etc/hosts has an entry like this
8835 // ip_address cname [aliases...]
8836 // 1.2.3.4 sun star bright
8838 // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
8839 // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
8841 // To achieve this, we need to add the entry like this:
8847 // We store the first name we parsed in "first" and add the address (A/AAAA) record.
8848 // Then we parse additional names adding CNAME records till we reach the end.
8853 // Continue to parse additional aliases until we reach end of the line and
8854 // for each "alias" parsed, add a CNAME record where "alias" points to the first "name".
8855 // See also /etc/hosts alias discussion above
8857 i = EtcHostsParseOneName(i + 1, length, buffer, &name2);
8861 if ((aliasIndex) && (*buffer == *name2))
8862 break; // break out of the loop if we wrap around
8864 if (!MakeDomainNameFromDNSNameString(&name2d, name2))
8866 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2);
8867 freeaddrinfo(gairesults);
8870 // Ignore if it points to itself
8871 if (!SameDomainName(&first, &name2d))
8873 if (!mDNSMacOSXCreateEtcHostsEntry(&name2d, mDNSNULL, &first, ifname, auth))
8875 freeaddrinfo(gairesults);
8881 LogInfo("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names first %##s, name2 %##s", first.c, name2d.c);
8885 else if (!aliasIndex)
8887 // We have never parsed any aliases. This case happens if there
8888 // is just one name and some extra white spaces at the end.
8889 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c);
8894 freeaddrinfo(gairesults);
8897 mDNSlocal void mDNSMacOSXParseEtcHosts(int fd, AuthHash *auth)
8900 char buf[ETCHOSTS_BUFSIZE];
8904 if (fd == -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
8906 fp = fopen("/etc/hosts", "r");
8907 if (!fp) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
8911 good = (fgets(buf, ETCHOSTS_BUFSIZE, fp) != NULL);
8914 // skip comment and empty lines
8915 if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n')
8919 if (!len) break; // sanity check
8920 //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
8921 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
8923 buf[len - 1] = '\0';
8926 // fgets always null terminates and hence even if we have no
8927 // newline at the end, it is null terminated. The callee
8928 // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
8929 // buf[length] is zero and hence we decrement len to reflect that.
8932 //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
8933 //here we need to check for just \r but taking extra caution.
8934 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
8936 buf[len - 1] = '\0';
8940 if (!len) //Sanity Check: len should never be zero
8942 LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
8945 mDNSMacOSXParseEtcHostsLine(buf, len, auth);
8950 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m);
8952 mDNSlocal int mDNSMacOSXGetEtcHostsFD(void)
8954 mDNS *const m = &mDNSStorage;
8955 #ifdef __DISPATCH_GROUP__
8956 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
8957 static dispatch_queue_t etcq = 0;
8958 static dispatch_source_t etcsrc = 0;
8959 static dispatch_source_t hostssrc = 0;
8961 // First time through? just schedule ourselves on the main queue and we'll do the work later
8964 etcq = dispatch_get_main_queue();
8967 // Do this work on the queue, not here - solves potential synchronization issues
8968 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
8973 if (hostssrc) return dispatch_source_get_handle(hostssrc);
8976 int fd = open("/etc/hosts", O_RDONLY);
8978 #ifdef __DISPATCH_GROUP__
8979 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
8982 // If the open failed and we're already watching /etc, we're done
8983 if (etcsrc) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd; }
8985 // we aren't watching /etc, we should be
8986 fd = open("/etc", O_RDONLY);
8987 if (fd == -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
8988 etcsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME, etcq);
8994 dispatch_source_set_event_handler(etcsrc,
8996 u_int32_t flags = dispatch_source_get_data(etcsrc);
8997 LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags);
8998 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9000 dispatch_source_cancel(etcsrc);
9001 dispatch_release(etcsrc);
9003 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9006 if ((flags & DISPATCH_VNODE_WRITE) != 0 && hostssrc == NULL)
9008 mDNSMacOSXUpdateEtcHosts(m);
9011 dispatch_source_set_cancel_handler(etcsrc, ^{close(fd);});
9012 dispatch_resume(etcsrc);
9014 // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
9015 fd = open("/etc/hosts", O_RDONLY | O_EVTONLY);
9016 if (fd == -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
9019 // create a dispatch source to watch for changes to hosts file
9020 hostssrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd,
9021 (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME |
9022 DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_LINK | DISPATCH_VNODE_REVOKE), etcq);
9023 if (hostssrc == NULL)
9028 dispatch_source_set_event_handler(hostssrc,
9030 u_int32_t flags = dispatch_source_get_data(hostssrc);
9031 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags);
9032 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9034 dispatch_source_cancel(hostssrc);
9035 dispatch_release(hostssrc);
9037 // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
9038 // the block immediately, we try to open the file and the file may not exist and may
9039 // fail to get a notification in the future. When the file does not exist and
9040 // we start to monitor the directory, on "dispatch_resume" of that source, there
9041 // is no guarantee that the file creation will be notified always because when
9042 // the dispatch_resume returns, the kevent manager may not have registered the
9043 // kevent yet but the file may have been created
9045 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9048 if ((flags & DISPATCH_VNODE_WRITE) != 0)
9050 mDNSMacOSXUpdateEtcHosts(m);
9053 dispatch_source_set_cancel_handler(hostssrc, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd); close(fd);});
9054 dispatch_resume(hostssrc);
9056 // Cleanup /etc source, no need to watch it if we already have /etc/hosts
9059 dispatch_source_cancel(etcsrc);
9060 dispatch_release(etcsrc);
9064 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
9065 return hostssrc ? (int)dispatch_source_get_handle(hostssrc) : -1;
9072 // When /etc/hosts is modified, flush all the cache records as there may be local
9073 // authoritative answers now
9074 mDNSlocal void FlushAllCacheRecords(mDNS *const m)
9080 FORALL_CACHERECORDS(slot, cg, cr)
9083 if (cr->resrec.InterfaceID) continue;
9085 // If a resource record can answer A or AAAA, they need to be flushed so that we will
9086 // never used to deliver an ADD or RMV
9087 if (RRTypeAnswersQuestionType(&cr->resrec, kDNSType_A) ||
9088 RRTypeAnswersQuestionType(&cr->resrec, kDNSType_AAAA))
9090 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr));
9091 mDNS_PurgeCacheResourceRecord(m, cr);
9096 // Add new entries to the core. If justCheck is set, this function does not add, just returns true
9097 mDNSlocal mDNSBool EtcHostsAddNewEntries(AuthHash *newhosts, mDNSBool justCheck)
9099 mDNS *const m = &mDNSStorage;
9102 AuthRecord *rr, *primary, *rrnext;
9103 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9104 for (ag = newhosts->rrauth_hash[slot]; ag; ag = ag->next)
9107 for (rr = ag->members; rr; rr = rrnext)
9112 mDNSBool found = mDNSfalse;
9113 ag1 = AuthGroupForRecord(&m->rrauth, &rr->resrec);
9114 if (ag1 && ag1->members)
9116 if (!primary) primary = ag1->members;
9120 // We are not using InterfaceID in checking for duplicates. This means,
9121 // if there are two addresses for a given name e.g., fe80::1%en0 and
9122 // fe80::1%en1, we only add the first one. It is not clear whether
9123 // this is a common case. To fix this, we also need to modify
9124 // mDNS_Register_internal in how it handles duplicates. If it becomes a
9125 // common case, we will fix it then.
9126 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9128 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
9139 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m, rr));
9142 RemoveAuthRecord(m, newhosts, rr);
9143 // if there is no primary, point to self
9144 rr->RRSet = (primary ? primary : rr);
9146 LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m, rr));
9147 if (mDNS_Register_internal(m, rr) != mStatus_NoError)
9148 LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr));
9155 // Delete entries from the core that are no longer needed. If justCheck is set, this function
9156 // does not delete, just returns true
9157 mDNSlocal mDNSBool EtcHostsDeleteOldEntries(AuthHash *newhosts, mDNSBool justCheck)
9159 mDNS *const m = &mDNSStorage;
9162 AuthRecord *rr, *rrnext;
9163 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9164 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
9165 for (rr = ag->members; rr; rr = rrnext)
9167 mDNSBool found = mDNSfalse;
9171 if (rr->RecordCallback != FreeEtcHosts) continue;
9172 ag1 = AuthGroupForRecord(newhosts, &rr->resrec);
9178 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9180 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m, rr));
9187 // there is no corresponding record in newhosts for the same name. This means
9188 // we should delete this from the core.
9193 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m, rr));
9196 // if primary is going away, make sure that the rest of the records
9197 // point to the new primary
9198 if (rr == ag->members)
9200 AuthRecord *new_primary = rr->next;
9201 AuthRecord *r = new_primary;
9206 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m, r));
9207 r->RRSet = new_primary;
9209 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m, r), r->resrec.name);
9213 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m, rr));
9214 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
9220 mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context)
9222 AuthHash *newhosts = (AuthHash *)context;
9226 //Delete old entries from the core if they are not present in the newhosts
9227 EtcHostsDeleteOldEntries(newhosts, mDNSfalse);
9228 // Add the new entries to the core if not already present in the core
9229 EtcHostsAddNewEntries(newhosts, mDNSfalse);
9232 mDNSlocal void FreeNewHosts(AuthHash *newhosts)
9235 AuthGroup *ag, *agnext;
9236 AuthRecord *rr, *rrnext;
9238 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9239 for (ag = newhosts->rrauth_hash[slot]; ag; ag = agnext)
9242 for (rr = ag->members; rr; rr = rrnext)
9245 freeL("etchosts", rr);
9247 freeL("AuthGroups", ag);
9251 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
9255 // As we will be modifying the core, we can only have one thread running at
9256 // any point in time.
9259 mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
9261 // Get the file desecriptor (will trigger us to start watching for changes)
9262 int fd = mDNSMacOSXGetEtcHostsFD();
9265 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd);
9266 mDNSMacOSXParseEtcHosts(fd, &newhosts);
9268 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
9270 // Optimization: Detect whether /etc/hosts changed or not.
9272 // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
9273 // newhosts is already registered with core. If we find at least one entry that is not
9274 // registered with core, then it means we have work to do.
9276 // 2. Next, we check to see if any of the entries that are registered with core is not present
9277 // in newhosts. If we find at least one entry that is not present, it means we have work to
9280 // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
9281 // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
9282 // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
9283 // in the future and this code does not have to change.
9285 // Add the new entries to the core if not already present in the core
9286 if (!EtcHostsAddNewEntries(&newhosts, mDNStrue))
9288 // No new entries to add, check to see if we need to delete any old entries from the
9289 // core if they are not present in the newhosts
9290 if (!EtcHostsDeleteOldEntries(&newhosts, mDNStrue))
9292 LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
9293 FreeNewHosts(&newhosts);
9295 KQueueUnlock("/etc/hosts changed");
9300 // This will flush the cache, stop and start the query so that the queries
9301 // can look at the /etc/hosts again
9305 // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
9306 // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
9307 // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
9308 // delivers these events in the right order and then calls us back to delete them.
9310 // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
9311 // is a common function that looks at all local auth records and delivers a RMV including
9312 // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
9313 // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
9314 // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
9315 // is called back where we do the Registration of the record. This results in RMV followed by ADD which
9317 mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts);
9318 FreeNewHosts(&newhosts);
9320 KQueueUnlock("/etc/hosts changed");
9323 #if COMPILER_LIKES_PRAGMA_MARK
9325 #pragma mark - Initialization & Teardown
9328 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
9329 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
9330 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
9331 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
9333 // Major version 13 is 10.9.x
9334 mDNSexport void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
9336 int major = 0, minor = 0;
9337 char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
9338 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
9341 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
9342 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
9343 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
9345 CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
9347 CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
9348 if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
9349 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
9355 LogMsg("Note: No Major Build Version number found; assuming 13");
9358 mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion));
9359 //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
9361 // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
9362 if ((prodname[0] & 0xDF) == 'M')
9368 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
9369 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
9370 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
9371 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
9374 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
9376 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
9379 struct sockaddr_in s5353;
9380 s5353.sin_family = AF_INET;
9381 s5353.sin_port = MulticastDNSPort.NotAnInteger;
9382 s5353.sin_addr.s_addr = 0;
9383 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
9387 if (err) LogMsg("No unicast UDP responses");
9388 else debugf("Unicast UDP responses okay");
9392 mDNSlocal void CreatePTRRecord(const domainname *domain)
9395 const domainname *pname = (domainname *)"\x9" "localhost";
9397 rr= mallocL("localhosts", sizeof(*rr));
9398 if (rr == NULL) return;
9399 mDNSPlatformMemZero(rr, sizeof(*rr));
9401 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
9402 AssignDomainName(&rr->namestorage, domain);
9404 rr->resrec.rdlength = DomainNameLength(pname);
9405 rr->resrec.rdata->u.name.c[0] = 0;
9406 AssignDomainName(&rr->resrec.rdata->u.name, pname);
9408 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
9409 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
9410 mDNS_Register(&mDNSStorage, rr);
9413 // Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
9414 // on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
9415 // fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
9416 // a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
9418 // Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
9419 // intentionally to avoid adding to the complexity of code handling /etc/hosts.
9420 mDNSlocal void SetupLocalHostRecords(void)
9422 char buffer[MAX_REVERSE_MAPPING_NAME];
9425 struct in6_addr addr;
9426 mDNSu8 *ptr = addr.__u6_addr.__u6_addr8;
9428 if (inet_pton(AF_INET, "127.0.0.1", &addr) == 1)
9430 mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
9431 ptr[3], ptr[2], ptr[1], ptr[0]);
9432 MakeDomainNameFromDNSNameString(&name, buffer);
9433 CreatePTRRecord(&name);
9435 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET failed");
9437 if (inet_pton(AF_INET6, "::1", &addr) == 1)
9439 for (i = 0; i < 16; i++)
9441 static const char hexValues[] = "0123456789ABCDEF";
9442 buffer[i * 4 ] = hexValues[ptr[15 - i] & 0x0F];
9443 buffer[i * 4 + 1] = '.';
9444 buffer[i * 4 + 2] = hexValues[ptr[15 - i] >> 4];
9445 buffer[i * 4 + 3] = '.';
9447 mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
9448 MakeDomainNameFromDNSNameString(&name, buffer);
9449 CreatePTRRecord(&name);
9451 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET6 failed");
9454 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
9455 mDNSlocal void setSameDomainLabelPointer(void);
9458 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
9459 // 1) query for b._dns-sd._udp.local on LocalOnly interface
9460 // (.local manually generated via explicit callback)
9461 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
9462 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
9463 // 4) result above should generate a callback from question in (1). result added to global list
9464 // 5) global list delivered to client via GetSearchDomainList()
9465 // 6) client calls to enumerate domains now go over LocalOnly interface
9466 // (!!!KRS may add outgoing interface in addition)
9468 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
9472 char HINFO_SWstring[256] = "";
9473 mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
9475 #if APPLE_OSX_mDNSResponder
9476 setSameDomainLabelPointer();
9479 err = mDNSHelperInit();
9483 // Store mDNSResponder Platform
9486 m->mDNS_plat = platform_OSX;
9491 m->mDNS_plat = platform_Atv;
9493 m->mDNS_plat = platform_iOS;
9497 m->mDNS_plat = platform_NonApple;
9500 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
9501 // If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
9503 for (i=0; i<100; i++)
9505 domainlabel testlabel;
9507 GetUserSpecifiedLocalHostName(&testlabel);
9508 if (testlabel.c[0]) break;
9512 m->hostlabel.c[0] = 0;
9514 int get_model[2] = { CTL_HW, HW_MODEL };
9515 size_t len_model = sizeof(HINFO_HWstring_buffer);
9517 // Normal Apple model names are of the form "iPhone2,1", and
9518 // internal code names are strings containing no commas, e.g. "N88AP".
9519 // We used to ignore internal code names, but Apple now uses these internal code names
9520 // even in released shipping products, so we no longer ignore strings containing no commas.
9521 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
9522 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
9523 HINFO_HWstring = HINFO_HWstring_buffer;
9525 // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
9526 // For names of the form "N88AP" containg no comma, we use the entire string.
9527 HINFO_HWstring_prefixlen = strchr(HINFO_HWstring_buffer, ',') ? strcspn(HINFO_HWstring, "0123456789") : strlen(HINFO_HWstring);
9529 if (mDNSPlatformInit_CanReceiveUnicast())
9530 m->CanReceiveUnicastOn5353 = mDNStrue;
9532 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
9533 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
9534 if (hlen + slen < 254)
9536 m->HIHardware.c[0] = hlen;
9537 m->HISoftware.c[0] = slen;
9538 mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
9539 mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
9542 m->p->permanentsockets.port = MulticastDNSPort;
9543 m->p->permanentsockets.m = m;
9544 m->p->permanentsockets.sktv4 = -1;
9545 m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack;
9546 m->p->permanentsockets.kqsv4.KQcontext = &m->p->permanentsockets;
9547 m->p->permanentsockets.kqsv4.KQtask = "IPv4 UDP packet reception";
9548 m->p->permanentsockets.sktv6 = -1;
9549 m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
9550 m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
9551 m->p->permanentsockets.kqsv6.KQtask = "IPv6 UDP packet reception";
9553 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
9554 if (err) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET) failed error %d errno %d (%s)", err, errno, strerror(errno));
9555 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
9556 if (err) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET6) failed error %d errno %d (%s)", err, errno, strerror(errno));
9558 struct sockaddr_in s4;
9559 socklen_t n4 = sizeof(s4);
9560 if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0)
9561 LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
9563 m->UnicastPort4.NotAnInteger = s4.sin_port;
9565 if (m->p->permanentsockets.sktv6 >= 0)
9567 struct sockaddr_in6 s6;
9568 socklen_t n6 = sizeof(s6);
9569 if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
9570 else m->UnicastPort6.NotAnInteger = s6.sin6_port;
9573 m->p->InterfaceList = mDNSNULL;
9574 m->p->userhostlabel.c[0] = 0;
9575 m->p->usernicelabel.c[0] = 0;
9576 m->p->prevoldnicelabel.c[0] = 0;
9577 m->p->prevnewnicelabel.c[0] = 0;
9578 m->p->prevoldhostlabel.c[0] = 0;
9579 m->p->prevnewhostlabel.c[0] = 0;
9580 m->p->NotifyUser = 0;
9581 m->p->KeyChainTimer = 0;
9582 m->p->WakeAtUTC = 0;
9583 m->p->RequestReSleep = 0;
9584 // Assume that everything is good to begin with. If something is not working,
9585 // we will detect that when we start sending questions.
9586 m->p->v4answers = 1;
9587 m->p->v6answers = 1;
9588 m->p->DNSTrigger = 0;
9589 m->p->LastConfigGeneration = 0;
9591 m->AutoTunnelRelayAddr = zerov6Addr;
9593 NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
9594 NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
9595 NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
9596 NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
9597 NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
9598 NetworkChangedKey_StateInterfacePrefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, CFSTR(""), NULL);
9599 if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS || !NetworkChangedKey_StateInterfacePrefix)
9600 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
9602 err = WatchForNetworkChanges(m);
9603 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
9605 err = WatchForSysEvents(m);
9606 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
9608 mDNSs32 utc = mDNSPlatformUTC();
9609 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
9611 UpdateInterfaceList(utc);
9612 SetupActiveInterfaces(utc);
9613 ReorderInterfaceList();
9615 // Explicitly ensure that our Keychain operations utilize the system domain.
9616 #ifndef NO_SECURITYFRAMEWORK
9617 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
9621 SetDomainSecrets(m);
9625 #ifndef NO_SECURITYFRAMEWORK
9626 err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
9627 if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
9630 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
9631 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
9634 IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
9635 if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
9638 iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
9639 if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
9642 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9643 IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue());
9644 LogInfo("IOPMConnectionSetDispatchQueue is now running");
9646 iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
9647 if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
9648 LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
9649 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9652 m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
9653 if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
9654 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
9656 m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
9657 if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
9660 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9661 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
9663 CFRunLoopAddSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
9664 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9668 #if APPLE_OSX_mDNSResponder
9669 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
9670 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
9671 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
9672 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
9673 if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9674 else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9675 else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9676 else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
9677 else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; }
9678 else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; }
9679 else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /* 4kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 13W */; }
9680 else if (!strncasecmp(HINFO_HWstring, "AirPort", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 12W */; }
9681 else if ( IsAppleTV() ) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 60 /* 1W */; SPMetricTotalPower = 63 /* 2W */; }
9682 else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
9683 else if (!strncasecmp(HINFO_HWstring, "PowerBook", 9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
9684 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
9685 HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
9686 #endif // APPLE_OSX_mDNSResponder
9688 // Currently this is not defined. SSL code will eventually fix this. If it becomes
9689 // critical, we will define this to workaround the bug in SSL.
9690 #ifdef __SSL_NEEDS_SERIALIZATION__
9691 SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL);
9693 SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
9695 if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
9697 mDNSMacOSXUpdateEtcHosts(m);
9698 SetupLocalHostRecords();
9700 return(mStatus_NoError);
9703 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
9706 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
9709 // Adding interfaces will use this flag, so set it now.
9710 m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
9712 #if APPLE_OSX_mDNSResponder
9713 m->SPSBrowseCallback = UpdateSPSStatus;
9714 #endif // APPLE_OSX_mDNSResponder
9716 mStatus result = mDNSPlatformInit_setup(m);
9718 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
9719 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
9720 if (result == mStatus_NoError)
9722 mDNSCoreInitComplete(m, mStatus_NoError);
9723 initializeD2DPlugins(m);
9725 result = DNSSECCryptoInit(m);
9729 mDNSexport void mDNSPlatformClose(mDNS *const m)
9731 if (m->p->PowerConnection)
9733 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9734 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);
9736 CFRunLoopRemoveSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
9738 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
9739 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
9740 IODeregisterForSystemPower(&m->p->PowerNotifier);
9741 IOServiceClose ( m->p->PowerConnection);
9742 IONotificationPortDestroy ( m->p->PowerPortRef);
9743 m->p->PowerConnection = 0;
9748 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9749 if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
9750 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
9752 CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode);
9753 CFRunLoopSourceInvalidate(m->p->StoreRLS);
9754 CFRelease(m->p->StoreRLS);
9755 m->p->StoreRLS = NULL;
9757 CFRelease(m->p->Store);
9763 CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->PMRLS, kCFRunLoopDefaultMode);
9764 CFRunLoopSourceInvalidate(m->p->PMRLS);
9765 CFRelease(m->p->PMRLS);
9769 if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
9771 terminateD2DPlugins();
9773 mDNSs32 utc = mDNSPlatformUTC();
9774 MarkAllInterfacesInactive(utc);
9775 ClearInactiveInterfaces(utc);
9776 CloseSocketSet(&m->p->permanentsockets);
9778 #if APPLE_OSX_mDNSResponder
9780 while (m->TunnelClients)
9782 ClientTunnel *cur = m->TunnelClients;
9783 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
9784 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
9785 AutoTunnelSetKeys(cur, mDNSfalse);
9786 m->TunnelClients = cur->next;
9787 freeL("ClientTunnel", cur);
9790 if (AnonymousRacoonConfig)
9792 AnonymousRacoonConfig = mDNSNULL;
9793 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel need not be done in mDNSResponder");
9795 #endif // APPLE_OSX_mDNSResponder
9798 #if COMPILER_LIKES_PRAGMA_MARK
9800 #pragma mark - General Platform Support Layer functions
9803 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
9805 return(arc4random());
9808 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
9809 mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
9811 mDNSexport mStatus mDNSPlatformTimeInit(void)
9813 // Notes: Typical values for mach_timebase_info:
9814 // tbi.numer = 1000 million
9815 // tbi.denom = 33 million
9816 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
9817 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
9818 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
9819 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
9820 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
9822 // Arithmetic notes:
9823 // tbi.denom is at least 1, and not more than 2^32-1.
9824 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
9825 // tbi.denom is at least 1, and not more than 2^32-1.
9826 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
9827 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
9828 // which is unlikely on any current or future Macintosh.
9829 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
9830 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
9831 struct mach_timebase_info tbi;
9832 kern_return_t result = mach_timebase_info(&tbi);
9833 if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
9837 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
9839 if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
9841 static uint64_t last_mach_absolute_time = 0;
9842 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
9843 uint64_t this_mach_absolute_time = mach_absolute_time();
9844 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
9846 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
9847 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
9848 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
9849 last_mach_absolute_time = this_mach_absolute_time;
9850 // Note: This bug happens all the time on 10.3
9851 NotifyOfElusiveBug("mach_absolute_time went backwards!",
9852 "This error occurs from time to time, often on newly released hardware, "
9853 "and usually the exact cause is different in each instance.\r\r"
9854 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
9855 "and assign it to Radar Component “Kernel” Version “X”.");
9857 last_mach_absolute_time = this_mach_absolute_time;
9859 return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
9862 mDNSexport mDNSs32 mDNSPlatformUTC(void)
9867 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
9868 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
9869 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
9870 mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (const char *)src); }
9871 mDNSexport mDNSu32 mDNSPlatformStrLCopy( void *dst, const void *src, mDNSu32 dstlen) { return (strlcpy((char *)dst, (const char *)src, dstlen)); }
9872 mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((const char*)src)); }
9873 mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
9874 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
9875 mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); }
9876 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); }
9877 mDNSexport void mDNSPlatformQsort ( void *base, int nel, int width, int (*compar)(const void *, const void *))
9879 return (qsort(base, nel, width, compar));
9881 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
9882 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
9884 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
9886 mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason)
9888 mDNS *const m = &mDNSStorage;
9889 if (allowSleep && m->p->IOPMAssertion)
9891 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
9892 IOPMAssertionRelease(m->p->IOPMAssertion);
9893 m->p->IOPMAssertion = 0;
9895 else if (!allowSleep)
9897 #ifdef kIOPMAssertionTypeNoIdleSleep
9898 if (m->p->IOPMAssertion)
9900 IOPMAssertionRelease(m->p->IOPMAssertion);
9901 m->p->IOPMAssertion = 0;
9904 CFStringRef assertionName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%d %s"), getprogname(), getpid(), reason ? reason : "");
9905 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, assertionName ? assertionName : CFSTR("mDNSResponder"), &m->p->IOPMAssertion);
9906 if (assertionName) CFRelease(assertionName);
9907 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__);
9912 mDNSexport void mDNSPlatformPreventSleep(mDNSu32 timeout, const char *reason)
9914 mDNS *const m = &mDNSStorage;
9915 if (m->p->IOPMAssertion)
9917 LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout, reason);
9920 #ifdef kIOPMAssertionTypeNoIdleSleep
9922 #if TARGET_OS_EMBEDDED
9924 return; // No need for maintenance wakes on non-AppleTV embedded devices.
9927 double timeoutVal = (double)timeout;
9928 CFStringRef str = CFStringCreateWithCString(NULL, reason, kCFStringEncodingUTF8);
9929 CFNumberRef Timeout_num = CFNumberCreate(NULL, kCFNumberDoubleType, &timeoutVal);
9930 CFMutableDictionaryRef assertionProperties = CFDictionaryCreateMutable(NULL, 0,
9931 &kCFTypeDictionaryKeyCallBacks,
9932 &kCFTypeDictionaryValueCallBacks);
9934 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertPreventUserIdleSystemSleep);
9936 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertMaintenanceActivity);
9938 CFDictionarySetValue(assertionProperties, kIOPMAssertionTimeoutKey, Timeout_num);
9939 CFDictionarySetValue(assertionProperties, kIOPMAssertionNameKey, str);
9941 IOPMAssertionCreateWithProperties(assertionProperties, (IOPMAssertionID *)&m->p->IOPMAssertion);
9943 CFRelease(Timeout_num);
9944 CFRelease(assertionProperties);
9945 LogSPS("Got an idle sleep assertion for %d seconds for %s", timeout, reason);
9949 mDNSexport void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
9954 ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, InterfaceID, mDNStrue);
9957 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
9960 mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration);
9963 mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
9965 NetworkInterfaceInfoOSX *info;
9967 if (InterfaceID == mDNSInterface_P2P)
9970 // mDNSInterface_BLE not considered a D2D interface for the purpose of this
9971 // routine, since it's not implemented via a D2D plugin.
9972 if (InterfaceID == mDNSInterface_BLE)
9975 if ( (InterfaceID == mDNSInterface_Any)
9976 || (InterfaceID == mDNSInterfaceMark)
9977 || (InterfaceID == mDNSInterface_LocalOnly)
9978 || (InterfaceID == mDNSInterface_Unicast))
9981 // Compare to cached AWDL interface ID.
9982 if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
9985 info = IfindexToInterfaceInfoOSX(InterfaceID);
9988 // this log message can print when operations are stopped on an interface that has gone away
9989 LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID);
9993 return (mDNSBool) info->D2DInterface;
9996 // Filter records send over P2P (D2D) type interfaces
9997 // Note that the terms P2P and D2D are used synonymously in the current code and comments.
9998 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
10000 // For an explicit match to a valid interface ID, return true.
10001 if (rr->resrec.InterfaceID == InterfaceID)
10004 // Only filtering records for D2D type interfaces, return true for all other interface types.
10005 if (!mDNSPlatformInterfaceIsD2D(InterfaceID))
10008 // If it's an AWDL interface the record must be explicitly marked to include AWDL.
10009 if (InterfaceID == AWDLInterfaceID)
10011 if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10017 // Send record if it is explicitly marked to include all other P2P type interfaces.
10018 if (rr->ARType == AuthRecordAnyIncludeP2P || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10021 // Don't send the record over this interface.
10025 // Filter questions send over P2P (D2D) type interfaces.
10026 mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
10028 // For an explicit match to a valid interface ID, return true.
10029 if (q->InterfaceID == intf->InterfaceID)
10032 // Only filtering questions for D2D type interfaces
10033 if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
10036 // If it's an AWDL interface the question must be explicitly marked to include AWDL.
10037 if (intf->InterfaceID == AWDLInterfaceID)
10039 if (q->flags & kDNSServiceFlagsIncludeAWDL)
10045 // Sent question if it is explicitly marked to include all other P2P type interfaces.
10046 if (q->flags & kDNSServiceFlagsIncludeP2P)
10049 // Don't send the question over this interface.
10053 // Returns true unless record was received over the AWDL interface and
10054 // the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
10055 // with the kDNSServiceFlagsIncludeAWDL flag set.
10056 mDNSexport mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
10058 if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID))
10061 if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL))
10067 // formating time to RFC 4034 format
10068 mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
10071 time_t t = (time_t)te;
10072 // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
10073 // gmtime_r first and then use strftime
10074 gmtime_r(&t, &tmTime);
10075 strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
10078 mDNSexport mDNSs32 mDNSPlatformGetPID()
10083 // Schedule a function asynchronously on the main queue
10084 mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func)
10086 // KQueueLock/Unlock is used for two purposes
10088 // 1. We can't be running along with the KQueue thread and hence acquiring the lock
10089 // serializes the access to the "core"
10091 // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
10092 // up and calls udsserver_idle which schedules the messages across the uds socket.
10093 // If "func" delivers something to the uds socket from the dispatch thread, it will
10094 // not be delivered immediately if not for the Unlock.
10095 dispatch_async(dispatch_get_main_queue(), ^{
10098 KQueueUnlock("mDNSPlatformDispatchAsync");
10099 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10100 // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
10101 // to handle any message that "func" might deliver.
10102 TriggerEventCompletion();
10107 // definitions for device-info record construction
10108 #define DEVINFO_MODEL "model="
10109 #define DEVINFO_MODEL_LEN sizeof_string(DEVINFO_MODEL)
10111 #define OSX_VER "osxvers="
10112 #define OSX_VER_LEN sizeof_string(OSX_VER)
10113 #define VER_NUM_LEN 2 // 2 digits of version number added to base string
10115 #define MODEL_COLOR "ecolor="
10116 #define MODEL_COLOR_LEN sizeof_string(MODEL_COLOR)
10117 #define MODEL_RGB_VALUE_LEN sizeof_string("255,255,255") // 'r,g,b'
10119 // Bytes available in TXT record for model name after subtracting space for other
10120 // fixed size strings and their length bytes.
10121 #define MAX_MODEL_NAME_LEN (256 - (DEVINFO_MODEL_LEN + 1) - (OSX_VER_LEN + VER_NUM_LEN + 1) - (MODEL_COLOR_LEN + MODEL_RGB_VALUE_LEN + 1))
10123 mDNSlocal mDNSu8 getModelIconColors(char *color)
10125 mDNSPlatformMemZero(color, MODEL_RGB_VALUE_LEN + 1);
10127 #if !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10132 IOReturn rGetDeviceColor = IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey,
10133 &red, &green, &blue);
10134 if (kIOReturnSuccess == rGetDeviceColor)
10136 // IOKit was able to get enclosure color for the current device.
10137 return snprintf(color, MODEL_RGB_VALUE_LEN + 1, "%d,%d,%d", red, green, blue);
10139 #endif // !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10145 // Initialize device-info TXT record contents and return total length of record data.
10146 mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
10148 mDNSu8 *bufferStart = ptr;
10149 mDNSu8 len = m->HIHardware.c[0] < MAX_MODEL_NAME_LEN ? m->HIHardware.c[0] : MAX_MODEL_NAME_LEN;
10151 *ptr = DEVINFO_MODEL_LEN + len; // total length of DEVINFO_MODEL string plus the hardware name string
10153 mDNSPlatformMemCopy(ptr, DEVINFO_MODEL, DEVINFO_MODEL_LEN);
10154 ptr += DEVINFO_MODEL_LEN;
10155 mDNSPlatformMemCopy(ptr, m->HIHardware.c + 1, len);
10158 // only include this string for OSX
10161 char ver_num[VER_NUM_LEN + 1]; // version digits + null written by snprintf
10162 *ptr = OSX_VER_LEN + VER_NUM_LEN; // length byte
10164 mDNSPlatformMemCopy(ptr, OSX_VER, OSX_VER_LEN);
10165 ptr += OSX_VER_LEN;
10166 // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
10167 // WARNING: This code assumes that OSXVers is always exactly two digits
10168 snprintf(ver_num, VER_NUM_LEN + 1, "%d", OSXVers);
10169 mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN);
10170 ptr += VER_NUM_LEN;
10172 char rgb[MODEL_RGB_VALUE_LEN + 1]; // RGB value + null written by snprintf
10173 len = getModelIconColors(rgb);
10176 *ptr = MODEL_COLOR_LEN + len; // length byte
10179 mDNSPlatformMemCopy(ptr, MODEL_COLOR, MODEL_COLOR_LEN);
10180 ptr += MODEL_COLOR_LEN;
10182 mDNSPlatformMemCopy(ptr, rgb, len);
10187 return (ptr - bufferStart);
10190 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
10192 // Use the scalar version of SameDomainLabel() by default
10193 mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
10194 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
10195 mDNSlocal mDNSBool (*SameDomainLabelPointer)(const mDNSu8 *a, const mDNSu8 *b) = scalarSameDomainLabel;
10197 #include <System/machine/cpu_capabilities.h>
10198 #define _cpu_capabilities ((uint32_t*) _COMM_PAGE_CPU_CAPABILITIES)[0]
10200 #if TARGET_OS_EMBEDDED
10202 #include <arm_neon.h>
10204 // Cache line aligned table that returns 32 for the upper case letters.
10205 // This will take up 4 cache lines.
10206 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table[256] = {
10207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10209 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10211 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
10212 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
10213 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10215 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10219 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
10226 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10228 const int len = *a++;
10230 if (len > MAX_DOMAIN_LABEL)
10232 fprintf(stderr, "v: Malformed label (too long)\n");
10241 uint32_t len_count = len;
10243 uint8x16_t vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
10245 uint8x16_t v32 = vdupq_n_u8(32);
10246 uint8x16_t v37 = vdupq_n_u8(37);
10247 uint8x16_t v101 = vdupq_n_u8(101);
10248 #if !defined __arm64__
10249 uint32x4_t vtemp32;
10250 uint32x2_t vtemp32d;
10254 while(len_count > 15)
10261 //Make vA to lowercase if there is any uppercase.
10262 vARotated = vaddq_u8(vA, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10263 vMaskA = vcgtq_s8(vARotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10264 vMaskA = vandq_u8(vMaskA, v32); //Prepare 32 for the elements with uppercase letters.
10265 vA = vaddq_u8(vA, vMaskA); //Add 32 only to the uppercase letters to make them lowercase letters.
10267 //Make vB to lowercase if there is any uppercase.
10268 vBRotated = vaddq_u8(vB, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10269 vMaskB = vcgtq_s8(vBRotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10270 vMaskB = vandq_u8(vMaskB, v32); //Prepare 32 for the elements with uppercase letters.
10271 vB = vaddq_u8(vB, vMaskB); //Add 32 only to the uppercase letters to make them lowercase letters.
10274 vA = vceqq_u8(vA, vB);
10276 #if defined __arm64__
10277 //View 8-bit element as 32-bit => a3 a2 a1 a0
10278 //If min of 4 32-bit values in vA is 0xffffffff, then it means we have 0xff for all 16.
10279 if(vminvq_u32(vA) != 0xffffffffU)
10285 //See if any element was not same.
10286 //View 8-bit element as 16-bit => a7 a6 a5 a4 a3 a2 a1 a0
10287 //(a7+a6) (a5+a4) (a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
10288 vtemp32 = vpaddlq_u16(vA);
10289 vtemp32d = vpadd_u32(vget_low_u32(vtemp32), vget_high_u32(vtemp32));
10290 vtemp32d = vpadd_u32(vtemp32d, vtemp32d);
10291 sum = vget_lane_u32(vtemp32d, 0);
10293 //0x0001fffe + 0x0001fffe + 0x0001fffe + 0x0001fffe = 0x0007fff8U when all same.
10294 if(sum != 0x0007fff8U)
10303 uint8x8_t vAd, vBd, vARotatedd, vBRotatedd, vMaskAd, vMaskBd;
10305 uint8x8_t v32d = vdup_n_u8(32);
10306 uint8x8_t v37d = vdup_n_u8(37);
10307 uint8x8_t v101d = vdup_n_u8(101);
10309 while(len_count > 7)
10316 //Make vA to lowercase if there is any uppercase.
10317 vARotatedd = vadd_u8(vAd, v37d); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10318 vMaskAd = vcgt_s8(vARotatedd, v101d); //Check if anything is greater than '101' which means we have uppercase letters.
10319 vMaskAd = vand_u8(vMaskAd, v32d); //Prepare 32 for the elements with uppercase letters.
10320 vAd = vadd_u8(vAd, vMaskAd); //Add 32 only to the uppercase letters to make them lowercase letters.
10322 //Make vB to lowercase if there is any uppercase.
10323 vBRotatedd = vadd_u8(vBd, v37d); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10324 vMaskBd = vcgt_s8(vBRotatedd, v101d); //Check if anything is greater than '101' which means we have uppercase letters.
10325 vMaskBd = vand_u8(vMaskBd, v32d); //Prepare 32 for the elements with uppercase letters.
10326 vBd = vadd_u8(vBd, vMaskBd); //Add 32 only to the uppercase letters to make them lowercase letters.
10329 vAd = vceq_u8(vAd, vBd);
10331 #if defined __arm64__
10332 //View 8-bit element as 32-bit => a1 a0
10333 //If min of 2 32-bit values in vAd is 0xffffffff, then it means we have 0xff for all 16.
10334 if(vminv_u32(vAd) != 0xffffffffU)
10340 //See if any element was not same.
10341 //View 8-bit element as 16-bit => a3 a2 a1 a0
10342 //(a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
10343 vtemp32d = vpaddl_u16(vAd);
10344 vtemp32d = vpadd_u32(vtemp32d, vtemp32d);
10345 sum = vget_lane_u32(vtemp32d, 0);
10347 //0x0001fffe + 0x0001fffe = 0x0003fffc when all same.
10348 if(sum != 0x0003fffcU)
10357 while(len_count > 0)
10362 ac += upper_to_lower_case_table[ac];
10363 bc += upper_to_lower_case_table[bc];
10375 // Use vectorized implementation if it is supported on this platform.
10376 mDNSlocal void setSameDomainLabelPointer(void)
10378 if(_cpu_capabilities & kHasNeon)
10381 SameDomainLabelPointer = vectorSameDomainLabel;
10382 LogMsg("setSameDomainLabelPointer: using vector code");
10385 LogMsg("setSameDomainLabelPointer: using scalar code");
10388 #else // TARGET_OS_EMBEDDED
10390 #include <smmintrin.h>
10392 // Cache line aligned table that returns 32 for the upper case letters.
10393 // This will take up 4 cache lines.
10394 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table[256] = {
10395 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10396 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10397 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10398 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10399 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
10400 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
10401 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10402 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10403 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10404 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10405 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10406 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10407 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10408 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10409 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10410 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
10414 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10416 const int len = *a++;
10418 if (len > MAX_DOMAIN_LABEL)
10420 fprintf(stderr, "v: Malformed label (too long)\n");
10429 uint32_t len_count = len;
10431 static const __attribute__ ((aligned(16))) unsigned char c_32[16] = { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 };
10432 static const __attribute__ ((aligned(16))) unsigned char c_37[16] = { 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37 };
10433 static const __attribute__ ((aligned(16))) unsigned char c_101[16] = { 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101 };
10434 __m128i v37 = _mm_load_si128((__m128i*)c_37);
10435 __m128i v101 = _mm_load_si128((__m128i*)c_101);
10436 __m128i v32 = _mm_load_si128((__m128i*)c_32);
10439 __m128i vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
10441 //AVX code that uses higher bandwidth (more elements per vector) was removed
10442 //to speed up the processing on the small sizes.
10443 //When I had them, the performance of 1 ~ 8 characters were slower by about 10% ~ 30%.
10444 while(len_count > 15)
10446 vA = _mm_loadu_si128((__m128i*)a);
10447 vB = _mm_loadu_si128((__m128i*)b);
10451 //Make vA to lowercase if there is any uppercase.
10452 vARotated = _mm_add_epi8(vA, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10453 vMaskA = _mm_cmpgt_epi8(vARotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10454 vMaskA = _mm_and_si128(vMaskA, v32); //Prepare 32 for the elements with uppercase letters.
10455 vA = _mm_add_epi8(vA, vMaskA); //Add 32 only to the uppercase letters to make them lowercase letters.
10457 //Make vB to lowercase if there is any uppercase.
10458 vBRotated = _mm_add_epi8(vB, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10459 vMaskB = _mm_cmpgt_epi8(vBRotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10460 vMaskB = _mm_and_si128(vMaskB, v32); //Prepare 32 for the elements with uppercase letters.
10461 vB = _mm_add_epi8(vB, vMaskB); //Add 32 only to the uppercase letters to make them lowercase letters.
10464 vA = _mm_cmpeq_epi8(vA, vB);
10466 //Return if any different.
10467 is_equal = _mm_movemask_epi8(vA);
10468 is_equal = is_equal & 0xffff;
10469 if(is_equal != 0xffff)
10477 while(len_count > 0)
10482 //Table will return 32 for upper case letters only.
10483 //0 will be returned for all others.
10484 ac += upper_to_lower_case_table[ac];
10485 bc += upper_to_lower_case_table[bc];
10487 //Return if a & b are different.
10498 // Use vectorized implementation if it is supported on this platform.
10499 mDNSlocal void setSameDomainLabelPointer(void)
10501 if(_cpu_capabilities & kHasSSE4_1)
10504 SameDomainLabelPointer = vectorSameDomainLabel;
10505 LogMsg("setSameDomainLabelPointer: using vector code");
10508 LogMsg("setSameDomainLabelPointer: using scalar code");
10511 #endif // TARGET_OS_EMBEDDED
10513 // Original SameDomainLabel() implementation.
10514 mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10517 const int len = *a++;
10519 if (len > MAX_DOMAIN_LABEL)
10520 { debugf("Malformed label (too long)"); return(mDNSfalse); }
10522 if (len != *b++) return(mDNSfalse);
10523 for (i=0; i<len; i++)
10527 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
10528 if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
10529 if (ac != bc) return(mDNSfalse);
10534 mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10536 return (*SameDomainLabelPointer)(a, b);
10539 #endif // APPLE_OSX_mDNSResponder
10543 #include "../unittests/mdns_macosx_ut.c"