Imported Upstream version 878.70.2
[platform/upstream/mdnsresponder.git] / mDNSMacOSX / mDNSMacOSX.c
1 /* -*- Mode: C; tab-width: 4 -*-
2  *
3  * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
4  *
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
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 // ***************************************************************************
19 // mDNSMacOSX.c:
20 // Supporting routines to run mDNS on a CFRunLoop platform
21 // ***************************************************************************
22
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
26
27 #include "mDNSEmbeddedAPI.h"        // Defines the interface provided to the client layer above
28 #include "DNSCommon.h"
29 #include "uDNS.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"
36
37 #include <stdio.h>
38 #include <stdarg.h>                 // For va_list support
39 #include <stdlib.h>                 // For arc4random
40 #include <net/if.h>
41 #include <net/if_types.h>           // For IFT_ETHER
42 #include <net/if_dl.h>
43 #include <net/bpf.h>                // For BIOCSETIF etc.
44 #include <sys/uio.h>
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <sys/sysctl.h>
48 #include <sys/event.h>
49 #include <fcntl.h>
50 #include <sys/ioctl.h>
51 #include <time.h>                   // platform support for UTC time
52 #include <arpa/inet.h>              // for inet_aton
53 #include <pthread.h>
54 #include <netdb.h>                  // for getaddrinfo
55 #include <sys/sockio.h>             // for SIOCGIFEFLAGS
56 #include <notify.h>
57 #include <netinet/in.h>             // For IP_RECVTTL
58 #ifndef IP_RECVTTL
59 #define IP_RECVTTL 24               // bool; receive reception TTL w/dgram
60 #endif
61
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.
65
66 #include <netinet/tcp.h>
67
68 #include <DebugServices.h>
69 #include "dnsinfo.h"
70
71 #include <ifaddrs.h>
72
73 #include <IOKit/IOKitLib.h>
74 #include <IOKit/IOMessage.h>
75
76 #include <IOKit/ps/IOPowerSources.h>
77 #include <IOKit/ps/IOPowerSourcesPrivate.h>
78 #include <IOKit/ps/IOPSKeys.h>
79
80 #include <mach/mach_error.h>
81 #include <mach/mach_port.h>
82 #include <mach/mach_time.h>
83 #include "helper.h"
84 #include "P2PPacketFilter.h"
85
86 #include <SystemConfiguration/SCPrivate.h>
87
88 #if TARGET_OS_IPHONE
89 // For WiFiManagerClientRef etc, declarations.
90 #include <MobileGestalt.h>
91 #include <MobileWiFi/WiFiManagerClient.h>
92 #include <dlfcn.h>
93 #endif // TARGET_OS_IPHONE
94
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
98
99 #if APPLE_OSX_mDNSResponder
100 #include <AWACS.h>
101 #include <ne_session.h> // for ne_session_set_socket_attributes()
102 #else
103 #define NO_AWACS 1
104 #endif // APPLE_OSX_mDNSResponder
105
106 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
107 #include <IOKit/platform/IOPlatformSupportPrivate.h>
108 #endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
109
110 #ifdef UNIT_TEST
111 #include "unittest.h"
112 #endif
113
114 #define kInterfaceSpecificOption "interface="
115
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'
120
121 #define DARK_WAKE_TIME 16 // Time we hold an idle sleep assertion for maintenance after a wake notification
122
123 // cache the InterfaceID of the AWDL interface 
124 mDNSInterfaceID AWDLInterfaceID;
125
126 // ***************************************************************************
127 // Globals
128
129 #if COMPILER_LIKES_PRAGMA_MARK
130 #pragma mark - Globals
131 #endif
132
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
140
141 mDNSexport int OSXVers, iOSVers;
142 mDNSexport int KQueueFD;
143
144 #ifndef NO_SECURITYFRAMEWORK
145 static CFArrayRef ServerCerts;
146 OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
147 #endif /* NO_SECURITYFRAMEWORK */
148
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");
159
160 static char HINFO_HWstring_buffer[32];
161 static char *HINFO_HWstring = "Device";
162 static int HINFO_HWstring_prefixlen = 6;
163
164 mDNSexport int WatchDogReportingThreshold = 250;
165
166 dispatch_queue_t SSLqueue;
167
168 #if TARGET_OS_EMBEDDED
169 #define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
170 #endif
171
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
181
182 // Don't send triggers too often. We arbitrarily limit it to three minutes.
183 #define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
184
185 // Used by AutoTunnel
186 const char btmmprefix[] = "btmmdns:";
187 const char dnsprefix[] = "dns:";
188
189 // String Array used to write list of private domains to Dynamic Store
190 static CFArrayRef privateDnsArray = NULL;
191
192 // ***************************************************************************
193 // Functions
194
195 #if COMPILER_LIKES_PRAGMA_MARK
196 #pragma mark -
197 #pragma mark - Utility Functions
198 #endif
199
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.
206
207 #if BONJOUR_ON_DEMAND
208 #define MulticastInterface(i) ((i)->m->BonjourEnabled && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
209 #else
210 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
211 #endif
212 #define SPSInterface(i)       ((i)->ifinfo.McastTxRx && !((i)->ifa_flags & IFF_LOOPBACK) && !(i)->D2DInterface)
213
214 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg)  // Both strings are UTF-8 text
215 {
216     // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
217     #if !ForceAlerts
218     {
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)
223                 break;
224         if (!i) 
225             return; // If not at Apple, don't show the alert
226     }
227     #endif
228
229     LogMsg("NotifyOfElusiveBug: %s", title);
230     LogMsg("NotifyOfElusiveBug: %s", msg);
231
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))
235     { 
236         LogMsg("Suppressing notification early in boot: %d", mDNSPlatformRawTime()); 
237         return; 
238     }
239
240 #ifndef NO_CFUSERNOTIFICATION
241     static int notifyCount = 0; // To guard against excessive display of warning notifications
242     if (notifyCount < 5) 
243     { 
244         notifyCount++; 
245         mDNSNotify(title, msg); 
246     }
247 #endif /* NO_CFUSERNOTIFICATION */
248
249 }
250
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, ...)
254 {
255     char buffer[512];
256     va_list ptr;
257     va_start(ptr,format);
258     buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
259     va_end(ptr);
260     LogMsg("!!!! %s !!!!", buffer);
261     NotifyOfElusiveBug("Memory Corruption", buffer);
262 #if ForceAlerts
263     *(volatile long*)0 = 0;  // Trick to crash and get a stack trace right here, if that's what we want
264 #endif
265 }
266 #endif
267
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, ...)
271 {
272     char buffer[512];
273     va_list ptr;
274     va_start(ptr,format);
275     buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
276     va_end(ptr);
277     LogMsg("!!!! %s !!!!", buffer);
278 #if ForceAlerts
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
281 #endif
282 }
283 #endif
284
285 // Returns true if it is an AppleTV based hardware running iOS, false otherwise
286 mDNSlocal mDNSBool IsAppleTV(void)
287 {
288 #if TARGET_OS_EMBEDDED
289     static mDNSBool sInitialized = mDNSfalse;
290     static mDNSBool sIsAppleTV   = mDNSfalse;
291     CFStringRef deviceClass = NULL;
292
293     if(!sInitialized)
294     {
295         deviceClass = (CFStringRef) MGCopyAnswer(kMGQDeviceClass, NULL);
296         if(deviceClass)
297         {
298             if(CFEqual(deviceClass, kMGDeviceClassAppleTV))
299                 sIsAppleTV = mDNStrue;
300             CFRelease(deviceClass);
301         }
302         sInitialized = mDNStrue;
303     }
304     return(sIsAppleTV);
305 #else 
306     return mDNSfalse;
307 #endif // TARGET_OS_EMBEDDED
308 }
309
310 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
311 {
312     static struct ifaddrs *ifa = NULL;
313
314     if (refresh && ifa)
315     {
316         freeifaddrs(ifa);
317         ifa = NULL;
318     }
319
320     if (ifa == NULL) 
321         getifaddrs(&ifa);
322     return ifa;
323 }
324
325 mDNSlocal void DynamicStoreWrite(int key, const char* subkey, uintptr_t value, signed long valueCnt)
326 {
327     CFStringRef sckey       = NULL;
328     Boolean release_sckey   = FALSE;
329     CFDataRef bytes         = NULL;
330     CFPropertyListRef plist = NULL;
331
332     switch ((enum mDNSDynamicStoreSetConfigKey)key)
333     {
334         case kmDNSMulticastConfig:
335             sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
336             break;
337         case kmDNSDynamicConfig:
338             sckey = CFSTR("State:/Network/DynamicDNS");
339             break;
340         case kmDNSPrivateConfig:
341             sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
342             break;
343         case kmDNSBackToMyMacConfig:
344             sckey = CFSTR("State:/Network/BackToMyMac");
345             break;
346         case kmDNSSleepProxyServersState:
347         {
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;
354             CFRelease(tmp);
355             break;
356         }
357         case kmDNSDebugState:
358             sckey = CFSTR("State:/Network/mDNSResponder/DebugState");
359             break;
360         default:
361             LogMsg("unrecognized key %d", key);
362             goto fin;
363     }
364     if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
365                                                      valueCnt, kCFAllocatorNull)))
366     {
367         LogMsg("CFDataCreateWithBytesNoCopy of value failed");
368         goto fin;
369     }
370     if (NULL == (plist = CFPropertyListCreateWithData(NULL, bytes, kCFPropertyListImmutable, NULL, NULL)))
371     {
372         LogMsg("CFPropertyListCreateWithData of bytes failed");
373         goto fin;
374     }
375     CFRelease(bytes);
376     bytes = NULL;
377     SCDynamicStoreSetValue(NULL, sckey, plist);
378
379 fin:
380     if (NULL != bytes)
381         CFRelease(bytes);
382     if (NULL != plist)
383         CFRelease(plist);
384     if (release_sckey && sckey)
385         CFRelease(sckey);
386 }
387
388 mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value)
389 {
390     CFPropertyListRef valueCopy;
391     char *subkeyCopy  = NULL;
392     if (!value)
393         return;
394
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);
398     if (!valueCopy)
399     {   
400         LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
401         return;
402     }
403     if (subkey)
404     {
405         int len    = strlen(subkey);
406         subkeyCopy = mDNSPlatformMemAllocate(len + 1);
407         if (!subkeyCopy)
408         {
409             LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
410             CFRelease(valueCopy);
411             return;
412         }
413         mDNSPlatformMemCopy(subkeyCopy, subkey, len);
414         subkeyCopy[len] = 0;
415     }
416
417     dispatch_async(dispatch_get_main_queue(), ^{
418         CFWriteStreamRef stream = NULL;
419         CFDataRef bytes = NULL;
420         CFIndex ret;
421         KQueueLock();
422
423         if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL)))
424         {
425             LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
426             goto END;
427         }
428         CFWriteStreamOpen(stream);
429         ret = CFPropertyListWrite(valueCopy, stream, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
430         if (ret == 0)
431         {
432             LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
433             goto END;
434         }
435         if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten)))
436         {
437             LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
438             goto END;
439         }
440         CFWriteStreamClose(stream);
441         CFRelease(stream);
442         stream = NULL;
443         DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes));
444
445     END:
446         CFRelease(valueCopy);
447         if (NULL != stream)
448         {
449             CFWriteStreamClose(stream);
450             CFRelease(stream);
451         }
452         if (NULL != bytes)
453             CFRelease(bytes); 
454         if (subkeyCopy)
455             mDNSPlatformMemFree(subkeyCopy);
456
457         KQueueUnlock("mDNSDynamicStoreSetConfig");
458     });
459 }
460
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)
463 {
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);
470     return(NULL);
471 }
472
473 mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
474 {
475     struct ifaddrs *ifa;
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; }
480     return -1;
481 }
482
483 mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(mDNSInterfaceID ifindex)
484 {
485     mDNS *const m = &mDNSStorage;
486     mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
487     NetworkInterfaceInfoOSX *i;
488
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);
492
493     return mDNSNULL;
494 }
495
496 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
497 {
498     (void) m;
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);
503
504     NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
505     if (!ifi)
506     {
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);
511     }
512
513     if (!ifi) return(mDNSNULL);
514
515     return(ifi->ifinfo.InterfaceID);
516 }
517
518
519 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
520 {
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);
527
528     mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
529
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);
533
534     // If we are supposed to suppress network change, return "id" back
535     if (suppressNetworkChange) return scope_id;
536
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);
542
543     return(0);
544 }
545
546 #if COMPILER_LIKES_PRAGMA_MARK
547 #pragma mark -
548 #pragma mark - UDP & TCP send & receive
549 #endif
550
551 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
552 {
553     mDNSBool result = mDNSfalse;
554     SCNetworkConnectionFlags flags;
555     CFDataRef remote_addr;
556     CFMutableDictionaryRef options;
557     SCNetworkReachabilityRef ReachRef = NULL;
558
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);
564     CFRelease(options);
565     CFRelease(remote_addr);
566
567     if (!ReachRef) 
568     { 
569         LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions"); 
570         goto end; 
571     }
572     if (!SCNetworkReachabilityGetFlags(ReachRef, &flags)) 
573     { 
574         LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); 
575         goto end; 
576     }
577     result = flags & kSCNetworkFlagsConnectionRequired;
578
579 end:
580     if (ReachRef) 
581         CFRelease(ReachRef);
582     return result;
583 }
584
585 // Set traffic class for socket
586 mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass)
587 {
588     int traffic_class;
589
590     if (useBackgroundTrafficClass)
591         traffic_class = SO_TC_BK_SYS;
592     else
593         traffic_class = SO_TC_CTL;
594
595     (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class));
596 }
597
598 #ifdef UNIT_TEST
599 // Run the unit test main
600 UNITTEST_SETSOCKOPT
601 #else
602 mDNSlocal int mDNSPlatformGetSocktFd(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType)
603 {
604     if (transType == mDNSTransport_UDP)
605     {
606         UDPSocket* sock = (UDPSocket*) sockCxt;
607         return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6;
608     }
609     else if (transType == mDNSTransport_TCP)
610     {
611         TCPSocket* sock = (TCPSocket*) sockCxt;
612         return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6;
613     }
614     else
615     {
616         LogInfo("mDNSPlatformGetSocktFd: invalid transport %d", transType);
617         return kInvalidSocketRef;
618     }
619 }
620
621 mDNSexport void mDNSPlatformSetSocktOpt(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType, const DNSQuestion *q)
622 {
623     int sockfd;
624     char unenc_name[MAX_ESCAPED_DOMAIN_NAME];
625
626     // verify passed-in arguments exist and that sockfd is valid
627     if (q == mDNSNULL || sockCxt == mDNSNULL || (sockfd = mDNSPlatformGetSocktFd(sockCxt, transType, addrType)) < 0)
628         return;
629
630     if (q->pid)
631     {
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);
634     }
635     else
636     {
637         if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1)
638             LogMsg("mDNSPlatformSetSocktOpt: Delegate UUID failed %s", strerror(errno));
639     }
640
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);
645
646     int nowake = 1;
647     if (setsockopt(sockfd, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
648         LogInfo("mDNSPlatformSetSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
649 }
650 #endif // UNIT_TEST
651
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)
659 {
660     NetworkInterfaceInfoOSX *info = mDNSNULL;
661     struct sockaddr_storage to;
662     int s = -1, err;
663     mStatus result = mStatus_NoError;
664     int sendto_errno;
665
666     if (InterfaceID)
667     {
668         info = IfindexToInterfaceInfoOSX(InterfaceID);
669         if (info == NULL)
670         {
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;
677         }
678     }
679
680     char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
681
682     if (dst->type == mDNSAddrType_IPv4)
683     {
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;
690
691         if (!mDNSAddrIsDNSMulticast(dst))
692         {
693         #ifdef IP_BOUND_IF
694             const mDNSu32 ifindex = info ? info->scope_id : IFSCOPE_NONE;
695             setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
696         #else
697             static int displayed = 0;
698             if (displayed < 1000)
699             {
700                 displayed++;
701                 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
702             }
703         #endif
704         }
705         else if (info)
706         {
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
711             if (err < 0)
712             {
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));
717             }
718         #else
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));
722         #endif
723         }
724     }
725     else if (dst->type == mDNSAddrType_IPv6)
726     {
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
736         {
737             err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
738             if (err < 0)
739             {
740                 const int setsockopt_errno = errno;
741                 char name[IFNAMSIZ];
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));
744                 else
745                     LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id);
746             }
747         }
748 #ifdef IPV6_BOUND_IF
749         if (info)   // Specify outgoing interface for non-multicast destination
750         {
751             if (!mDNSAddrIsDNSMulticast(dst))
752             {
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);
755                 else
756                     setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
757             }
758         }
759 #endif
760     }
761
762     else
763     {
764         LogFatalError("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
765         return mStatus_BadParamErr;
766     }
767
768     if (s >= 0)
769         verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
770                       InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
771     else
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));
774
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);
778
779     // switch to background traffic class for this message if requested
780     if (useBackgroundTrafficClass)
781         setTrafficClass(s, useBackgroundTrafficClass);
782
783     err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
784     sendto_errno = (err < 0) ? errno : 0;
785
786     // set traffic class back to default value
787     if (useBackgroundTrafficClass)
788         setTrafficClass(s, mDNSfalse);
789
790     if (err < 0)
791     {
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))
796         {
797             if (sendto_errno == EHOSTUNREACH) return(mStatus_HostUnreachErr);
798             if (sendto_errno == EHOSTDOWN || sendto_errno == ENETDOWN || sendto_errno == ENETUNREACH) return(mStatus_TransientErr);
799         }
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));
809         else
810         {
811             MessageCount++;
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);
818         }
819
820         result = mStatus_UnknownErr;
821     }
822
823     return(result);
824 }
825
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)
828 {
829     static unsigned int numLogMessages = 0;
830     struct iovec databuffers = { (char *)buffer, max };
831     struct msghdr msg;
832     ssize_t n;
833     struct cmsghdr *cmPtr;
834     char ancillary[1024];
835
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
837
838     // Set up the message
839     msg.msg_name       = (caddr_t)from;
840     msg.msg_namelen    = *fromlen;
841     msg.msg_iov        = &databuffers;
842     msg.msg_iovlen     = 1;
843     msg.msg_control    = (caddr_t)&ancillary;
844     msg.msg_controllen = sizeof(ancillary);
845     msg.msg_flags      = 0;
846
847     // Receive the data
848     n = recvmsg(s, &msg, 0);
849     if (n<0)
850     {
851         if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
852         return(-1);
853     }
854     if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
855     {
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);
858         return(-1);
859     }
860     if (msg.msg_flags & MSG_CTRUNC)
861     {
862         if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
863         return(-1);
864     }
865
866     *fromlen = msg.msg_namelen;
867
868     // Parse each option out of the ancillary data.
869     for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
870     {
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)
873         {
874             dstaddr->type = mDNSAddrType_IPv4;
875             dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
876             //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
877         }
878         if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
879         {
880             struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
881             if (sdl->sdl_nlen < IF_NAMESIZE)
882             {
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);
886             }
887         }
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)
891         {
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);
896         }
897         if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
898             *ttl = *(int*)CMSG_DATA(cmPtr);
899     }
900
901     return(n);
902 }
903
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)
906 {
907     NetworkInterfaceInfo *intf;
908
909     if (addr->type == mDNSAddrType_IPv4)
910     {
911         for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
912         {
913             if (intf->ip.type == addr->type && intf->McastTxRx)
914             {
915                 if ((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) == 0)
916                 {
917                     return(intf->InterfaceID);
918                 }
919             }
920         }
921     }
922
923     if (addr->type == mDNSAddrType_IPv6)
924     {
925         for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
926         {
927             if (intf->ip.type == addr->type && intf->McastTxRx)
928             {
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)))
933                     {
934                         return(intf->InterfaceID);
935                     }
936             }
937         }
938     }
939     return(mDNSInterface_Any);
940 }
941
942 mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool encounteredEOF)
943 {
944     KQSocketSet *const ss = (KQSocketSet *)context;
945     mDNS *const m = ss->m;
946     int err = 0, count = 0, closed = 0;
947
948     if (filter != EVFILT_READ)
949         LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
950
951     if (s1 != ss->sktv4 && s1 != ss->sktv6)
952     {
953         LogMsg("myKQSocketCallBack: native socket %d", s1);
954         LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6);
955     }
956
957     if (encounteredEOF)
958     {
959         LogMsg("myKQSocketCallBack: socket %d is no longer readable (EOF)", s1);
960         if (s1 == ss->sktv4)
961         {
962             ss->sktv4EOF = mDNStrue;
963             KQueueSet(ss->sktv4, EV_DELETE, EVFILT_READ, &ss->kqsv4);
964         }
965         else if (s1 == ss->sktv6)
966         {
967             ss->sktv6EOF = mDNStrue;
968             KQueueSet(ss->sktv6, EV_DELETE, EVFILT_READ, &ss->kqsv6);
969         }
970         return;
971     }
972
973     while (!closed)
974     {
975         mDNSAddr senderAddr, destAddr = zeroAddr;
976         mDNSIPPort senderPort;
977         struct sockaddr_storage from;
978         size_t fromlen = sizeof(from);
979         char packetifname[IF_NAMESIZE] = "";
980         mDNSu8 ttl;
981         err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
982         if (err < 0) break;
983
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++;
986
987         count++;
988         if (from.ss_family == AF_INET)
989         {
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);
995         }
996         else if (from.ss_family == AF_INET6)
997         {
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);
1003         }
1004         else
1005         {
1006             LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
1007             return;
1008         }
1009
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;
1013         while (intf) 
1014         {
1015             if (intf->Exists && !strcmp(intf->ifinfo.ifname, packetifname))
1016                 break;
1017             intf = intf->next;
1018         }
1019
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.
1025         if (intf)
1026             InterfaceID = intf->ifinfo.InterfaceID;
1027         else if (mDNSAddrIsDNSMulticast(&destAddr))
1028             continue;
1029
1030         if (!InterfaceID)
1031         {
1032             InterfaceID = FindMyInterface(&destAddr);
1033         }
1034
1035 //              LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1036 //                      &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
1037
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;
1043
1044         if (ss->proxy)
1045         {
1046             m->p->UDPProxyCallback(&m->p->UDPProxy, &m->imsg.m, (unsigned char*)&m->imsg + err, &senderAddr,
1047                 senderPort, &destAddr, ss->port, InterfaceID, NULL);
1048         }
1049         else
1050         {
1051             mDNSCoreReceive(m, &m->imsg.m, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
1052         }
1053
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;
1057     }
1058
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)
1063     {
1064         LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
1065         close(s1);
1066         return;
1067     }
1068
1069     if (err < 0 && (errno != EWOULDBLOCK || count == 0))
1070     {
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;
1078         int so_error = -1;
1079         int so_nread = -1;
1080         int fionread = -1;
1081         socklen_t solen = sizeof(int);
1082         fd_set readfds;
1083         struct timeval timeout;
1084         int selectresult;
1085         FD_ZERO(&readfds);
1086         FD_SET(s1, &readfds);
1087         timeout.tv_sec  = 0;
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.");
1104
1105         sleep(1);       // After logging this error, rate limit so we don't flood syslog
1106     }
1107 }
1108
1109 mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
1110 {
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!
1115 }
1116
1117 #ifndef NO_SECURITYFRAMEWORK
1118
1119 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
1120 {
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); }
1124     *dataLength = 0;
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);
1130 }
1131
1132 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
1133 {
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); }
1137     *dataLength = 0;
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);
1143 }
1144
1145 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConnectionType ctype)
1146 {
1147     char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
1148
1149     sock->tlsContext = SSLCreateContext(kCFAllocatorDefault, pside, ctype);
1150     if (!sock->tlsContext) 
1151     { 
1152         LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed"); 
1153         return(mStatus_UnknownErr); 
1154     }
1155
1156     mStatus err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
1157     if (err) 
1158     { 
1159         LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err); 
1160         goto fail; 
1161     }
1162
1163     err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
1164     if (err) 
1165     { 
1166         LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err); 
1167         goto fail; 
1168     }
1169
1170     // Set the default ciphersuite configuration
1171     err = SSLSetSessionConfig(sock->tlsContext, CFSTR("default"));
1172     if (err) 
1173     {
1174         LogMsg("ERROR: tlsSetupSock: SSLSetSessionConfig failed with error code: %d", err);
1175         goto fail;
1176     }
1177
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]) 
1181     {
1182         LogMsg("ERROR: tlsSetupSock: hostname NULL"); 
1183         err = -1;
1184         goto fail;
1185     }
1186
1187     ConvertDomainNameToCString(&sock->hostname, domname_cstr);
1188     err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
1189     if (err) 
1190     { 
1191         LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err); 
1192         goto fail; 
1193     }
1194
1195     return(err);
1196
1197 fail:
1198     if (sock->tlsContext)
1199         CFRelease(sock->tlsContext);
1200     return(err);
1201 }
1202
1203 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1204 mDNSlocal void doSSLHandshake(TCPSocket *sock)
1205 {
1206     mStatus err = SSLHandshake(sock->tlsContext);
1207
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
1210     //
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
1218     //is already freed.
1219
1220     dispatch_async(dispatch_get_main_queue(), ^{
1221
1222                        LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1223
1224                        if (sock->handshake == handshake_to_be_closed)
1225                        {
1226                            LogInfo("SSLHandshake completed after close");
1227                            mDNSPlatformTCPCloseConnection(sock);
1228                        }
1229                        else
1230                        {
1231                            if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1232                            else LogMsg("doSSLHandshake: sock->fd is -1");
1233
1234                            if (err == errSSLWouldBlock)
1235                                sock->handshake = handshake_required;
1236                            else
1237                            {
1238                                if (err)
1239                                {
1240                                    LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1241                                    CFRelease(sock->tlsContext);
1242                                    sock->tlsContext = NULL;
1243                                }
1244
1245                                sock->err = err ? mStatus_ConnFailed : 0;
1246                                sock->handshake = handshake_completed;
1247
1248                                LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1249                                doTcpSocketCallback(sock);
1250                            }
1251                        }
1252
1253                        LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1254                        return;
1255                    });
1256 }
1257 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1258 mDNSlocal void *doSSLHandshake(TCPSocket *sock)
1259 {
1260     // Warning: Touching sock without the kqueue lock!
1261     // We're protected because sock->handshake == handshake_in_progress
1262     mStatus err = SSLHandshake(sock->tlsContext);
1263
1264     KQueueLock();
1265     debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1266
1267     if (sock->handshake == handshake_to_be_closed)
1268     {
1269         LogInfo("SSLHandshake completed after close");
1270         mDNSPlatformTCPCloseConnection(sock);
1271     }
1272     else
1273     {
1274         if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1275         else LogMsg("doSSLHandshake: sock->fd is -1");
1276
1277         if (err == errSSLWouldBlock)
1278             sock->handshake = handshake_required;
1279         else
1280         {
1281             if (err)
1282             {
1283                 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1284                 CFRelease(sock->tlsContext);
1285                 sock->tlsContext = NULL;
1286             }
1287
1288             sock->err = err ? mStatus_ConnFailed : 0;
1289             sock->handshake = handshake_completed;
1290
1291             debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1292             doTcpSocketCallback(sock);
1293         }
1294     }
1295
1296     debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1297     KQueueUnlock("doSSLHandshake");
1298     return NULL;
1299 }
1300 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1301
1302 mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
1303 {
1304     debugf("spawnSSLHandshake %p: entry", sock);
1305
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);
1309
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);});
1313
1314     debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
1315 }
1316
1317 #endif /* NO_SECURITYFRAMEWORK */
1318
1319 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context, __unused mDNSBool encounteredEOF)
1320 {
1321     TCPSocket *sock = context;
1322     sock->err = mStatus_NoError;
1323
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);
1329
1330     if (sock->flags & kTCPSocketFlags_UseTLS)
1331     {
1332 #ifndef NO_SECURITYFRAMEWORK
1333         if (!sock->setup) 
1334         { 
1335             sock->setup = mDNStrue; 
1336             sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
1337             if (sock->err)
1338             {
1339                 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
1340                 return;
1341             }
1342         }
1343         if (sock->handshake == handshake_required) 
1344         { 
1345             spawnSSLHandshake(sock); 
1346             return;
1347         }
1348         else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
1349         {
1350             return;
1351         }
1352         else if (sock->handshake != handshake_completed)
1353         {
1354             if (!sock->err) 
1355                 sock->err = mStatus_UnknownErr;
1356             LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
1357         }
1358 #else  /* NO_SECURITYFRAMEWORK */ 
1359         sock->err = mStatus_UnsupportedErr;
1360 #endif /* NO_SECURITYFRAMEWORK */
1361     }
1362
1363     doTcpSocketCallback(sock);
1364 }
1365
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)
1368 {
1369     dispatch_queue_t queue = dispatch_get_main_queue();
1370     dispatch_source_t source;
1371     if (flags == EV_DELETE)
1372     {
1373         if (filter == EVFILT_READ)
1374         {
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);
1379         }
1380         else if (filter == EVFILT_WRITE)
1381         {
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);
1386         }
1387         else
1388             LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
1389         return 0;
1390     }
1391     if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
1392
1393     if (filter == EVFILT_READ)
1394     {
1395         source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
1396     }
1397     else if (filter == EVFILT_WRITE)
1398     {
1399         source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
1400     }
1401     else
1402     {
1403         LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
1404         return -1;
1405     }
1406     if (!source) return -1;
1407     dispatch_source_set_event_handler(source, ^{
1408
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);
1414
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
1417                                           // get merged
1418                                           TriggerEventCompletion();
1419
1420                                       });
1421     dispatch_source_set_cancel_handler(source, ^{
1422                                            if (entryRef->fdClosed)
1423                                            {
1424                                                //LogMsg("CancelHandler: closing fd %d", fd);
1425                                                close(fd);
1426                                            }
1427                                        });
1428     dispatch_resume(source);
1429     if (filter == EVFILT_READ)
1430         entryRef->readSource = source;
1431     else
1432         entryRef->writeSource = source;
1433
1434     return 0;
1435 }
1436
1437 mDNSexport void KQueueLock()
1438 {
1439 }
1440 mDNSexport void KQueueUnlock(const char const *task)
1441 {
1442     (void)task; //unused
1443 }
1444 #else
1445 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
1446 {
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;
1450 }
1451
1452 mDNSexport void KQueueLock()
1453 {
1454     mDNS *const m = &mDNSStorage;
1455     pthread_mutex_lock(&m->p->BigMutex);
1456     m->p->BigMutexStartTime = mDNSPlatformRawTime();
1457 }
1458
1459 mDNSexport void KQueueUnlock(const char* task)
1460 {
1461     mDNS *const m = &mDNSStorage;
1462     mDNSs32 end = mDNSPlatformRawTime();
1463     (void)task;
1464     if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
1465         LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
1466
1467     pthread_mutex_unlock(&m->p->BigMutex);
1468
1469     char wake = 1;
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));
1472 }
1473 #endif
1474
1475 mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
1476 {
1477 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1478         (void) fd; //unused
1479     if (kq->readSource)
1480     {
1481         dispatch_source_cancel(kq->readSource);
1482         kq->readSource = mDNSNULL;
1483     }
1484     if (kq->writeSource)
1485     {
1486         dispatch_source_cancel(kq->writeSource);
1487         kq->writeSource = mDNSNULL;
1488     }
1489     // Close happens in the cancellation handler
1490     debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
1491     kq->fdClosed = mDNStrue;
1492 #else
1493     (void)kq; //unused
1494     close(fd);
1495 #endif
1496 }
1497
1498 mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
1499 {
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
1504     mStatus err;
1505
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); }
1508
1509     // for TCP sockets, the traffic class is set once and not changed
1510     setTrafficClass(skt, useBackgroundTrafficClass);
1511
1512     if (sa_family == AF_INET)
1513     {
1514         // Bind it
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; }
1521
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; }
1525
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; }
1530
1531         port->NotAnInteger = addr.sin_port;
1532     }
1533     else
1534     {
1535         // Bind it
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; }
1542
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; }
1546
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; }
1551
1552         port->NotAnInteger = addr6.sin6_port;
1553
1554     }
1555     *s = skt;
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;
1563 #endif
1564     return mStatus_NoError;
1565 }
1566
1567 mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
1568 {
1569     mStatus err;
1570
1571     TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
1572     if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
1573
1574     mDNSPlatformMemZero(sock, sizeof(TCPSocket));
1575
1576     sock->ss.m     = &mDNSStorage;
1577     sock->ss.sktv4 = -1;
1578     sock->ss.sktv6 = -1;
1579     err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
1580
1581     if (!err)
1582     {
1583         err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass);
1584         if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
1585     }
1586     if (err)
1587     {
1588         LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
1589         freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
1590         return(mDNSNULL);
1591     }
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;
1602
1603     return sock;
1604 }
1605
1606 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
1607 {
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;
1613
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;
1620
1621     if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
1622
1623     if (dst->type == mDNSAddrType_IPv4)
1624     {
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;
1631     }
1632     else
1633     {
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;
1640     }
1641
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))
1645     {
1646         LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1647         return errno;
1648     }
1649
1650     // Watch for incoming data
1651     if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
1652     {
1653         LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1654         return errno;
1655     }
1656
1657     if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
1658     {
1659         LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
1660         return mStatus_UnknownErr;
1661     }
1662
1663     // We bind to the interface and all subsequent packets including the SYN will be sent out
1664     // on this interface
1665     //
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)
1669     {
1670         NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(InterfaceID);
1671         if (dst->type == mDNSAddrType_IPv4)
1672         {
1673         #ifdef IP_BOUND_IF
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; }
1676         #else
1677             (void)InterfaceID; // Unused
1678             (void)info; // Unused
1679         #endif
1680         }
1681         else
1682         {
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; }
1686         #else
1687             (void)InterfaceID; // Unused
1688             (void)info; // Unused
1689         #endif
1690         }
1691     }
1692
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.
1696     sock->fd = *s;
1697     sock->kqEntry = k;
1698     // initiate connection wth peer
1699     if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
1700     {
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));
1704         else
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;
1707     }
1708
1709     LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1710     // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1711     return err;
1712 }
1713
1714 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1715 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
1716 {
1717     mStatus err = mStatus_NoError;
1718
1719     TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
1720     if (!sock) return(mDNSNULL);
1721
1722     mDNSPlatformMemZero(sock, sizeof(*sock));
1723     sock->fd = fd;
1724     sock->flags = flags;
1725
1726     if (flags & kTCPSocketFlags_UseTLS)
1727     {
1728 #ifndef NO_SECURITYFRAMEWORK
1729         if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
1730
1731         err = tlsSetupSock(sock, kSSLServerSide, kSSLStreamType);
1732         if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
1733
1734         err = SSLSetCertificate(sock->tlsContext, ServerCerts);
1735         if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
1736 #else
1737         err = mStatus_UnsupportedErr;
1738 #endif /* NO_SECURITYFRAMEWORK */
1739     }
1740 #ifndef NO_SECURITYFRAMEWORK
1741 exit:
1742 #endif
1743
1744     if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
1745     return(sock);
1746 }
1747
1748 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
1749 {
1750     mDNSu16 port;
1751
1752     port = -1;
1753     if (sock)
1754     {
1755         port = sock->ss.port.NotAnInteger;
1756     }
1757     return port;
1758 }
1759
1760 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
1761 {
1762     if (ss->sktv4 != -1)
1763     {
1764         mDNSPlatformCloseFD(&ss->kqsv4,  ss->sktv4);
1765         ss->sktv4 = -1;
1766     }
1767     if (ss->sktv6 != -1)
1768     {
1769         mDNSPlatformCloseFD(&ss->kqsv6,  ss->sktv6);
1770         ss->sktv6 = -1;
1771     }
1772     if (ss->closeFlag) *ss->closeFlag = 1;
1773 }
1774
1775 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
1776 {
1777     if (sock)
1778     {
1779 #ifndef NO_SECURITYFRAMEWORK
1780         if (sock->tlsContext)
1781         {
1782             if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
1783             {
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;
1788                 return;
1789             }
1790
1791             SSLClose(sock->tlsContext);
1792             CFRelease(sock->tlsContext);
1793             sock->tlsContext = NULL;
1794         }
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);
1801         sock->fd = -1;
1802
1803         freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
1804     }
1805 }
1806
1807 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
1808 {
1809     ssize_t nread = 0;
1810     *closed = mDNSfalse;
1811
1812     if (sock->flags & kTCPSocketFlags_UseTLS)
1813     {
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);
1818
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; }
1825 #else
1826         nread = -1;
1827         *closed = mDNStrue;
1828 #endif /* NO_SECURITYFRAMEWORK */
1829     }
1830     else
1831     {
1832         static int CLOSEDcount = 0;
1833         static int EAGAINcount = 0;
1834         nread = recv(sock->fd, buf, buflen, 0);
1835
1836         if (nread > 0) 
1837         { 
1838             CLOSEDcount = 0; 
1839             EAGAINcount = 0; 
1840         } // On success, clear our error counters
1841         else if (nread == 0)
1842         {
1843             *closed = mDNStrue;
1844             if ((++CLOSEDcount % 1000) == 0) 
1845             { 
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
1853             }
1854         }
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
1859         {
1860             nread = 0;
1861             if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
1862         }
1863     }
1864
1865     return nread;
1866 }
1867
1868 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
1869 {
1870     int nsent;
1871
1872     if (sock->flags & kTCPSocketFlags_UseTLS)
1873     {
1874 #ifndef NO_SECURITYFRAMEWORK
1875         size_t processed;
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);
1879
1880         mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
1881
1882         if (!err) nsent = (int) processed;
1883         else if (err == errSSLWouldBlock) nsent = 0;
1884         else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
1885 #else
1886         nsent = -1;
1887 #endif /* NO_SECURITYFRAMEWORK */
1888     }
1889     else
1890     {
1891         nsent = send(sock->fd, msg, len, 0);
1892         if (nsent < 0)
1893         {
1894             if (errno == EAGAIN) nsent = 0;
1895             else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
1896         }
1897     }
1898
1899     return nsent;
1900 }
1901
1902 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
1903 {
1904     return sock->fd;
1905 }
1906
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)
1910 {
1911     int         *s        = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
1912     KQueueEntry *k        = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
1913     const int on = 1;
1914     const int twofivefive = 255;
1915     mStatus err = mStatus_NoError;
1916     char *errstr = mDNSNULL;
1917     const int mtu = 0;
1918     int saved_errno;
1919
1920     cp->closeFlag = mDNSNULL;
1921
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); }
1924
1925     // set default traffic class
1926     setTrafficClass(skt, mDNSfalse);
1927
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)) 
1933     {
1934         err = setsockopt(skt, SOL_SOCKET, SO_RECV_ANYIF, &on, sizeof(on));
1935         if (err < 0) { errstr = "setsockopt - SO_RECV_ANYIF"; goto fail; }
1936     }
1937 #endif // SO_RECV_ANYIF
1938
1939     // ... with a shared UDP port, if it's for multicast receiving
1940     if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort))
1941     {
1942         err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
1943         if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
1944     }
1945
1946     // Don't want to wake from sleep for inbound packets on the mDNS sockets
1947     if (mDNSSameIPPort(port, MulticastDNSPort)) 
1948     {
1949         int nowake = 1;
1950         if (setsockopt(skt, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
1951             LogInfo("SetupSocket: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
1952     }
1953
1954     if (sa_family == AF_INET)
1955     {
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; }
1959
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; }
1963
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; }
1967
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; }
1971
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; }
1975
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;
1984     }
1985     else if (sa_family == AF_INET6)
1986     {
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; }
1989
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; }
1993
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; }
1997
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; }
2002
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; }
2006
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; }
2010
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; }
2014
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));
2020         
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;
2033     }
2034
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
2037     *s = skt;
2038     k->KQcallback = myKQSocketCallBack;
2039     k->KQcontext  = cp;
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;
2045 #endif
2046     KQueueSet(*s, EV_ADD, EVFILT_READ, k);
2047
2048     return(mStatus_NoError);
2049
2050 fail:
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));
2055
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)
2058     {
2059         err = 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.");
2066     }
2067
2068     mDNSPlatformCloseFD(k, skt);
2069     return(err);
2070 }
2071
2072 mDNSexport UDPSocket *mDNSPlatformUDPSocket(const mDNSIPPort requestedport)
2073 {
2074     mStatus err;
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;
2083     p->ss.sktv4 = -1;
2084     p->ss.sktv6 = -1;
2085     p->ss.proxy = mDNSfalse;
2086
2087     do
2088     {
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);
2092         if (!err)
2093         {
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; }
2096         }
2097         i--;
2098     } while (err == EADDRINUSE && randomizePort && i);
2099
2100     if (err)
2101     {
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);
2110         return(mDNSNULL);
2111     }
2112     return(p);
2113 }
2114
2115 #ifdef UNIT_TEST
2116 UNITTEST_UDPCLOSE
2117 #else
2118 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
2119 {
2120     CloseSocketSet(&sock->ss);
2121     freeL("UDPSocket", sock);
2122 }
2123 #endif
2124
2125 mDNSexport mDNSBool mDNSPlatformUDPSocketEncounteredEOF(const UDPSocket *sock)
2126 {
2127     return (sock->ss.sktv4EOF || sock->ss.sktv6EOF);
2128 }
2129
2130 #if COMPILER_LIKES_PRAGMA_MARK
2131 #pragma mark -
2132 #pragma mark - BPF Raw packet sending/receiving
2133 #endif
2134
2135 #if APPLE_OSX_mDNSResponder
2136
2137 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
2138 {
2139     if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2140     NetworkInterfaceInfoOSX *info;
2141
2142     info = IfindexToInterfaceInfoOSX(InterfaceID);
2143     if (info == NULL)
2144     {
2145         LogMsg("mDNSPlatformSendRawPacket: Invalid interface index %p", InterfaceID);
2146         return;
2147     }
2148     if (info->BPF_fd < 0)
2149         LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
2150     else
2151     {
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));
2155     }
2156 }
2157
2158 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
2159 {
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);
2168     else
2169     {
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);
2173     }
2174 }
2175
2176 mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
2177 {
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);
2182 #else
2183
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);
2191 #endif
2192     i->BPF_fd = -1;
2193     if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
2194 }
2195
2196 mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
2197 {
2198     KQueueLock();
2199
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;
2203
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);
2208
2209     if (n<0)
2210     {
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
2217          */
2218         if (errno == EAGAIN)
2219         {
2220             LogMsg("bpf_callback got EAGAIN bailing");
2221             goto exit;
2222         }
2223         LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
2224         CloseBPF(info);
2225         goto exit;
2226     }
2227
2228     while (ptr < end)
2229     {
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);
2239     }
2240 exit:
2241     KQueueUnlock("bpf_callback");
2242 }
2243 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2244 mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
2245 {
2246     bpf_callback_common(info);
2247 }
2248 #else
2249 mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
2250 {
2251     (void)cfs;
2252     (void)CallBackType;
2253     (void)address;
2254     (void)data;
2255     bpf_callback_common((NetworkInterfaceInfoOSX *)context);
2256 }
2257 #endif
2258
2259 mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
2260 {
2261     LogMsg("mDNSPlatformSendKeepalive called\n");
2262     mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win);
2263 }
2264
2265 mDNSexport mStatus mDNSPlatformClearSPSData(void)
2266 {
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);
2271
2272     spsAddressKey = SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyAddress"));
2273     if (spsAddressKey != NULL)
2274     {
2275         CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, spsAddressKey);
2276         if (keyList != NULL)
2277         {
2278             if (SCDynamicStoreSetMultiple(addrStore, NULL, keyList, NULL) == false)
2279                 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr( spsAddressKey, kCFStringEncodingASCII), SCErrorString(SCError()));
2280         }
2281         if (keyList) CFRelease(keyList);
2282     }
2283     ownerOPTRecKey= SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyOPTRecord"));
2284     if(ownerOPTRecKey != NULL)
2285     {
2286         CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, ownerOPTRecKey);
2287         if (keyList != NULL)
2288         {
2289             if (SCDynamicStoreSetMultiple(optStore, NULL, keyList, NULL) == false)
2290                 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr(ownerOPTRecKey, kCFStringEncodingASCII), SCErrorString(SCError()));
2291         }
2292         if (keyList) CFRelease(keyList);
2293     }
2294
2295     if (addrStore)   CFRelease(addrStore);
2296     if (optStore)    CFRelease(optStore);
2297     if (spsAddressKey)  CFRelease(spsAddressKey);
2298     if (ownerOPTRecKey) CFRelease(ownerOPTRecKey);
2299     return KERN_SUCCESS;
2300 }
2301
2302 mDNSlocal int getMACAddress(int family, v6addr_t raddr, v6addr_t gaddr, int *gfamily, ethaddr_t eth)
2303 {
2304     struct
2305     {
2306         struct rt_msghdr m_rtm;
2307         char   m_space[512];
2308     } m_rtmsg;
2309     
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;
2318     
2319 #define NEXTADDR(w, s, len)         \
2320 if (rtm->rtm_addrs & (w))       \
2321 {                               \
2322 bcopy((char *)s, cp, len);  \
2323 cp += len;                  \
2324 }
2325     
2326     bzero(&sins,  sizeof(struct sockaddr_storage));
2327     bzero(&sdl_m, sizeof(struct sockaddr_dl));
2328     bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
2329     
2330     sock = socket(PF_ROUTE, SOCK_RAW, 0);
2331     if (sock < 0)
2332     {
2333         const int socket_errno = errno;
2334         LogMsg("getMACAddress: Can not open the socket - %s", strerror(socket_errno));
2335         return socket_errno;
2336     }
2337     
2338     rtm->rtm_addrs   |= RTA_DST | RTA_GATEWAY;
2339     rtm->rtm_type     = RTM_GET;
2340     rtm->rtm_flags    = 0;
2341     rtm->rtm_version  = RTM_VERSION;
2342     rtm->rtm_seq      = ++seq;
2343     
2344     sdl_m.sdl_len     = sizeof(sdl_m);
2345     sdl_m.sdl_family  = AF_LINK;
2346     if (family == AF_INET)
2347     {
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);
2353     }
2354     else if (family == AF_INET6)
2355     {
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);
2361     }
2362     NEXTADDR(RTA_GATEWAY, &sdl_m, sdl_m.sdl_len);
2363     rtm->rtm_msglen = rlen = cp - (char *)&m_rtmsg;
2364     
2365     if (write(sock, (char *)&m_rtmsg, rlen) < 0)
2366     {
2367         const int write_errno = errno;
2368         LogMsg("getMACAddress: writing to routing socket: %s", strerror(write_errno));
2369         close(sock);
2370         return write_errno;
2371     }
2372     
2373     do
2374     {
2375         rlen = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
2376     }
2377     while (rlen > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid()));
2378     
2379     if (rlen < 0)
2380         LogMsg("getMACAddress: Read from routing socket failed");
2381     
2382     if (family == AF_INET)
2383     {
2384         sin = (struct sockaddr_in *) (rtm + 1);
2385         sdl = (struct sockaddr_dl *) (sin->sin_len + (char *) sin);
2386     }
2387     else if (family == AF_INET6)
2388     {
2389         sin6 = (struct sockaddr_in6 *) (rtm +1);
2390         sdl  = (struct sockaddr_dl  *) (sin6->sin6_len + (char *) sin6);
2391     }
2392     
2393     if (!sdl)
2394     {
2395         LogMsg("getMACAddress: sdl is NULL for family %d", family);
2396         close(sock);
2397         return -1;
2398     }
2399     
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)
2404     {
2405         if (sin)
2406         {
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));
2409         }
2410         else
2411         {
2412             LogMsg("getMACAddress: sin is NULL");
2413         }
2414         close(sock);
2415         return -1;
2416     }
2417     else if (sdl->sdl_family == AF_INET6)
2418     {
2419         if (sin6)
2420         {
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));
2423         }
2424         else
2425         {
2426             LogMsg("getMACAddress: sin6 is NULL");
2427         }
2428         close(sock);
2429         return -1;
2430     }
2431     
2432     unsigned char *ptr = (unsigned char *)LLADDR(sdl);
2433     for (i = 0; i < ETHER_ADDR_LEN; i++)
2434         (eth)[i] = *(ptr +i);
2435     
2436     close(sock);
2437     
2438     return KERN_SUCCESS;
2439 }
2440
2441 mDNSlocal int GetRemoteMacinternal(int family, v6addr_t raddr, ethaddr_t eth)
2442 {
2443     int      ret = 0;
2444     v6addr_t gateway;
2445     int      gfamily = 0;
2446     int      count = 0;
2447
2448     do
2449     {
2450         ret = getMACAddress(family, raddr, gateway, &gfamily, eth);
2451         if (ret == -1)
2452         {
2453             memcpy(raddr, gateway, sizeof(family));
2454             family = gfamily;
2455             count++;
2456         }
2457     }
2458     while ((ret == -1) && (count < 5));
2459     return ret;
2460 }
2461
2462 mDNSlocal int StoreSPSMACAddressinternal(int family, v6addr_t spsaddr, const char *ifname)
2463 {
2464     ethaddr_t              eth;
2465     char                   spsip[INET6_ADDRSTRLEN];
2466     int                    ret        = 0;
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;
2474     
2475     if ((store == NULL) || (ipstore == NULL))
2476     {
2477         LogMsg("StoreSPSMACAddressinternal: Unable to accesss SC Dynamic Store");
2478         ret = -1;
2479         goto fin;
2480     }
2481     
2482     // Get the MAC address of the Sleep Proxy Server
2483     memset(eth, 0, sizeof(eth));
2484     ret = GetRemoteMacinternal(family, spsaddr, eth);
2485     if (ret !=  0)
2486     {
2487         LogMsg("StoreSPSMACAddressinternal: Failed to determine the MAC address");
2488         goto fin;
2489     }
2490     
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);
2494     if (!dict)
2495     {
2496         LogMsg("StoreSPSMACAddressinternal: SPSCreateDict() Could not create CFDictionary dict");
2497         ret = -1;
2498         goto fin;
2499     }
2500     
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)
2504         CFRelease(macaddr);
2505     
2506     if( NULL == inet_ntop(family, (void *)spsaddr, spsip, sizeof(spsip)))
2507     {
2508         LogMsg("StoreSPSMACAddressinternal: inet_ntop failed: %s", strerror(errno));
2509         ret = -1;
2510         goto fin;
2511     }
2512     
2513     CFStringRef ipaddr = CFStringCreateWithCString(NULL, spsip, kCFStringEncodingUTF8);
2514     CFDictionarySetValue(dict, CFSTR("IPAddress"), ipaddr);
2515     if (NULL != ipaddr)
2516         CFRelease(ipaddr);
2517     
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)
2520     {
2521         if ((ipdict = SCDynamicStoreCopyValue(ipstore, entityname)) != NULL)
2522         {
2523             if((addrs = CFDictionaryGetValue(ipdict, CFSTR("Addresses"))) != NULL)
2524             {
2525                 addrs = CFRetain(addrs);
2526                 CFDictionarySetValue(dict, CFSTR("RegisteredAddresses"), addrs);
2527             }
2528         }
2529     }
2530     SCDynamicStoreSetValue(store, sckey, dict);
2531     
2532 fin:
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);
2540     
2541     return ret;
2542 }
2543
2544 mDNSlocal void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname)
2545 {
2546     struct
2547     {
2548         v6addr_t saddr;
2549     } addr;
2550     int err = 0;
2551     
2552     mDNSPlatformMemCopy(addr.saddr, spsaddr, sizeof(v6addr_t));
2553     
2554     err = StoreSPSMACAddressinternal(family, (uint8_t *)addr.saddr, ifname);
2555     if (err != 0)
2556         LogMsg("mDNSStoreSPSMACAddress : failed");
2557 }
2558
2559 mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
2560 {
2561     int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2562     
2563     LogInfo("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname);
2564     mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname);
2565     
2566     return KERN_SUCCESS;
2567 }
2568
2569
2570 mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage* msg, int length)
2571 {
2572     int                    ret   = 0;
2573     CFStringRef            sckey = NULL;
2574     SCDynamicStoreRef      store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreOwnerOPTRecord"), NULL, NULL);
2575     CFMutableDictionaryRef dict  = NULL;
2576
2577     if (store == NULL)
2578     {
2579         LogMsg("mDNSPlatformStoreOwnerOptRecord: Unable to accesss SC Dynamic Store");
2580         ret = -1;
2581         goto fin;
2582     }
2583
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);
2587     if (!dict)
2588     {
2589         LogMsg("mDNSPlatformStoreOwnerOptRecord: Could not create CFDictionary dictionary to store OPT Record");       
2590         ret =-1;
2591         goto fin;
2592     }
2593
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);
2598
2599     SCDynamicStoreSetValue(store, sckey, dict);
2600
2601 fin:
2602     if (NULL != store)  CFRelease(store);
2603     if (NULL != sckey)  CFRelease(sckey);
2604     if (NULL != dict)   CFRelease(dict);
2605     return ret;
2606 }
2607
2608 mDNSlocal void mDNSGet_RemoteMAC(int family, v6addr_t raddr)
2609 {
2610     ethaddr_t            eth;
2611     IPAddressMACMapping *addrMapping;
2612     int kr = KERN_FAILURE;
2613     struct
2614     {
2615         v6addr_t addr;
2616     } dst;
2617
2618     bzero(eth, sizeof(ethaddr_t));
2619     mDNSPlatformMemCopy(dst.addr, raddr, sizeof(v6addr_t));
2620
2621     kr = GetRemoteMacinternal(family, (uint8_t *)dst.addr, eth);
2622
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.
2625     if (kr == 0)
2626     {
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)
2631         {
2632             addrMapping->ipaddr.type = mDNSAddrType_IPv4;
2633             mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, raddr, sizeof(v6addr_t));
2634         }
2635         else
2636         {
2637             addrMapping->ipaddr.type = mDNSAddrType_IPv6;
2638             mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v6.b, raddr, sizeof(v6addr_t));
2639         }
2640         UpdateRMAC(&mDNSStorage, addrMapping);
2641     }
2642 }
2643
2644 mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr)
2645 {
2646     int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2647     
2648     LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC");
2649     mDNSGet_RemoteMAC(family, raddr->ip.v6.b);
2650     
2651     return KERN_SUCCESS;
2652 }
2653
2654 mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
2655 {
2656     mDNSs32 intfid;
2657     mDNSs32 error  = 0;
2658     int     family = (laddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2659
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)
2662     {
2663         LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error);
2664         return error;
2665     }
2666     mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, intfid);
2667     return error;
2668 }
2669
2670 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2671
2672 mDNSlocal int CountProxyTargets(NetworkInterfaceInfoOSX *x, int *p4, int *p6)
2673 {
2674     int numv4 = 0, numv6 = 0;
2675     AuthRecord *rr;
2676
2677     for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
2678         if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2679         {
2680             if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
2681             numv4++;
2682         }
2683
2684     for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
2685         if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2686         {
2687             if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
2688             numv6++;
2689         }
2690
2691     if (p4) *p4 = numv4;
2692     if (p6) *p6 = numv6;
2693     return(numv4 + numv6);
2694 }
2695
2696 mDNSexport void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)
2697 {
2698     mDNS *const m = &mDNSStorage;
2699     NetworkInterfaceInfoOSX *x;
2700
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;
2703
2704     if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
2705
2706     #define MAX_BPF_ADDRS 250
2707     int numv4 = 0, numv6 = 0;
2708
2709     if (CountProxyTargets(x, &numv4, &numv6) > MAX_BPF_ADDRS)
2710     {
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;
2714     }
2715
2716     LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC  %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
2717
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] =
2721     {
2722         BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, 12),              // 0 Read Ethertype (bytes 12,13)
2723
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
2726
2727         BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0),      // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
2728
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
2733
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)
2736     };
2737
2738     // Special filter program to use when there are no address proxy records
2739     static struct bpf_insn nullfilter[] =
2740     {
2741         BPF_STMT(BPF_RET | BPF_K, 0)                            // 0 Match no packets and return size 0
2742     };
2743
2744     struct bpf_program prog;
2745     if (!numv4 && !numv6)
2746     {
2747         LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
2748         if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
2749
2750         // Cancel any previous ND group memberships we had
2751         if (x->BPF_mcfd >= 0)
2752         {
2753             close(x->BPF_mcfd);
2754             x->BPF_mcfd = -1;
2755         }
2756
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
2760         prog.bf_len   = 1;
2761         prog.bf_insns = nullfilter;
2762     }
2763     else
2764     {
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;
2770
2771         static const struct bpf_insn rf  = BPF_STMT(BPF_RET + BPF_K, 0);                // No match: Return nothing
2772
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)
2774
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)
2779
2780         static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94);               // Success: Return Eth + IPv6 + TCP + 20 bytes spare
2781
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
2784
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.
2796
2797         // IPSEC capture size notes:
2798         //  8 bytes UDP header
2799         //  4 bytes Non-ESP Marker
2800         // 28 bytes IKE Header
2801         // --
2802         // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
2803
2804         AuthRecord *rr;
2805         for (rr = m->ResourceRecords; rr; rr=rr->next)
2806             if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2807             {
2808                 mDNSv4Addr a = rr->AddressProxy.ip.v4;
2809                 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2810                 BPF_SetOffset(pc, jt, ret4);
2811                 pc->jf   = 0;
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];
2813                 pc++;
2814             }
2815         *pc++ = rf;
2816
2817         if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
2818         *pc++ = g6; // chk6 points here
2819
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);
2823
2824         for (rr = m->ResourceRecords; rr; rr=rr->next)
2825             if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2826             {
2827                 const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
2828                 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2829                 BPF_SetOffset(pc, jt, ret6);
2830                 pc->jf   = 0;
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];
2832                 pc++;
2833
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];
2840
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);
2845
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);
2849
2850                 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
2851             }
2852
2853         if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
2854         *pc++ = rf;     // fail points here
2855
2856         if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
2857         *pc++ = r4a;    // ret4 points here
2858         *pc++ = r4b;
2859         *pc++ = r4c;
2860         *pc++ = r4d;
2861
2862         if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
2863         *pc++ = r6a;    // ret6 points here
2864 #if 0
2865         // For debugging BPF filter program
2866         unsigned int q;
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);
2869 #endif
2870         prog.bf_len   = (u_int)(pc - filter);
2871         prog.bf_insns = filter;
2872     }
2873
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);
2876 }
2877
2878 mDNSexport void mDNSPlatformReceiveBPF_fd(int fd)
2879 {
2880     mDNS *const m = &mDNSStorage;
2881     mDNS_Lock(m);
2882
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); }
2886     else
2887     {
2888         LogSPS("%s using   BPF fd %d", i->ifinfo.ifname, fd);
2889
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);
2896
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));
2899
2900         if (i->BPF_len > sizeof(m->imsg))
2901         {
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));
2905             else
2906                 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd, i->ifinfo.ifname, i->BPF_len);
2907         }
2908
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));
2912
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));
2915
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));
2918
2919         /*  <rdar://problem/10287386>
2920          *  make socket non blocking see comments in bpf_callback_common for more info
2921          */
2922         if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
2923         {
2924             LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2925         }
2926
2927         struct ifreq ifr;
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; }
2932         else
2933         {
2934 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2935             i->BPF_fd  = fd;
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);
2941 #else
2942             CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
2943             i->BPF_fd  = fd;
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);
2947 #endif
2948             mDNSPlatformUpdateProxyList(i->ifinfo.InterfaceID);
2949         }
2950     }
2951
2952     mDNS_Unlock(m);
2953 }
2954
2955 #endif // APPLE_OSX_mDNSResponder
2956
2957 #if COMPILER_LIKES_PRAGMA_MARK
2958 #pragma mark -
2959 #pragma mark - Key Management
2960 #endif
2961
2962 #ifndef NO_SECURITYFRAMEWORK
2963 mDNSlocal CFArrayRef CopyCertChain(SecIdentityRef identity)
2964 {
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);
2970     else
2971     {
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);
2977         else
2978         {
2979             SecPolicyRef policy;
2980             err = SecPolicySearchCopyNext(searchRef, &policy);
2981             if (err || !policy) LogMsg("CopyCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
2982             else
2983             {
2984                 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
2985                 if (!wrappedCert) LogMsg("CopyCertChain: wrappedCert is NULL");
2986                 else
2987                 {
2988                     SecTrustRef trust;
2989                     err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
2990                     if (err || !trust) LogMsg("CopyCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
2991                     else
2992                     {
2993                         err = SecTrustEvaluate(trust, NULL);
2994                         if (err) LogMsg("CopyCertChain: SecTrustEvaluate() returned %d", (int) err);
2995                         else
2996                         {
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);
3001                             else
3002                             {
3003                                 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
3004                                 if (!certChain) LogMsg("CopyCertChain: certChain is NULL");
3005                                 else
3006                                 {
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);
3012                                 }
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...
3018                             }
3019                         }
3020                         CFRelease(trust);
3021                     }
3022                     CFRelease(wrappedCert);
3023                 }
3024                 CFRelease(policy);
3025             }
3026             CFRelease(searchRef);
3027         }
3028 #pragma clang diagnostic pop
3029         CFRelease(cert);
3030     }
3031     return certChain;
3032 }
3033 #endif /* NO_SECURITYFRAMEWORK */
3034
3035 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
3036 {
3037 #ifdef NO_SECURITYFRAMEWORK
3038     return mStatus_UnsupportedErr;
3039 #else
3040     SecIdentityRef identity = nil;
3041     SecIdentitySearchRef srchRef = nil;
3042     OSStatus err;
3043
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; }
3050
3051     err = SecIdentitySearchCopyNext(srchRef, &identity);
3052     if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
3053 #pragma clang diagnostic pop
3054
3055     if (CFGetTypeID(identity) != SecIdentityGetTypeID())
3056     { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
3057
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; }
3061
3062     return mStatus_NoError;
3063 #endif /* NO_SECURITYFRAMEWORK */
3064 }
3065
3066 mDNSexport void  mDNSPlatformTLSTearDownCerts(void)
3067 {
3068 #ifndef NO_SECURITYFRAMEWORK
3069     if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
3070 #endif /* NO_SECURITYFRAMEWORK */
3071 }
3072
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)
3075 {
3076     CFStringEncoding encoding = kCFStringEncodingUTF8;
3077     CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
3078     if (cfs)
3079     {
3080         CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3081         CFRelease(cfs);
3082     }
3083 }
3084
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)
3087 {
3088     CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
3089     if (cfs)
3090     {
3091         CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3092         CFRelease(cfs);
3093     }
3094 }
3095
3096 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
3097 {
3098     mDNSs32 val;
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;
3104 }
3105
3106 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
3107 {
3108     if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
3109
3110     if (sa->sa_family == AF_INET)
3111     {
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);
3116     }
3117
3118     if (sa->sa_family == AF_INET6)
3119     {
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);
3130     }
3131
3132     LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
3133     return(mStatus_Invalid);
3134 }
3135
3136 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
3137 {
3138     mDNSEthAddr eth = zeroEthAddr;
3139
3140     CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
3141     if (entityname)
3142     {
3143         CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, entityname);
3144         if (dict)
3145         {
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);
3150             CFRelease(dict);
3151         }
3152         CFRelease(entityname);
3153     }
3154
3155     return(eth);
3156 }
3157
3158 mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
3159 {
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)
3163         {
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; }
3167         }
3168     *eth = zeroEthAddr;
3169     return -1;
3170 }
3171
3172 #ifndef SIOCGIFWAKEFLAGS
3173 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
3174 #endif
3175
3176 #ifndef IF_WAKE_ON_MAGIC_PACKET
3177 #define IF_WAKE_ON_MAGIC_PACKET 0x01
3178 #endif
3179
3180 #ifndef ifr_wake_flags
3181 #define ifr_wake_flags ifr_ifru.ifru_intval
3182 #endif
3183
3184 mDNSlocal mDNSBool  CheckInterfaceSupport(NetworkInterfaceInfo *const intf, const char *key)
3185 {
3186     io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
3187     if (!service)
3188     {
3189         LogSPS("CheckInterfaceSupport: No service for interface %s", intf->ifname);
3190         return mDNSfalse;
3191     }
3192
3193     io_name_t n1, n2;
3194     IOObjectGetClass(service, n1);
3195     io_object_t parent = IO_OBJECT_NULL;
3196     mDNSBool    ret    = mDNSfalse;
3197
3198     kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
3199     if (kr == KERN_SUCCESS)
3200     {
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;
3205
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.
3208         if (IsAppleTV())
3209             ref = IORegistryEntrySearchCFProperty(parent, kIOServicePlane, keystr, kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively);
3210         else
3211             ref = IORegistryEntryCreateCFProperty(parent, keystr, kCFAllocatorDefault, mDNSNULL);
3212
3213         if (!ref)
3214         {
3215             LogSPS("CheckInterfaceSupport: No %s for interface %s/%s/%s", key, intf->ifname, n1, n2);
3216             ret = mDNSfalse;
3217         }
3218         else
3219         {
3220             ret = mDNStrue;
3221             CFRelease(ref);
3222         }
3223         IOObjectRelease(parent);
3224         CFRelease(keystr);
3225     }
3226     else
3227     {
3228         LogSPS("CheckInterfaceSupport: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
3229         ret = mDNSfalse;
3230     }
3231
3232     IOObjectRelease(service);
3233     return ret;
3234 }
3235
3236
3237 mDNSlocal  mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
3238 {
3239     return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
3240 }
3241
3242 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
3243 {
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)
3246     {
3247         LogSPS("NetWakeInterface: returning false for %s", i->ifinfo.ifname);
3248         return(mDNSfalse);
3249     }
3250
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))
3255     {
3256         LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i->ifinfo.ifname);
3257         return mDNStrue;
3258     }
3259
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); }
3262
3263     struct ifreq ifr;
3264     strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3265     if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
3266     {
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;
3277     }
3278
3279     close(s);
3280
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
3282
3283     LogSPS("NetWakeInterface: %-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
3284
3285     return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
3286 }
3287
3288 mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
3289 {
3290     int sockFD;
3291     struct ifreq ifr;
3292
3293     sockFD = socket(AF_INET, SOCK_DGRAM, 0);
3294     if (sockFD < 0)
3295     {
3296         LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno, strerror(errno));
3297         return 0;
3298     }
3299
3300     ifr.ifr_addr.sa_family = AF_INET;
3301     strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
3302
3303     if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
3304     {
3305         LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno));
3306         ifr.ifr_eflags = 0;
3307     }
3308
3309     close(sockFD);
3310     return ifr.ifr_eflags;
3311 }
3312
3313 #if TARGET_OS_IPHONE
3314
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;
3320
3321 mDNSlocal mDNSBool MobileWiFiLibLoad(void)
3322 {
3323     static mDNSBool isInitialized = mDNSfalse;
3324     static void *MobileWiFiLib_p = mDNSNULL;
3325     static const char path[] = "/System/Library/PrivateFrameworks/MobileWiFi.framework/MobileWiFi";
3326
3327     if (!isInitialized)
3328     {
3329         if (!MobileWiFiLib_p)
3330         {
3331             MobileWiFiLib_p = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
3332             if (!MobileWiFiLib_p)
3333             {
3334                 LogInfo("MobileWiFiLibLoad: dlopen() failed.");
3335                 goto exit;
3336             }
3337         }
3338
3339         if (!WiFiManagerClientCreate_p)
3340         {
3341             WiFiManagerClientCreate_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCreate");
3342             if (!WiFiManagerClientCreate_p)
3343             {
3344                 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCreate symbol failed.");
3345                 goto exit;
3346             }
3347         }
3348
3349         if (!WiFiManagerClientCopyDevices_p)
3350         {
3351             WiFiManagerClientCopyDevices_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCopyDevices");
3352             if (!WiFiManagerClientCopyDevices_p)
3353             {
3354                 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCopyDevices symbol failed.");
3355                 goto exit;
3356             }
3357         }
3358
3359         if (!WiFiDeviceClientCopyCurrentNetwork_p)
3360         {
3361             WiFiDeviceClientCopyCurrentNetwork_p = dlsym(MobileWiFiLib_p, "WiFiDeviceClientCopyCurrentNetwork");
3362             if (!WiFiDeviceClientCopyCurrentNetwork_p)
3363             {
3364                 LogInfo("MobileWiFiLibLoad: load of WiFiDeviceClientCopyCurrentNetwork symbol failed.");
3365                 goto exit;
3366             }
3367         }
3368
3369         if (!WiFiNetworkIsCarPlay_p)
3370         {
3371             WiFiNetworkIsCarPlay_p = dlsym(MobileWiFiLib_p, "WiFiNetworkIsCarPlay");
3372             if (!WiFiNetworkIsCarPlay_p)
3373             {
3374                 LogInfo("MobileWiFiLibLoad: load of WiFiNetworkIsCarPlay symbol failed.");
3375                 goto exit;
3376             }
3377         }
3378
3379         isInitialized = mDNStrue;
3380     }
3381
3382 exit:
3383     return isInitialized;
3384 }
3385
3386 #define CARPLAY_DEBUG 0
3387
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)
3392 {
3393     static WiFiManagerClientRef manager = NULL;
3394     CFArrayRef              devices;
3395     WiFiDeviceClientRef     device;
3396     WiFiNetworkRef          network;
3397     mDNSBool                rvalue = mDNSfalse;
3398
3399     if (!MobileWiFiLibLoad())
3400     {
3401         LogInfo("IsCarPlaySSID: MobileWiFiLibLoad() failed!");
3402         return mDNSfalse;
3403     }
3404
3405     // Cache the WiFiManagerClientRef.
3406     if (manager == NULL)
3407         manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
3408
3409     if (manager == NULL)
3410     {
3411         LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3412         return mDNSfalse;
3413     }
3414
3415     devices = WiFiManagerClientCopyDevices_p(manager);
3416
3417     // If the first call fails, update the cached WiFiManagerClientRef pointer and try again.
3418     if (devices == NULL)
3419     {
3420         LogInfo("IsCarPlaySSID: First call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
3421
3422         // Release the previously cached WiFiManagerClientRef which is apparently now stale.
3423         CFRelease(manager);
3424         manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
3425         if (manager == NULL)
3426         {
3427             LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3428             return mDNSfalse;
3429         }
3430         devices = WiFiManagerClientCopyDevices_p(manager);
3431         if (devices == NULL)
3432         {
3433             LogInfo("IsCarPlaySSID: Second call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
3434             return mDNSfalse;
3435         }
3436     }
3437
3438     device = (WiFiDeviceClientRef)CFArrayGetValueAtIndex(devices, 0);
3439     network = WiFiDeviceClientCopyCurrentNetwork_p(device);
3440     if (network != NULL)
3441     {
3442         if (WiFiNetworkIsCarPlay_p(network))
3443         {
3444             LogInfo("IsCarPlaySSID: %s is CarPlay hosted", ifa_name);
3445             rvalue = mDNStrue;
3446         }
3447 #if CARPLAY_DEBUG
3448         else
3449             LogInfo("IsCarPlaySSID: %s is NOT CarPlay hosted", ifa_name);
3450 #endif // CARPLAY_DEBUG
3451
3452         CFRelease(network);
3453     }
3454     else
3455         LogInfo("IsCarPlaySSID: WiFiDeviceClientCopyCurrentNetwork() returned NULL for %s", ifa_name);
3456
3457     CFRelease(devices);
3458
3459     return rvalue;
3460 }
3461
3462 #else   // TARGET_OS_IPHONE
3463
3464 mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
3465 {
3466     (void)ifa_name;  // unused
3467
3468     // OSX WifiManager currently does not implement WiFiNetworkIsCarPlay()
3469     return mDNSfalse;;
3470 }
3471
3472 #endif  // TARGET_OS_IPHONE
3473
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)
3479 {
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);
3484
3485     mDNSAddr ip, mask;
3486     if (SetupAddr(&ip,   ifa->ifa_addr   ) != mStatus_NoError) return(NULL);
3487     if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
3488
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))
3494         {
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;
3505
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)
3510             {
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)
3517                 {
3518                     mDNS_Lock(m);
3519                     if (NetWake) mDNS_ActivateNetWake_internal  (m, &(*p)->ifinfo);
3520                     else         mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
3521                     mDNS_Unlock(m);
3522                 }
3523             }
3524             // Reset the flag if it has changed this time.
3525             (*p)->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
3526
3527             return(*p);
3528         }
3529
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;
3535     i->ifinfo.ip          = ip;
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;
3545
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;
3552     else
3553         i->ifinfo.DirectLink  = IsCarPlaySSID(ifa->ifa_name);
3554
3555     if (i->ifinfo.DirectLink)
3556         LogInfo("AddInterfaceToList: DirectLink set for %s", ifa->ifa_name);
3557
3558     i->next            = mDNSNULL;
3559     i->m               = m;
3560     i->Exists          = mDNStrue;
3561     i->Flashing        = mDNSfalse;
3562     i->Occulting       = mDNSfalse;
3563
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);
3567
3568     i->isExpensive     = (eflags & IFEF_EXPENSIVE) ? mDNStrue: mDNSfalse;
3569     if (eflags & IFEF_AWDL)
3570     {
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);
3577     }
3578     else
3579     {
3580         i->ifinfo.SupportsUnicastMDNSResponse = mDNStrue;
3581     }
3582     i->AppearanceTime  = utc;       // Brand new interface; AppearanceTime is now
3583     i->LastSeen        = utc;
3584     i->ifa_flags       = ifa->ifa_flags;
3585     i->scope_id        = scope_id;
3586     i->BSSID           = bssid;
3587     i->sa_family       = ifa->ifa_addr->sa_family;
3588     i->BPF_fd          = -1;
3589     i->BPF_mcfd        = -1;
3590     i->BPF_len         = 0;
3591     i->Registered      = mDNSNULL;
3592
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);
3598
3599     *p = i;
3600     return(i);
3601 }
3602
3603 #if APPLE_OSX_mDNSResponder
3604
3605 #if COMPILER_LIKES_PRAGMA_MARK
3606 #pragma mark -
3607 #pragma mark - AutoTunnel
3608 #endif
3609
3610 #define kRacoonPort 4500
3611
3612 static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
3613
3614 #ifndef NO_SECURITYFRAMEWORK
3615
3616 static CFMutableDictionaryRef domainStatusDict = NULL;
3617
3618 mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
3619 {
3620     if (q->LongLived)
3621     {
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;
3628     }
3629
3630     return mStatus_NoError;
3631 }
3632
3633 mDNSlocal mStatus UpdateLLQStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
3634 {
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)
3639         {
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; }
3644         }
3645
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);
3650     return status;
3651 }
3652
3653 mDNSlocal mStatus UpdateRRStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
3654 {
3655     AuthRecord *r;
3656
3657     if (info->deltime) return mStatus_NoError;
3658     for (r = mDNSStorage.ResourceRecords; r; r = r->next)
3659     {
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;
3665         while (n->c[0])
3666         {
3667             DomainAuthInfo *ptr;
3668             for (ptr = mDNSStorage.AuthInfoList; ptr; ptr = ptr->next)
3669                 if (SameDomainName(&ptr->domain, n))
3670                 {
3671                     if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime))
3672                     {
3673                         mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
3674                         return r->updateError;
3675                     }
3676                 }
3677             n = (const domainname *)(n->c + 1 + n->c[0]);
3678         }
3679     }
3680     return mStatus_NoError;
3681 }
3682
3683 #endif // ndef NO_SECURITYFRAMEWORK
3684
3685 // MUST be called with lock held
3686 mDNSlocal void UpdateAutoTunnelDomainStatus(const DomainAuthInfo *const info)
3687 {
3688 #ifdef NO_SECURITYFRAMEWORK
3689     (void)info;
3690 #else
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;
3696     char buffer[1024];
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];
3704
3705     mDNS_CheckLock(m);
3706
3707     if (!domainStatusDict)
3708     {
3709         domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3710         if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
3711     }
3712
3713     if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
3714
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; }
3718
3719     if (info->deltime)
3720     {
3721         if (CFDictionaryContainsKey(domainStatusDict, domain))
3722         {
3723             CFDictionaryRemoveValue(domainStatusDict, domain);
3724             if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3725         }
3726         CFRelease(domain);
3727         CFRelease(dict);
3728
3729         return;
3730     }
3731
3732     mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
3733     tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3734     if (!tmp)
3735         LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
3736     else
3737     {
3738         CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
3739         CFRelease(tmp);
3740     }
3741
3742     if (llq)
3743     {
3744         mDNSu32 port = mDNSVal16(llq->ExternalPort);
3745
3746         num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3747         if (!num)
3748             LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
3749         else
3750         {
3751             CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
3752             CFRelease(num);
3753         }
3754
3755         if (llq->Result)
3756         {
3757             num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
3758             if (!num)
3759                 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
3760             else
3761             {
3762                 CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
3763                 CFRelease(num);
3764             }
3765         }
3766     }
3767
3768     if (tun)
3769     {
3770         mDNSu32 port = mDNSVal16(tun->ExternalPort);
3771
3772         num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3773         if (!num)
3774             LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
3775         else
3776         {
3777             CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
3778             CFRelease(num);
3779         }
3780
3781         mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress);
3782         tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3783         if (!tmp)
3784             LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
3785         else
3786         {
3787             CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
3788             CFRelease(tmp);
3789         }
3790
3791         if (tun->Result)
3792         {
3793             num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
3794             if (!num)
3795                 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
3796             else
3797             {
3798                 CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
3799                 CFRelease(num);
3800             }
3801         }
3802     }
3803     if (tun || llq)
3804     {
3805         mDNSu32 code = m->LastNATMapResultCode;
3806
3807         num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
3808         if (!num)
3809             LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
3810         else
3811         {
3812             CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
3813             CFRelease(num);
3814         }
3815     }
3816
3817     mDNS_snprintf(buffer, sizeof(buffer), "Success");
3818     llqStatus = UpdateLLQStatus(llqBuffer, sizeof(llqBuffer), info);
3819     status = UpdateRRStatus(buffer, sizeof(buffer), info);
3820
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)
3824     {
3825         LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer);
3826     }
3827     else if (m->Router.type == mDNSAddrType_None)
3828     {
3829         status = mStatus_NoRouter;
3830         mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
3831     }
3832     else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
3833     {
3834         status = mStatus_NoRouter;
3835         mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
3836     }
3837     else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress))
3838     {
3839         status = mStatus_ServiceNotRunning;
3840         mDNS_snprintf(buffer, sizeof(buffer), "No inner address");
3841     }
3842     else if (!llq && !tun)
3843     {
3844         status = mStatus_NotInitializedErr;
3845         mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
3846     }
3847     else if (llqStatus == mStatus_NoSuchRecord)
3848     {
3849         status = llqStatus;
3850         mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
3851     }
3852     else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
3853     {
3854         status = mStatus_DoubleNAT;
3855         mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address");
3856     }
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)))))
3860     {
3861         status = mStatus_NATPortMappingDisabled;
3862         mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router");
3863     }
3864     else if ((llq && llq->Result) || (tun && tun->Result))
3865     {
3866         status = mStatus_NATTraversal;
3867         mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
3868     }
3869     else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
3870     {
3871         status = mStatus_NATTraversal;
3872         mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
3873     }
3874     else
3875     {
3876         status = llqStatus;
3877         mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
3878         LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer);
3879     }
3880
3881     num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
3882     if (!num)
3883         LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
3884     else
3885     {
3886         CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
3887         CFRelease(num);
3888     }
3889
3890     tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3891     if (!tmp)
3892         LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
3893     else
3894     {
3895         CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
3896         CFRelease(tmp);
3897     }
3898
3899     if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
3900         !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
3901     {
3902         CFDictionarySetValue(domainStatusDict, domain, dict);
3903         if (!m->ShutdownTime)
3904         {
3905             LogInfo("UpdateAutoTunnelDomainStatus: %s status %d", status ? "failure" : "success", status);
3906             mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3907         }
3908     }
3909
3910     CFRelease(domain);
3911     CFRelease(dict);
3912
3913     debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
3914 #endif // def NO_SECURITYFRAMEWORK
3915 }
3916
3917 // MUST be called with lock held
3918 mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
3919 {
3920 #ifdef NO_SECURITYFRAMEWORK
3921         (void) m;
3922 #else
3923     mDNS_CheckLock(m);
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
3929 }
3930
3931 mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m)     // Determine whether we need racoon to accept incoming connections
3932 {
3933     DomainAuthInfo *info;
3934
3935     for (info = m->AuthInfoList; info; info = info->next)
3936         if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
3937             break;
3938
3939     if (info != AnonymousRacoonConfig)
3940     {
3941         AnonymousRacoonConfig = info;
3942         LogInfo("UpdateAnonymousRacoonConfig need not be done in mDNSResponder");
3943     }
3944 }
3945
3946 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
3947
3948 // Caller must hold the lock
3949 mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record)
3950 {
3951     mDNS_CheckLock(m);
3952
3953     LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c);
3954
3955     if (record->resrec.RecordType > kDNSRecordTypeDeregistering)
3956     {
3957         mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal);
3958         if (err)
3959         {
3960             record->resrec.RecordType = kDNSRecordTypeUnregistered;
3961             LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c);
3962             return mDNSfalse;
3963         }
3964         else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
3965     }
3966     else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType);
3967
3968     return mDNStrue;
3969 }
3970
3971 // Caller must hold the lock
3972 mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
3973 {
3974     if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord))
3975     {
3976         info->AutoTunnelHostRecord.namestorage.c[0] = 0;
3977         m->NextSRVUpdate = NonZeroTime(m->timenow);
3978     }
3979 }
3980
3981 // Caller must hold the lock
3982 mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
3983 {
3984     mStatus err;
3985     mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result;
3986
3987     mDNS_CheckLock(m);
3988
3989     if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem))
3990     {
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);
3994     }
3995     else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
3996     {
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;
4004
4005         err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
4006         if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c);
4007         else
4008         {
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);
4012         }
4013     }
4014     else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType);
4015 }
4016
4017 // Caller must hold the lock
4018 mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4019 {
4020     LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
4021
4022     DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget);
4023     DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService);
4024     UpdateAutoTunnelHostRecord(m, info);
4025 }
4026
4027 // Caller must hold the lock
4028 mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4029 {
4030     mDNS_CheckLock(m);
4031
4032     if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)
4033     {
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);
4036     }
4037     else
4038     {
4039         if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
4040         {
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;
4050
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);
4054         }
4055         else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType);
4056
4057         if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
4058         {
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;
4070
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);
4074         }
4075         else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType);
4076
4077         UpdateAutoTunnelHostRecord(m, info);
4078
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);
4082
4083     }
4084 }
4085
4086 // Caller must hold the lock
4087 mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4088 {
4089     DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo);
4090 }
4091
4092 // Caller must hold the lock
4093 mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4094 {
4095     mDNS_CheckLock(m);
4096
4097     if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime)
4098         DeregisterAutoTunnelDeviceInfoRecord(m, info);
4099     else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
4100     {
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);
4103
4104         info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data);
4105         info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
4106
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);
4110     }
4111     else
4112         LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType);
4113 }
4114
4115 // Caller must hold the lock
4116 mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4117 {
4118     LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
4119
4120     DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
4121     UpdateAutoTunnelHostRecord(m, info);
4122     UpdateAutoTunnelDomainStatus(info);
4123 }
4124
4125 // Caller must hold the lock
4126 mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4127 {
4128     mDNS_CheckLock(m);
4129
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)
4133     {
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;
4141
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);
4145
4146         UpdateAutoTunnelHostRecord(m, info);
4147
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);
4151
4152     }
4153     else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType);
4154 }
4155
4156 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
4157 {
4158     DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
4159     if (result == mStatus_MemFree)
4160     {
4161         LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
4162         
4163         mDNS_Lock(m);
4164         
4165         // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
4166         if (rr == &info->AutoTunnelHostRecord)
4167         {
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);
4171         }
4172         if (m->ShutdownTime)
4173         {
4174             LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
4175             mDNS_Unlock(m);        
4176             return;
4177         }
4178         if (rr == &info->AutoTunnelHostRecord)
4179         {
4180             LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
4181             UpdateAutoTunnelHostRecord(m,info);
4182         }
4183         else if (rr == &info->AutoTunnelDeviceInfo)
4184         {
4185             LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
4186             UpdateAutoTunnelDeviceInfoRecord(m,info);
4187         }
4188         else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
4189         {
4190             LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
4191             UpdateAutoTunnelServiceRecords(m,info);
4192         }
4193         else if (rr == &info->AutoTunnel6Record)
4194         {
4195             LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
4196             UpdateAutoTunnel6Record(m,info);
4197         }
4198
4199         mDNS_Unlock(m);        
4200     }
4201 }
4202
4203 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
4204 {
4205     DomainAuthInfo *info;
4206
4207     LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
4208             n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort));
4209
4210     mDNS_Lock(m);
4211     
4212     m->NextSRVUpdate = NonZeroTime(m->timenow);
4213     LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4214
4215     for (info = m->AuthInfoList; info; info = info->next)
4216         if (info->AutoTunnel)
4217             UpdateAutoTunnelServiceRecords(m, info);
4218
4219     UpdateAnonymousRacoonConfig(m);     // Determine whether we need racoon to accept incoming connections
4220
4221     UpdateAutoTunnelDomainStatuses(m);
4222
4223     mDNS_Unlock(m);
4224 }
4225
4226 mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
4227 {
4228     LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
4229
4230     mDNS_Lock(m);
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);
4239     mDNS_Unlock(m);
4240 }
4241
4242 // Must be called with the lock held
4243 mDNSexport void StartServerTunnel(DomainAuthInfo *const info)
4244 {
4245     mDNS *const m = &mDNSStorage;
4246     if (info->deltime) return;
4247     
4248     if (info->AutoTunnelServiceStarted)
4249     {
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);
4253         return;
4254     }
4255     
4256     info->AutoTunnelServiceStarted = mDNStrue;
4257
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);
4268
4269     // If the global AutoTunnel NAT-T is not yet started, start it.
4270     if (!m->AutoTunnelNAT.clientContext)
4271     {
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);
4280     }
4281 }
4282
4283 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
4284 {
4285     mDNSv6Addr loc_outer6;
4286     mDNSv6Addr rmt_outer6;
4287
4288     // When we are tunneling over IPv6 Relay address, the port number is zero
4289     if (mDNSIPPortIsZero(tun->rmt_outer_port))
4290     {
4291         loc_outer6 = tun->loc_outer6;
4292         rmt_outer6 = tun->rmt_outer6;
4293     }
4294     else
4295     {
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];
4301
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];
4307     }
4308
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)));
4310 }
4311
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])
4314
4315 mDNSlocal void ReissueBlockedQuestionWithType(domainname *d, mDNSBool success, mDNSu16 qtype)
4316 {
4317     mDNS *const m = &mDNSStorage;
4318     DNSQuestion *q = m->Questions;
4319     while (q)
4320     {
4321         if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
4322         {
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.
4336             q = m->Questions;
4337         }
4338         else
4339             q = q->next;
4340     }
4341 }
4342
4343 mDNSlocal void ReissueBlockedQuestions(domainname *d, mDNSBool success)
4344 {
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);
4352 }
4353
4354 mDNSlocal void UnlinkAndReissueBlockedQuestions(ClientTunnel *tun, mDNSBool success)
4355 {
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);
4363 }
4364
4365 mDNSlocal mDNSBool TunnelClientDeleteMatching(ClientTunnel *tun, mDNSBool v6Tunnel)
4366 {
4367     mDNS *const m = &mDNSStorage;
4368     ClientTunnel **p;
4369     mDNSBool needSetKeys = mDNStrue;
4370
4371     p = &tun->next;
4372     while (*p)
4373     {
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;
4376         else
4377         {
4378             ClientTunnel *old = *p;
4379             if (v6Tunnel)
4380             {
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)
4384                 {
4385                     LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4386                     mDNS_StopQuery(m, &old->q);
4387                 }
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))
4392                 {
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);
4397                 }
4398                 else
4399                 {
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,
4403                             &old->rmt_inner);
4404                     needSetKeys = mDNSfalse;
4405                 }
4406             }
4407             else
4408             {
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)
4412                 {
4413                     LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4414                     mDNS_StopQuery(m, &old->q);
4415                 }
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))
4421                 {
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);
4426                 }
4427                 else
4428                 {
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,
4432                             &old->rmt_inner);
4433                     needSetKeys = mDNSfalse;
4434                 }
4435             }
4436
4437             *p = old->next;
4438             LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
4439             freeL("ClientTunnel", old);
4440         }
4441     }
4442     return needSetKeys;
4443 }
4444
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)
4448 {
4449     ClientTunnel **p;
4450
4451     p = &tun->next;
4452     while (*p)
4453     {
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;
4457         else
4458         {
4459             ClientTunnel *old = *p;
4460             if (v6Tunnel)
4461             {
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);
4464             }
4465             else
4466             {
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);
4469             }
4470             if (old->q.ThisQInterval >= 0)
4471             {
4472                 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4473                 mDNS_StopQuery(&mDNSStorage, &old->q);
4474             }
4475             else
4476             {
4477                 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4478                 AutoTunnelSetKeys(old, mDNSfalse);
4479             }
4480             *p = old->next;
4481             LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
4482             freeL("ClientTunnel", old);
4483         }
4484     }
4485 }
4486
4487 mDNSlocal void TunnelClientFinish(DNSQuestion *question, const ResourceRecord *const answer)
4488 {
4489     mDNS *const m = &mDNSStorage;
4490     mDNSBool needSetKeys = mDNStrue;
4491     ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4492     mDNSBool v6Tunnel = mDNSfalse;
4493     DomainAuthInfo *info;
4494
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;
4498
4499     if (v6Tunnel)
4500     {
4501         LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
4502         tun->rmt_outer6 = answer->rdata->u.ipv6;
4503         tun->loc_outer6 = m->AutoTunnelRelayAddr;
4504     }
4505     else
4506     {
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;
4515     }
4516
4517     question->ThisQInterval = -1;       // So we know this tunnel setup has completed
4518
4519     info = GetAuthInfoForName(m, &tun->dstname);
4520     if (!info)
4521     {
4522         LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
4523         ReissueBlockedQuestions(&tun->dstname, mDNSfalse);
4524         return;
4525     }
4526     
4527     tun->loc_inner = info->AutoTunnelInnerAddress;
4528
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);
4535
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);
4538
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);
4543 }
4544
4545 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
4546 {
4547     ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4548     DomainAuthInfo *info;
4549
4550     LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
4551
4552     if (!AddRecord) return;
4553     mDNS_StopQuery(m, question);
4554
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)
4558     {
4559         LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
4560         UnlinkAndReissueBlockedQuestions(tun, mDNSfalse);
4561         return;
4562     }
4563
4564     switch (tun->tc_state)
4565     {
4566     case TC_STATE_AAAA_PEER:
4567         if (question->qtype != kDNSType_AAAA)
4568         {
4569             LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
4570         }
4571         info = GetAuthInfoForName(m, &tun->dstname);
4572         if (!info)
4573         {
4574             LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
4575             UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4576             return;
4577         }
4578         if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
4579         {
4580             LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
4581             UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4582             return;
4583         }
4584         if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
4585         {
4586             LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6);
4587             UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4588             return;
4589         }
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))
4593         {
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");
4598         }
4599         else
4600         {
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");
4605         }
4606         AppendDomainName(&question->qname, &tun->dstname);
4607         mDNS_StartQuery(m, &tun->q);
4608         return;
4609     case TC_STATE_AAAA_PEER_RELAY:
4610         if (question->qtype != kDNSType_AAAA)
4611         {
4612             LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
4613         }
4614         // If it failed, look for the SRV record.
4615         if (!answer->rdlength)
4616         {
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);
4623             return;
4624         }
4625         TunnelClientFinish(question, answer);
4626         return;
4627     case TC_STATE_SRV_PEER:
4628         if (question->qtype != kDNSType_SRV)
4629         {
4630             LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
4631         }
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);
4638         return;
4639     case TC_STATE_ADDR_PEER:
4640         if (question->qtype != kDNSType_A)
4641         {
4642             LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
4643         }
4644         TunnelClientFinish(question, answer);
4645         return;
4646     default:
4647         LogMsg("AutoTunnelCallback: Unknown question %p", question);
4648     }
4649 }
4650
4651 // Must be called with the lock held
4652 mDNSexport void AddNewClientTunnel(DNSQuestion *const q)
4653 {
4654     mDNS *const m = &mDNSStorage;
4655     ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
4656     if (!p) return;
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
4669
4670     p->q.InterfaceID      = mDNSInterface_Any;
4671     p->q.flags            = 0;
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();
4693     p->q.euid             = 0;
4694     p->q.QuestionCallback = AutoTunnelCallback;
4695     p->q.QuestionContext  = p;
4696
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);
4699 }
4700
4701 #endif // APPLE_OSX_mDNSResponder
4702
4703 #if COMPILER_LIKES_PRAGMA_MARK
4704 #pragma mark -
4705 #pragma mark - Power State & Configuration Change Management
4706 #endif
4707
4708 mDNSlocal mStatus ReorderInterfaceList()
4709 {
4710     // Disable Reorder lists till <rdar://problem/30071012> is fixed to prevent spurious name conflicts
4711     return (mStatus_NoError);
4712
4713     mDNS *const m = &mDNSStorage;
4714     nwi_state_t state = nwi_state_copy();
4715
4716     if (state == mDNSNULL)
4717     {
4718         LogMsg("NWI State is NULL!");
4719         return (mStatus_Invalid);
4720     }
4721
4722     // Get the count of interfaces
4723     mDNSu32 count =  nwi_state_get_interface_names(state, mDNSNULL, 0);
4724     if (count == 0)
4725     {
4726         LogMsg("Unable to get the ordered list of interface names");
4727         nwi_state_release(state);
4728         return (mStatus_Invalid);
4729     }
4730
4731     // Get the ordered interface list
4732     int i;
4733     const char *names[count];
4734     count = nwi_state_get_interface_names(state, names, count);
4735
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 )
4741         {
4742             if (strcmp((*ptr)->ifname, names[i]) == 0)
4743             {
4744                 NetworkInterfaceInfo *node = *ptr;
4745                 *ptr = (*ptr)->next;
4746                 node->next = newList;
4747                 newList = node;
4748             }
4749             else
4750                 ptr = &((*ptr)->next);
4751         }
4752     }
4753
4754     // Get to the end of the list
4755     NetworkInterfaceInfo *newListEnd = newList;
4756     while (newListEnd != mDNSNULL && newListEnd->next != mDNSNULL)
4757         newListEnd = newListEnd->next;
4758
4759     // Add any remaing interfaces to the end of the sorted list
4760     if (newListEnd != mDNSNULL)
4761         newListEnd->next  = m->HostInterfaces;
4762
4763     // If we have a valid new list, point to that now
4764     if (newList != mDNSNULL)
4765         m->HostInterfaces = newList;
4766
4767     nwi_state_release(state);
4768     return (mStatus_NoError);
4769 }
4770
4771 mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
4772 {
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));
4783
4784     if (m->SleepState == SleepState_Sleeping) ifa = NULL;
4785
4786     while (ifa)
4787     {
4788 #if LIST_ALL_INTERFACES
4789         if (ifa->ifa_addr)
4790         {
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);
4800         }
4801         else
4802             LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X ifa_addr is NOT set",
4803                    ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags);
4804         
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);
4821 #endif
4822
4823         if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
4824         {
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);
4828         }
4829
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)
4832             {
4833                 if (!ifa->ifa_netmask)
4834                 {
4835                     mDNSAddr ip;
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);
4839                 }
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)
4843                 {
4844                     mDNSAddr ip;
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);
4848                 }
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)
4851                 {
4852                     LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
4853                 }
4854                 else
4855                 {
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;
4860
4861                     struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
4862                     if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
4863                     {
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);
4871                     }
4872
4873                     if (!(ifru_flags6 & (IN6_IFF_TENTATIVE | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
4874                     {
4875                         if (ifa->ifa_flags & IFF_LOOPBACK)
4876                         {
4877                             if (ifa->ifa_addr->sa_family == AF_INET) 
4878                                 v4Loopback = ifa;
4879                             else if (sin6->sin6_addr.s6_addr[0] != 0xFD) 
4880                                 v6Loopback = ifa;
4881                         }
4882                         else
4883                         {
4884                             NetworkInterfaceInfoOSX *i = AddInterfaceToList(ifa, utc);
4885                             if (i && MulticastInterface(i) && i->ifinfo.Advertise)
4886                             {
4887                                 if (ifa->ifa_addr->sa_family == AF_INET) 
4888                                     foundav4 = mDNStrue;
4889                                 else 
4890                                     foundav6 = mDNStrue;
4891                             }
4892                         }
4893                     }
4894                 }
4895             }
4896         ifa = ifa->ifa_next;
4897     }
4898
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);
4902
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)
4906         if (i->Exists)
4907         {
4908             mDNSBool txrx = MulticastInterface(i);
4909             if (i->ifinfo.McastTxRx != txrx)
4910             {
4911                 i->ifinfo.McastTxRx = txrx;
4912                 i->Exists = MulticastStateChanged; // State change; need to deregister and reregister this interface
4913             }
4914         }
4915
4916     if (InfoSocket >= 0) 
4917         close(InfoSocket);
4918
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]);
4921
4922     // Set up the nice label
4923     domainlabel nicelabel;
4924     nicelabel.c[0] = 0;
4925     GetUserSpecifiedFriendlyComputerName(&nicelabel);
4926     if (nicelabel.c[0] == 0)
4927     {
4928         debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
4929         MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
4930     }
4931
4932     // Set up the RFC 1034-compliant label
4933     domainlabel hostlabel;
4934     hostlabel.c[0] = 0;
4935     GetUserSpecifiedLocalHostName(&hostlabel);
4936     if (hostlabel.c[0] == 0)
4937     {
4938         debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
4939         MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
4940     }
4941
4942     mDNSBool namechange = mDNSfalse;
4943
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);
4948     else
4949     {
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;
4954     }
4955
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);
4958     else
4959     {
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;
4963         mDNS_SetFQDN(m);
4964         namechange = mDNStrue;
4965     }
4966
4967     if (namechange)     // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
4968     {
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
4974     }
4975
4976     return(mStatus_NoError);
4977 }
4978
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)
4982 {
4983     int i = 0, bits = 0;
4984     int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
4985     while (i < bytes)
4986     {
4987         mDNSu8 b = mask->ip.v6.b[i++];
4988         while (b & 0x80) { bits++; b <<= 1; }
4989         if (b) return(-1);
4990     }
4991     while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
4992     return(bits);
4993 }
4994
4995 // Returns count of non-link local V4 addresses registered (why? -- SC)
4996 mDNSlocal int SetupActiveInterfaces(mDNSs32 utc)
4997 {
4998     mDNS *const m = &mDNSStorage;
4999     NetworkInterfaceInfoOSX *i;
5000     int count = 0;
5001
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)
5005         if (i->Exists)
5006         {
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);
5010
5011             if (i->Registered && i->Registered != primary)  // Sanity check
5012             {
5013                 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
5014                 i->Registered = mDNSNULL;
5015             }
5016
5017             if (!i->Registered)
5018             {
5019                 InterfaceActivationSpeed activationSpeed;
5020
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;
5025
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);
5030
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)
5038                 {
5039                     activationSpeed = FastActivation;
5040                     LogInfo("SetupActiveInterfaces: %s DirectLink interface registering", i->ifinfo.ifname);
5041                 }
5042                 else if (i->Flashing && i->Occulting)
5043                 {
5044                     activationSpeed = SlowActivation;
5045                 }
5046                 else
5047                 {
5048                     activationSpeed = NormalActivation;
5049                 }
5050
5051                 mDNS_RegisterInterface(m, n, activationSpeed);
5052
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)"   : "");
5059
5060                 if (!n->McastTxRx)
5061                 {
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)
5067                     {
5068                         struct ip_mreq imr;
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;
5072
5073                         if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET) == i)
5074                         {
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));
5079                         }
5080                     }
5081                     if (i->sa_family == AF_INET6)
5082                     {
5083                         struct ipv6_mreq i6mr;
5084                         i6mr.ipv6mr_interface = primary->scope_id;
5085                         i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
5086
5087                         if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET6) == i)
5088                         {
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);
5093                         }
5094                     }
5095 #endif // TARGET_OS_EMBEDDED
5096                 }
5097                 else
5098                 {
5099                     if (i->sa_family == AF_INET)
5100                     {
5101                         struct ip_mreq imr;
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;
5105
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)
5117                         {
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));
5122                         }
5123
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);
5129                     }
5130                     if (i->sa_family == AF_INET6)
5131                     {
5132                         struct ipv6_mreq i6mr;
5133                         i6mr.ipv6mr_interface = primary->scope_id;
5134                         i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
5135
5136                         if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET6) == i)
5137                         {
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);
5142                         }
5143
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);
5149                     }
5150                 }
5151             }
5152         }
5153
5154     return count;
5155 }
5156
5157 mDNSlocal void MarkAllInterfacesInactive(mDNSs32 utc)
5158 {
5159     NetworkInterfaceInfoOSX *i;
5160     for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
5161     {
5162         if (i->Exists) i->LastSeen = utc;
5163         i->Exists = mDNSfalse;
5164     }
5165 }
5166
5167 // Returns count of non-link local V4 addresses deregistered (why? -- SC)
5168 mDNSlocal int ClearInactiveInterfaces(mDNSs32 utc)
5169 {
5170     mDNS *const m = &mDNSStorage;
5171     // First pass:
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;
5177     int count = 0;
5178     for (i = m->p->InterfaceList; i; i = i->next)
5179     {
5180         // If this interface is no longer active, or its InterfaceID is changing, deregister it
5181         NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
5182         if (i->Registered)
5183             if (i->Exists == 0 || i->Exists == MulticastStateChanged || i->Registered != primary)
5184             {
5185                 InterfaceActivationSpeed activationSpeed;
5186
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)"   : "");
5194
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)
5202                 {
5203                     activationSpeed = FastActivation;
5204                     LogInfo("ClearInactiveInterfaces: %s DirectLink interface deregistering", i->ifinfo.ifname);
5205                 }
5206                 else if (i->Flashing && i->Occulting)
5207                 {
5208                     activationSpeed = SlowActivation;
5209                 }
5210                 else
5211                 {
5212                     activationSpeed = NormalActivation;
5213                 }
5214                 mDNS_DeregisterInterface(m, &i->ifinfo, activationSpeed);
5215
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.
5221
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.
5224             }
5225     }
5226
5227     // Second pass:
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;
5230     while (*p)
5231     {
5232         i = *p;
5233         // If no longer active, delete interface from list and free memory
5234         if (!i->Exists)
5235         {
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
5245             if (delete)
5246             {
5247                 *p = i->next;
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
5250             }
5251         }
5252         p = &i->next;
5253     }
5254     return count;
5255 }
5256
5257 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
5258 {
5259     DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
5260     if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
5261     else
5262     {
5263         dnle->next = mDNSNULL;
5264         dnle->uid  = uid;
5265         AssignDomainName(&dnle->name, name);
5266         **List = dnle;
5267         *List = &dnle->next;
5268     }
5269 }
5270
5271 mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
5272 {
5273     dns_resolver_t *a = *(dns_resolver_t**)aa;
5274     dns_resolver_t *b = *(dns_resolver_t**)bb;
5275
5276     return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
5277 }
5278
5279 mDNSlocal void UpdateSearchDomainHash(MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID)
5280 {
5281     mDNS *const m = &mDNSStorage;
5282     char *buf = ".";
5283     mDNSu32 scopeid = 0;
5284     char ifid_buf[16];
5285
5286     if (domain)
5287         buf = domain;
5288     //
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.
5292     //
5293     // Note: We have to handle a few of these tricky cases.
5294     //
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)
5299     //
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.
5303
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);
5308
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);
5312 }
5313
5314 mDNSlocal void FinalizeSearchDomainHash(MD5_CTX *sdc)
5315 {
5316     mDNS *const m = &mDNSStorage;
5317     mDNSu8 md5_hash[MD5_LEN];
5318
5319     MD5_Final(md5_hash, sdc);
5320
5321     if (memcmp(md5_hash, m->SearchDomainsHash, MD5_LEN))
5322     {
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);
5329     }
5330     else { LogInfo("FinalizeSearchDomains: The hash is same"); }
5331 }
5332
5333 mDNSexport const char *DNSScopeToString(mDNSu32 scope)
5334 {
5335     switch (scope)
5336     {
5337         case kScopeNone:
5338             return "Unscoped";
5339         case kScopeInterfaceID:
5340             return "InterfaceScoped";
5341         case kScopeServiceID:
5342             return "ServiceScoped";
5343         default:
5344             return "Unknown";
5345     }
5346 }
5347
5348 mDNSlocal void ConfigSearchDomains(dns_resolver_t *resolver, mDNSInterfaceID interfaceId, mDNSu32 scope,  MD5_CTX *sdc, uint64_t generation)
5349 {
5350     const char *scopeString = DNSScopeToString(scope);
5351     int j;
5352     domainname d;
5353
5354     if (scope == kScopeNone)
5355         interfaceId = mDNSInterface_Any;
5356
5357     if (scope == kScopeNone || scope == kScopeInterfaceID)
5358     {
5359         for (j = 0; j < resolver->n_search; j++)
5360         {
5361             if (MakeDomainNameFromDNSNameString(&d, resolver->search[j]) != NULL)
5362             {
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);
5369             }
5370             else
5371             {
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);
5374             }
5375         }
5376     }
5377     else
5378     {
5379         LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString, InterfaceNameForID(&mDNSStorage, interfaceId));
5380     }
5381 }
5382
5383 mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNSu32 ifindex)
5384 {
5385     NetworkInterfaceInfoOSX *ni;
5386     mDNSInterfaceID interface;
5387
5388     for (ni = mDNSStorage.p->InterfaceList; ni; ni = ni->next)
5389     {
5390         if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex) 
5391             break;
5392     }
5393     if (ni != NULL) 
5394     {
5395         interface = ni->ifinfo.InterfaceID;
5396     }
5397     else
5398     {
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.
5404
5405         LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex);
5406
5407         // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
5408         interface = (mDNSInterfaceID)(unsigned long)ifindex;
5409     }
5410     return interface;
5411 }
5412
5413 mDNSlocal void ConfigNonUnicastResolver(dns_resolver_t *r)
5414 {
5415     char *opt = r->options;
5416     domainname d; 
5417
5418     if (opt && !strncmp(opt, "mdns", strlen(opt)))
5419     {
5420         if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5421         { 
5422             LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain); 
5423             return;
5424         }
5425         mDNS_AddMcastResolver(&mDNSStorage, &d, mDNSInterface_Any, r->timeout);
5426     }
5427 }
5428
5429 mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID)
5430 {
5431     int n;
5432     domainname d;
5433     int serviceID = 0;
5434     mDNSBool cellIntf = mDNSfalse;
5435     mDNSBool reqA, reqAAAA;
5436     NetworkInterfaceInfoOSX *info;
5437     mDNSBool isExpensive;
5438
5439     if (!r->domain || !*r->domain) 
5440     {
5441         d.c[0] = 0;
5442     }
5443     else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5444     { 
5445         LogMsg("ConfigDNSServers: bad domain %s", r->domain); 
5446         return;
5447     }
5448     // Parse the resolver specific attributes that affects all the DNS servers.
5449     if (scope == kScopeServiceID)
5450     {
5451         serviceID = r->service_identifier;
5452     }
5453
5454 #if TARGET_OS_IPHONE
5455     cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
5456 #endif
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;
5461
5462     for (n = 0; n < r->n_nameserver; n++)
5463     {
5464         mDNSAddr saddr;
5465         DNSServer *s;
5466
5467         if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6)
5468             continue;
5469         
5470         if (SetupAddr(&saddr, r->nameserver[n]))
5471         {
5472             LogMsg("ConfigDNSServers: Bad address");
5473             continue;
5474         }
5475         
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
5479         //
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);
5485         if (s)
5486         {
5487             LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c);
5488         }
5489     }
5490 }
5491
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.
5494 //
5495 // "resolver" has entries that should only be used for unscoped questions.
5496 //
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)
5499 //
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)
5502 //
5503 mDNSlocal void ConfigResolvers(dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc, mDNSu16 resGroupID)
5504 {
5505     int i;
5506     dns_resolver_t **resolver;
5507     int nresolvers;
5508     const char *scopeString = DNSScopeToString(scope);
5509     mDNSInterfaceID interface;
5510
5511     switch (scope)
5512     {
5513         case kScopeNone:
5514             resolver = config->resolver;
5515             nresolvers = config->n_resolver;
5516             break;
5517         case kScopeInterfaceID:
5518             resolver = config->scoped_resolver;
5519             nresolvers = config->n_scoped_resolver;
5520             break;
5521         case kScopeServiceID:
5522             resolver = config->service_specific_resolver;
5523             nresolvers = config->n_service_specific_resolver;
5524             break;
5525         default:
5526             return;
5527     }
5528     qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
5529
5530     for (i = 0; i < nresolvers; i++)
5531     {
5532         dns_resolver_t *r = resolver[i];
5533
5534         LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString, i, r->domain, r->n_nameserver);
5535
5536         interface = mDNSInterface_Any;
5537
5538         // Parse the interface index 
5539         if (r->if_index != 0)
5540         {
5541             interface = ConfigParseInterfaceID(r->if_index);
5542         }
5543
5544         if (setsearch)
5545         {
5546             ConfigSearchDomains(resolver[i], interface, scope, sdc, config->generation);
5547             
5548             // Parse other scoped resolvers for search lists
5549             if (!setservers) 
5550                 continue;
5551         }
5552
5553         if (r->port == 5353 || r->n_nameserver == 0)
5554         {
5555             ConfigNonUnicastResolver(r);
5556         }
5557         else
5558         {
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) 
5562                 resGroupID++;
5563
5564             ConfigDNSServers(r, interface, scope, resGroupID);
5565         }
5566     }
5567 }
5568
5569 #if APPLE_OSX_mDNSResponder
5570 mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
5571 {
5572     if (QuerySuppressed(q))
5573     {
5574         debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5575         return mDNSfalse;
5576     }
5577     if (mDNSOpaque16IsZero(q->TargetQID))
5578     {
5579         debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5580         return mDNSfalse;
5581     }
5582     // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
5583     // for trigger.
5584     if (q->LOAddressAnswers)
5585     {
5586         debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5587         return mDNSfalse;
5588     }
5589     return mDNStrue;
5590 }
5591 #endif
5592
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)
5598 {
5599     mDNS *const m = &mDNSStorage;
5600     if (!QuestionValidForDNSTrigger(q))
5601         return;
5602
5603     // Ignore applications that start and stop queries for no reason before we ever talk
5604     // to any DNS server.
5605     if (!q->triedAllServersOnce)
5606     {
5607         LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q->qname.c, DNSTypeName(q->qtype));
5608         return;
5609     }
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)
5615     {
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));
5618     }
5619 }
5620 #endif
5621
5622 mDNSlocal void AckConfigd(dns_config_t *config)
5623 {
5624     mDNS_CheckLock(&mDNSStorage);
5625
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");
5629 }
5630
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)
5635 {
5636     mDNS *const m = &mDNSStorage;
5637     mDNSBool trigger = mDNSfalse;
5638     mDNSs32 timenow;
5639
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.
5649     mDNS_Lock(m);
5650     timenow = m->timenow;
5651     if (m->p->DNSTrigger && (timenow - m->p->DNSTrigger) < DNS_TRIGGER_INTERVAL)
5652     {
5653         if (!m->p->v4answers || !m->p->v6answers)
5654         {
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);
5657         }
5658         mDNS_Unlock(m);
5659         return;
5660     }
5661     mDNS_Unlock(m);
5662     if (v4q != NULL && QuestionValidForDNSTrigger(v4q))
5663     {
5664         int old = m->p->v4answers;
5665
5666         m->p->v4answers = 1;
5667
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.
5671         if (!old)
5672         {
5673             LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
5674                 v4q->qname.c, DNSTypeName(v4q->qtype));
5675             trigger = mDNStrue;
5676         }
5677     }
5678     if (v6q != NULL && QuestionValidForDNSTrigger(v6q))
5679     {
5680         int old = m->p->v6answers;
5681
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.
5686         if (!old)
5687         {
5688             LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
5689                 v6q->qname.c, DNSTypeName(v6q->qtype));
5690             trigger = mDNStrue;
5691         }
5692     }
5693     if (trigger)
5694     {
5695         dns_config_t *config = dns_configuration_copy();
5696         if (config)
5697         {
5698             mDNS_Lock(m);
5699             AckConfigd(config);
5700             mDNS_Unlock(m);
5701             dns_configuration_free(config);
5702         }
5703         else
5704         {
5705             LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
5706         }
5707     }
5708 }
5709
5710 mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
5711 {
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])
5716     {
5717         MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
5718     }
5719     else
5720     {
5721          ActiveDirectoryPrimaryDomain.c[0] = 0;
5722     }
5723
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))
5728     {
5729         SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
5730     }
5731     else
5732     {
5733         AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
5734         ActiveDirectoryPrimaryDomainLabelCount = 0;
5735         ActiveDirectoryPrimaryDomainServer = zeroAddr;
5736     }
5737 }
5738 #endif
5739
5740 mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
5741 {
5742     int i;
5743     char buf[MAX_ESCAPED_DOMAIN_NAME];  // Max legal C-string name, including terminating NULL
5744     domainname d;
5745
5746     CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_DynamicDNS);
5747     if (ddnsdict)
5748     {
5749         if (fqdn)
5750         {
5751             CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
5752             if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
5753             {
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))
5757                 {
5758                     CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
5759                     if (name)
5760                     {
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)");
5764                         else 
5765                             debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
5766                     }
5767                 }
5768             }
5769         }
5770         if (RegDomains)
5771         {
5772             CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
5773             if (regArray && CFArrayGetCount(regArray) > 0)
5774             {
5775                 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
5776                 if (regDict && DictionaryIsEnabled(regDict))
5777                 {
5778                     CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
5779                     if (name)
5780                     {
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)");
5784                         else
5785                         {
5786                             debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
5787                             AppendDNameListElem(&RegDomains, 0, &d);
5788                         }
5789                     }
5790                 }
5791             }
5792         }
5793         if (BrowseDomains)
5794         {
5795             CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
5796             if (browseArray)
5797             {
5798                 for (i = 0; i < CFArrayGetCount(browseArray); i++)
5799                 {
5800                     CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
5801                     if (browseDict && DictionaryIsEnabled(browseDict))
5802                     {
5803                         CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
5804                         if (name)
5805                         {
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)");
5809                             else
5810                             {
5811                                 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
5812                                 AppendDNameListElem(&BrowseDomains, 0, &d);
5813                             }
5814                         }
5815                     }
5816                 }
5817             }
5818         }
5819         CFRelease(ddnsdict);
5820     }
5821     if (RegDomains)
5822     {
5823         CFDictionaryRef btmm = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BackToMyMac);
5824         if (btmm)
5825         {
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++)
5831             {
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);
5835                 else
5836                 {
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])
5841                     {
5842                         LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
5843                         AppendDNameListElem(&RegDomains, uid, &d);
5844                     }
5845                 }
5846             }
5847             CFRelease(btmm);
5848         }
5849     }
5850
5851 }
5852
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)
5856 {
5857     mDNS *const m = &mDNSStorage;
5858     MD5_CTX sdc;    // search domain context
5859     static mDNSu16 resolverGroupID = 0;
5860
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;
5865
5866     LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
5867             setservers    ? " setservers"    : "",
5868             setsearch     ? " setsearch"     : "",
5869             fqdn          ? " fqdn"          : "",
5870             RegDomains    ? " RegDomains"    : "",
5871             BrowseDomains ? " BrowseDomains" : "");
5872
5873     if (setsearch) MD5_Init(&sdc);
5874
5875     // Add the inferred address-based configuration discovery domains
5876     // (should really be in core code I think, not platform-specific)
5877     if (setsearch)
5878     {
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;
5884         saddr.sin_port = 0;
5885         saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
5886
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);
5889
5890         while (ifa)
5891         {
5892             mDNSAddr a, n;
5893             char buf[64];
5894
5895             if (ifa->ifa_addr->sa_family == AF_INET &&
5896                 ifa->ifa_netmask                    &&
5897                 !(ifa->ifa_flags & IFF_LOOPBACK)    &&
5898                 !SetupAddr(&a, ifa->ifa_addr)       &&
5899                 !mDNSv4AddressIsLinkLocal(&a.ip.v4)  )
5900             {
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);
5912             }
5913             ifa = ifa->ifa_next;
5914         }
5915     }
5916
5917 #ifndef MDNS_NO_DNSINFO
5918     if (setservers || setsearch)
5919     {
5920         dns_config_t *config = dns_configuration_copy();
5921         if (!config)
5922         {
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");
5929         }
5930         else
5931         {
5932             LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config->n_resolver, config->generation, m->p->LastConfigGeneration);
5933
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.
5941
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.
5947
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)
5950             {
5951                 LogInfo("mDNSPlatformSetDNSConfig(setservers): generation number %llu same, not processing", config->generation);
5952                 dns_configuration_free(config);
5953                 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
5954                 return mDNSfalse;
5955             }
5956 #if APPLE_OSX_mDNSResponder
5957             SetupActiveDirectoryDomain(config);
5958 #endif
5959
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.
5965             //
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;
5969
5970             ConfigResolvers(config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID);
5971             resolverGroupID += config->n_scoped_resolver;
5972
5973             ConfigResolvers(config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID);
5974
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.
5979             if (ackConfig)
5980             {
5981                 // Note: We have to set the generation number here when we are acking.
5982                 // For every DNS configuration change, we do the following:
5983                 //
5984                 // 1) Copy dns configuration, handle search domains change
5985                 // 2) Copy dns configuration, handle dns server change
5986                 //
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
5990                 // during acking.
5991                 m->p->LastConfigGeneration = config->generation;
5992                 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers, setsearch);
5993                 AckConfigd(config);
5994             }
5995             dns_configuration_free(config);
5996             if (setsearch) FinalizeSearchDomainHash(&sdc);
5997         }
5998     }
5999 #endif // MDNS_NO_DNSINFO
6000     SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6001     return mDNStrue;
6002 }
6003
6004
6005 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
6006 {
6007     char buf[256];
6008
6009     CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_IPv4);
6010     if (dict)
6011     {
6012         r->type  = mDNSAddrType_IPv4;
6013         r->ip.v4 = zerov4Addr;
6014         CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
6015         if (string)
6016         {
6017             if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
6018                 LogMsg("Could not convert router to CString");
6019             else
6020             {
6021                 struct sockaddr_in saddr;
6022                 saddr.sin_len = sizeof(saddr);
6023                 saddr.sin_family = AF_INET;
6024                 saddr.sin_port = 0;
6025                 inet_aton(buf, &saddr.sin_addr);
6026                 *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
6027             }
6028         }
6029         string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
6030         if (string)
6031         {
6032             mDNSBool HavePrimaryGlobalv6 = mDNSfalse;  // does the primary interface have a global v6 address?
6033             struct ifaddrs *ifa = myGetIfAddrs(1);
6034             *v4 = *v6 = zeroAddr;
6035
6036             if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) 
6037             { 
6038                 LogMsg("Could not convert router to CString"); 
6039                 goto exit; 
6040             }
6041             // find primary interface in list
6042             while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
6043             {
6044                 if (!ifa->ifa_addr)
6045                 {
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;
6048                     continue;
6049                 }
6050                 mDNSAddr tmp6 = zeroAddr;
6051                 if (!strcmp(buf, ifa->ifa_name))
6052                 {
6053                     if (ifa->ifa_addr->sa_family == AF_INET)
6054                     {
6055                         if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) 
6056                             SetupAddr(v4, ifa->ifa_addr);
6057                     }
6058                     else if (ifa->ifa_addr->sa_family == AF_INET6)
6059                     {
6060                         SetupAddr(&tmp6, ifa->ifa_addr);
6061                         if (tmp6.ip.v6.b[0] >> 5 == 1)   // global prefix: 001
6062                         { 
6063                             HavePrimaryGlobalv6 = mDNStrue; 
6064                             *v6 = tmp6; 
6065                         }
6066                     }
6067                 }
6068                 else
6069                 {
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])
6072                     {
6073                         SetupAddr(&tmp6, ifa->ifa_addr);
6074                         if (tmp6.ip.v6.b[0] >> 5 == 1) 
6075                             *v6 = tmp6;
6076                     }
6077                 }
6078                 ifa = ifa->ifa_next;
6079             }
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
6082         }
6083
6084 exit:
6085         CFRelease(dict);
6086     }
6087     return mStatus_NoError;
6088 }
6089
6090 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
6091 {
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);
6095
6096     char *p = uname;
6097     while (*p)
6098     {
6099         *p = tolower(*p);
6100         if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
6101         p++;
6102     }
6103
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).
6111
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);
6116     else
6117     {
6118         const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
6119         if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
6120         else
6121         {
6122             const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6123             if (HostVals[0])
6124             {
6125                 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6126                 if (StateVals[0])
6127                 {
6128                     CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6129                     if (StateDict)
6130                     {
6131                         mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
6132                         CFRelease(StateDict);
6133                     }
6134                     CFRelease(StateVals[0]);
6135                 }
6136                 CFRelease(HostVals[0]);
6137             }
6138             CFRelease(StatusVals[0]);
6139         }
6140         CFRelease(HostKeys[0]);
6141     }
6142 }
6143
6144 #if APPLE_OSX_mDNSResponder
6145 #if !NO_AWACS
6146
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
6149 // help catch it
6150 mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
6151 {
6152     SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
6153     if (!store)
6154     {
6155         LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6156         return mDNSfalse;
6157     }
6158     CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
6159     if (btmm)
6160     {
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];
6165         domainname dom;
6166         int i;
6167         CFDictionaryGetKeysAndValues(btmm, key, val);
6168         for (i = 0; i < size; i++)
6169         {
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);
6173             else
6174             {
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])
6179                 {
6180                     if (SameDomainName(&dom, d))
6181                     {
6182                         LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
6183                         CFRelease(btmm);
6184                         CFRelease(store);
6185                         return mDNStrue;
6186                     }
6187                 }
6188             }
6189         }
6190         CFRelease(btmm);
6191     }
6192     CFRelease(store);
6193     LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
6194     return mDNSfalse;
6195 }
6196
6197 // Appends data to the buffer
6198 mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
6199 {
6200     int len;
6201
6202     len = strlcpy(buf + *currlen, data, bufsz - *currlen);
6203     if (len >= (bufsz - *currlen))
6204     {
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;
6210         return -1;
6211     }
6212     else { (*currlen) += len; }
6213
6214     buf[*currlen] = ',';
6215     if (*currlen >= bufsz)
6216     {
6217         LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
6218         *currlen = bufsz - 1;
6219         buf[*currlen] = 0;
6220         return -1;
6221     }
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; }
6224     (*currlen)++;
6225     return *currlen;
6226 }
6227
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)
6231 {
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];
6238     int currulen = 0;
6239     int currplen = 0;
6240
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.
6246     //
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.
6249
6250     for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6251         if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
6252         {
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;
6259         }
6260
6261     if (BTMMDomain)
6262     {
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.
6266
6267         if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
6268         if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
6269
6270         LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
6271         AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
6272         AWACSDConnected = mDNStrue;
6273     }
6274     else
6275     {
6276         // Disconnect only if we connected previously
6277         if (AWACSDConnected)
6278         {
6279             LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
6280             AWACS_Disconnect();
6281             AWACSDConnected = mDNSfalse;
6282         }
6283         else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
6284     }
6285 }
6286 #elif !TARGET_OS_EMBEDDED
6287 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6288 {
6289     (void) m; // Unused
6290     LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
6291 }
6292 #endif // ! NO_AWACS
6293
6294 #if !TARGET_OS_EMBEDDED
6295 mDNSlocal void ProcessConndConfigChanges(void);
6296 #endif
6297
6298 #endif // APPLE_OSX_mDNSResponder
6299
6300 // MUST be called holding the lock
6301 mDNSlocal void SetDomainSecrets_internal(mDNS *m)
6302 {
6303 #ifdef NO_SECURITYFRAMEWORK
6304         (void) m;
6305     LogMsg("Note: SetDomainSecrets: no keychain support");
6306 #else
6307     mDNSBool haveAutoTunnels = mDNSfalse;
6308
6309     LogInfo("SetDomainSecrets");
6310
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);
6319
6320 #if APPLE_OSX_mDNSResponder
6321     {
6322         // Mark all TunnelClients for deletion
6323         ClientTunnel *client;
6324         for (client = m->TunnelClients; client; client = client->next)
6325         {
6326             LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
6327             client->MarkedForDeletion = mDNStrue;
6328         }
6329     }
6330 #endif // APPLE_OSX_mDNSResponder
6331
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; }
6335     CFIndex i;
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);
6342     else
6343     {
6344         CFIndex ArrayCount = CFArrayGetCount(secrets);
6345         // Iterate through the secrets
6346         for (i = 0; i < ArrayCount; ++i)
6347         {
6348             mDNSBool AutoTunnel;
6349             int j, offset;
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; }
6356
6357             // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
6358
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';
6367
6368             AutoTunnel = mDNSfalse;
6369             offset = 0;
6370             if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
6371                 offset = strlen(dnsprefix);
6372             else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix)))
6373             {
6374                 AutoTunnel = mDNStrue;
6375                 offset = strlen(btmmprefix);
6376             }
6377             domainname domain;
6378             if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
6379
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';
6386
6387             domainname keyname;
6388             if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
6389
6390             // Get key data (kmDNSKcKey)
6391             data = CFArrayGetValueAtIndex(entry, kmDNSKcKey);
6392             if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6393             { 
6394                 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data));
6395                 continue;
6396             }
6397             CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6398             stringbuf[CFDataGetLength(data)] = '\0';    // mDNS_SetSecretForDomain requires NULL-terminated C string for key
6399
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))
6405             { 
6406                 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data));
6407                 continue;
6408             }
6409             CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)hostbuf);
6410             hostbuf[CFDataGetLength(data)] = '\0';
6411
6412             domainname hostname;
6413             mDNSIPPort port;
6414             char *hptr;
6415             hptr = strchr(hostbuf, ':');
6416
6417             port.NotAnInteger = 0;
6418             if (hptr)
6419             {
6420                 mDNSu8 *p;
6421                 mDNSu16 val = 0;
6422
6423                 *hptr++ = '\0';
6424                 while(hptr && *hptr != 0)
6425                 {
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';
6429                     hptr++;
6430                 }
6431                 if (!val) continue;
6432                 p = (mDNSu8 *)&val;
6433                 port.NotAnInteger = p[0] << 8 | p[1];
6434             }
6435             // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
6436             hptr = strchr(hostbuf, '@');
6437             if (hptr)
6438                 hptr++;
6439             else
6440                 hptr = hostbuf;
6441             if (!MakeDomainNameFromDNSNameString(&hostname, hptr)) { LogMsg("SetDomainSecrets: bad host name %s", hptr); continue; }
6442
6443             DomainAuthInfo *FoundInList;
6444             for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6445                 if (SameDomainName(&FoundInList->domain, &domain)) break;
6446
6447 #if APPLE_OSX_mDNSResponder
6448             if (FoundInList)
6449             {
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))
6454                     {
6455                         LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
6456                         client->MarkedForDeletion = mDNSfalse;
6457                     }
6458             }
6459
6460 #endif // APPLE_OSX_mDNSResponder
6461
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]));
6466
6467             // If didn't find desired domain in the list, make a new entry
6468             ptr = FoundInList;
6469             if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
6470             if (!FoundInList)
6471             {
6472                 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
6473                 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
6474             }
6475
6476             //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
6477
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)
6480             {
6481                 if (!FoundInList) mDNSPlatformMemFree(ptr);     // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
6482                 continue;
6483             }
6484
6485             ConvertDomainNameToCString(&domain, stringbuf);
6486             CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
6487             if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
6488         }
6489         CFRelease(secrets);
6490     }
6491
6492     if (!privateDnsArray || !CFEqual(privateDnsArray, sa))
6493     {
6494         if (privateDnsArray)
6495             CFRelease(privateDnsArray);
6496         
6497         privateDnsArray = sa;
6498         CFRetain(privateDnsArray);
6499         mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
6500     }
6501     CFRelease(sa);
6502
6503 #if APPLE_OSX_mDNSResponder
6504     {
6505         // clean up ClientTunnels
6506         ClientTunnel **pp = &m->TunnelClients;
6507         while (*pp)
6508         {
6509             if ((*pp)->MarkedForDeletion)
6510             {
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);
6515                 *pp = cur->next;
6516                 freeL("ClientTunnel", cur);
6517             }
6518             else
6519                 pp = &(*pp)->next;
6520         }
6521
6522         mDNSBool needAutoTunnelNAT = mDNSfalse;
6523         DomainAuthInfo *info;
6524         for (info = m->AuthInfoList; info; info = info->next)
6525         {
6526             if (info->AutoTunnel)
6527             {
6528                 UpdateAutoTunnelDeviceInfoRecord(m, info);
6529                 UpdateAutoTunnelHostRecord(m, info);
6530                 UpdateAutoTunnelServiceRecords(m, info);
6531                 UpdateAutoTunnel6Record(m, info);
6532                 if (info->deltime)
6533                 {
6534                     if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse;
6535                 }
6536                 else if (info->AutoTunnelServiceStarted)
6537                     needAutoTunnelNAT = true;
6538
6539                     UpdateAutoTunnelDomainStatus(info);
6540             }
6541         }
6542
6543         // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
6544         if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext)
6545         {
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;
6555         }
6556
6557         UpdateAnonymousRacoonConfig(m);     // Determine whether we need racoon to accept incoming connections
6558         ProcessConndConfigChanges();       // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
6559     }
6560 #endif // APPLE_OSX_mDNSResponder
6561
6562     CheckSuppressUnusableQuestions(m);
6563
6564 #endif /* NO_SECURITYFRAMEWORK */
6565 }
6566
6567 mDNSexport void SetDomainSecrets(mDNS *m)
6568 {
6569 #if DEBUG
6570     // Don't get secrets for BTMM if running in debug mode
6571     if (!IsDebugSocketInUse())
6572 #endif
6573     SetDomainSecrets_internal(m);
6574 }
6575
6576 mDNSlocal void SetLocalDomains(void)
6577 {
6578     CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6579     if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
6580
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"));
6587
6588     mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
6589     CFRelease(sa);
6590 }
6591
6592 mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
6593 {
6594         
6595     CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_PowerSettings);
6596     if (!dict)
6597     {
6598         LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
6599     }
6600     else
6601     {
6602         CFNumberRef number = CFDictionaryGetValue(dict, name);
6603         if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
6604             *val = 0;
6605         CFRelease(dict);
6606     }
6607         
6608 }
6609
6610 #if APPLE_OSX_mDNSResponder
6611
6612 static CFMutableDictionaryRef spsStatusDict = NULL;
6613 static const CFStringRef kMetricRef = CFSTR("Metric");
6614
6615 mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
6616 {
6617     mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
6618     CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
6619     if (!num)
6620         LogMsg("SPSStatusPutNumber: Could not create CFNumber");
6621     else
6622     {
6623         CFDictionarySetValue(dict, key, num);
6624         CFRelease(num);
6625     }
6626 }
6627
6628 mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
6629 {
6630     CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6631     if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
6632
6633     char buffer[1024];
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);
6638     CFRelease(spsname);
6639
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"));
6644
6645     mDNSu32 tmp = SPSMetric(ptr);
6646     CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
6647     if (!num)
6648         LogMsg("SPSCreateDict: Could not create CFNumber");
6649     else
6650     {
6651         CFDictionarySetValue(dict, kMetricRef, num);
6652         CFRelease(num);
6653     }
6654
6655     if (ptr[0] >= 12)
6656     {
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; }
6661         else
6662         {
6663             CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
6664             CFRelease(spsname);
6665         }
6666     }
6667
6668     return dict;
6669 }
6670
6671 mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
6672 {
6673     (void)context;
6674     return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
6675                            (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
6676                            NULL);
6677 }
6678
6679 mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
6680 {
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>");
6683
6684     mDNS_Lock(m);
6685     mDNS_UpdateAllowSleep(m);
6686     mDNS_Unlock(m);
6687
6688     if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return;  // Ignore instances with invalid names
6689
6690     if (!spsStatusDict)
6691     {
6692         spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6693         if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
6694     }
6695
6696     CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
6697     if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
6698
6699     CFMutableArrayRef array = NULL;
6700
6701     if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
6702     {
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
6707     }
6708     else
6709     if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
6710
6711     if (!answer) // special call that means the question has been stopped (because the interface is going away)
6712         CFArrayRemoveAllValues(array);
6713     else
6714     {
6715         CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
6716         if (!dict) { CFRelease(ifname); return; }
6717
6718         if (AddRecord)
6719         {
6720             if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
6721             {
6722                 int i=0;
6723                 for (i=0; i<CFArrayGetCount(array); i++)
6724                     if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
6725                         break;
6726                 CFArrayInsertValueAtIndex(array, i, dict);
6727             }
6728             else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
6729         }
6730         else
6731         {
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);
6735         }
6736
6737         CFRelease(dict);
6738     }
6739
6740     if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
6741
6742     CFRelease(ifname);
6743 }
6744
6745 mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
6746 {
6747     mDNSs32 val = -1;
6748     SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
6749     if (!store)
6750         LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6751     else
6752     {
6753         CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
6754         if (dict)
6755         {
6756             CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
6757             if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
6758             CFRelease(dict);
6759         }
6760         CFRelease(store);
6761     }
6762     return val;
6763 }
6764
6765 mDNSlocal void SetSPS(mDNS *const m)
6766 {
6767     
6768     // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
6769     mDNSu8 sps = (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware : 0;
6770
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;
6774
6775     // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
6776
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;
6781
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;
6785
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.
6788     if (IsAppleTV())
6789     {
6790         NetworkInterfaceInfo *intf  = mDNSNULL;
6791         mDNSEthAddr           bssid = zeroEthAddr;
6792         for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
6793         {
6794             if (intf->InterfaceID == AWDLInterfaceID) continue;
6795             bssid = GetBSSID(intf->ifname);
6796             if (!mDNSSameEthAddress(&bssid, &zeroEthAddr))
6797             {
6798                 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
6799                 sps = 0;
6800                 break;
6801             }
6802         }
6803     }
6804 #endif  //  NO_APPLETV_SLEEP_PROXY_ON_WIFI
6805
6806     mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
6807 }
6808
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.
6812
6813 enum
6814 {                               // commands from the daemon to the driver
6815     cmd_mDNSOffloadRR = 21,     // give the mdns update buffer to the driver
6816 };
6817
6818 typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr;
6819
6820 typedef struct
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)
6831 } mDNSOffloadCmd;
6832
6833 #include <IOKit/IOKitLib.h>
6834 #include <dns_util.h>
6835
6836 mDNSlocal mDNSu16 GetPortArray(int trans, mDNSIPPort *portarray)
6837 {
6838     mDNS *const m = &mDNSStorage;
6839     const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
6840     int   count = 0;
6841
6842     AuthRecord *rr;
6843     for (rr = m->ResourceRecords; rr; rr=rr->next)
6844     {
6845         if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c))
6846         {
6847             if (!portarray)
6848                 count++;
6849             else
6850             {
6851                 int i;
6852                 for (i = 0; i < count; i++)
6853                     if (mDNSSameIPPort(portarray[i], rr->resrec.rdata->u.srv.port))
6854                         break;
6855
6856                 // Add it into the port list only if it not already present in the list
6857                 if (i >= count)
6858                     portarray[count++] = rr->resrec.rdata->u.srv.port;
6859             }
6860         }
6861     }
6862
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)
6865     {
6866         LogSPS("GetPortArray Back to My Mac at %d", count);
6867         if (portarray) portarray[count] = IPSECPort;
6868         count++;
6869     }
6870     return(count);
6871 }
6872
6873 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6874 mDNSlocal mDNSBool SupportsTCPKeepAlive()
6875 {
6876     IOReturn  ret      = kIOReturnSuccess;
6877     CFTypeRef obj      = NULL;
6878     mDNSBool  supports = mDNSfalse;
6879
6880     ret = IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj);
6881     if ((kIOReturnSuccess == ret) && (obj != NULL))
6882     {
6883         supports = (obj ==  kCFBooleanTrue)? mDNStrue : mDNSfalse;
6884         CFRelease(obj);
6885     }
6886     LogSPS("%s: The hardware %s TCP Keep Alive", __func__, (supports ? "supports" : "does not support"));
6887     return supports;
6888 }
6889
6890 mDNSlocal mDNSBool OnBattery(void)
6891 {
6892     CFTypeRef powerInfo = IOPSCopyPowerSourcesInfo();
6893     CFTypeRef powerSrc  = IOPSGetProvidingPowerSourceType(powerInfo);
6894     mDNSBool  result    = mDNSfalse;
6895
6896     if (powerInfo != NULL)
6897     {
6898         result = CFEqual(CFSTR(kIOPSBatteryPowerValue), powerSrc);
6899         CFRelease(powerInfo);
6900     }
6901     LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
6902     return result;
6903 }
6904
6905 #endif // !TARGET_OS_EMBEDDED
6906
6907 #define TfrRecordToNIC(RR) \
6908     ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
6909
6910 mDNSlocal mDNSu32 CountProxyRecords(uint32_t *const numbytes, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
6911 {
6912     mDNS *const m = &mDNSStorage;
6913     *numbytes = 0;
6914     int count = 0;
6915
6916     AuthRecord *rr;
6917
6918     for (rr = m->ResourceRecords; rr; rr=rr->next)
6919     {
6920         if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
6921         {
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))
6927                 continue;
6928
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));
6934
6935                         // Offload only Valid Keepalive records
6936                         if (isKeepAliveRecord && !mDNSValidKeepAliveRecord(rr))
6937                                 continue;
6938 #else
6939             (void) TCPKAOnly;     // unused
6940             (void) supportsTCPKA; // unused
6941             (void) intf;          // unused
6942 #endif // APPLE_OSX_mDNSResponder
6943             if (TfrRecordToNIC(rr))
6944             {
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));
6948                 count++;
6949             }
6950         }
6951     }
6952     return(count);
6953 }
6954
6955 mDNSlocal void GetProxyRecords(DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
6956 {
6957     mDNS *const m = &mDNSStorage;
6958     mDNSu8 *p = msg->data;
6959     const mDNSu8 *const limit = p + *numbytes;
6960     InitializeDNSMessage(&msg->h, zeroID, zeroID);
6961
6962     int count = 0;
6963     AuthRecord *rr;
6964
6965     for (rr = m->ResourceRecords; rr; rr=rr->next)
6966     {
6967         if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
6968         {
6969 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6970             mDNSBool   isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
6971
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))
6975                 continue;
6976
6977                         // Offload only Valid Keepalive records
6978                         if (isKeepAliveRecord && !mDNSValidKeepAliveRecord(rr))
6979                                 continue;
6980 #else
6981             (void) TCPKAOnly;     // unused
6982             (void) supportsTCPKA; // unused
6983 #endif // APPLE_OSX_mDNSResponder
6984
6985             if (TfrRecordToNIC(rr))
6986             {
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));
6995                 count++;
6996             }
6997         }
6998     }
6999     *numbytes = p - msg->data;
7000 }
7001
7002 mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf)
7003 {
7004     if(!UseInternalSleepProxy)
7005     {
7006         LogMsg("SupportsInNICProxy: Internal Sleep Proxy is disabled");
7007         return mDNSfalse;
7008     }
7009     return CheckInterfaceSupport(intf, mDNS_IOREG_KEY);
7010 }
7011
7012 mDNSexport mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool *keepaliveOnly)  // Called with the lock held
7013 {
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));
7019
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());
7024
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);
7029 #else
7030     (void) onbattery; // unused;
7031 #endif
7032     if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", intf->ifname); return(mStatus_UnknownErr); }
7033
7034     io_name_t n1, n2;
7035     IOObjectGetClass(service, n1);
7036     io_object_t parent = IO_OBJECT_NULL;
7037
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);
7040     else
7041     {
7042         CFTypeRef ref = mDNSNULL;
7043         if (IsAppleTV())
7044         {
7045             while (service)
7046             {
7047                 ref = IORegistryEntryCreateCFProperty(parent,  CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
7048                 if (!ref)
7049                 {
7050                     IOObjectRelease(service);
7051                     service = parent;
7052                     kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
7053                     if (kr != KERN_SUCCESS)
7054                     {
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;
7059                         break;
7060                     }
7061                 }
7062                 else
7063                 {
7064                     IOObjectGetClass(parent, n2);
7065                     LogSPS("ActivateLocalProxy: Found  %s Interface %s parent %s", mDNS_IOREG_KEY, intf->ifname, n2);
7066                     break;
7067                 }
7068             }
7069         }
7070         else
7071         {
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);
7075         }
7076
7077         if (!ref || parent == IO_OBJECT_NULL) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
7078         else
7079         {
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);
7085             else
7086             {
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);
7090                 else
7091                 {
7092                     mDNSOffloadCmd cmd;
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);
7099
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;
7104
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);
7110
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);
7114
7115                     char outputData[2];
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;
7120
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);
7126                 }
7127             }
7128             CFRelease(ref);
7129         }
7130         if (parent != IO_OBJECT_NULL) IOObjectRelease(parent);
7131     }
7132     if (service != IO_OBJECT_NULL) IOObjectRelease(service);
7133     *keepaliveOnly = TCPKAOnly;
7134     return result;
7135 }
7136
7137 #endif // APPLE_OSX_mDNSResponder
7138
7139 mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
7140 {
7141     mDNSs32 val = 0;
7142     mDNSu8  ret = (mDNSu8)mDNS_NoWake;
7143
7144 #if TARGET_OS_IOS
7145     LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7146     return ret;
7147 #endif
7148
7149     if (DisableSleepProxyClient)
7150     {
7151        LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7152        return ret;
7153     }
7154
7155     GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
7156
7157     ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
7158
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
7165
7166     LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret);
7167     return ret;
7168 }
7169
7170 mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
7171 {
7172     mDNSs32 val = 0;
7173     // PrioritizeNetworkReachabilityOverSleep has been deprecated.
7174     // GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
7175     // Statically set the PrioritizeNetworkReachabilityOverSleep value to 1 for AppleTV
7176     if (IsAppleTV())
7177         val = 1;
7178     return val != 0 ? mDNStrue : mDNSfalse;
7179 }
7180
7181
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
7185 // the RR relay.
7186 //
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.
7192 //
7193 // Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
7194 // its presence shouldn't delay sleep.
7195 //
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.
7198 //
7199 // Also note that returning false here will not delay sleep past the maximum of 10 seconds.
7200 mDNSexport mDNSBool RecordReadyForSleep(AuthRecord *rr)
7201 {
7202     mDNS *const m = &mDNSStorage;
7203     if (!AuthRecord_uDNS(rr)) return mDNStrue;
7204     
7205     if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
7206     {
7207         LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7208         return mDNSfalse;
7209     }
7210     
7211     if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result))
7212     {
7213         if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone
7214             && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel"))
7215         {
7216             DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
7217             if (info && info->AutoTunnel)
7218             {
7219                 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7220                 return mDNSfalse;
7221             }
7222         }
7223     }
7224     
7225     return mDNStrue;
7226 }
7227
7228 // Caller must hold the lock
7229 mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
7230 {
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);
7238 }
7239
7240 #if !TARGET_OS_EMBEDDED
7241 mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname)
7242 {
7243     struct ifaddrs  *ifa;
7244     struct ifaddrs  *ifaddrs;
7245     mDNSAddr addr;
7246
7247     if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;}
7248
7249     if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;}
7250
7251     for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
7252     {
7253         if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
7254             continue;
7255         if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
7256             continue;
7257         if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
7258         {
7259             LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
7260             continue;
7261         }
7262         if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6))
7263         {
7264             LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr);
7265             break;
7266         }
7267     }
7268     freeifaddrs(ifaddrs);
7269     return ifa != NULL;
7270 }
7271
7272 mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf)
7273 {
7274     mDNSv6Addr retVal;
7275     struct addrinfo hints;
7276     struct addrinfo *res0;
7277
7278     memset(&hints, 0, sizeof(hints));
7279     hints.ai_family = AF_INET6;
7280     hints.ai_flags = AI_NUMERICHOST;
7281
7282     int err = getaddrinfo(buf, NULL, &hints, &res0);
7283     if (err)
7284         return zerov6Addr;
7285
7286     retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr;
7287
7288     freeaddrinfo(res0);
7289
7290     return retVal;
7291 }
7292
7293 mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict()
7294 {
7295     CFDictionaryRef connd = NULL;
7296     CFDictionaryRef BTMMDict = NULL;
7297
7298     connd = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BTMMConnectivity);
7299     if (!connd)
7300     {
7301         LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
7302         goto end;
7303     }
7304
7305     BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
7306     if (!BTMMDict)
7307     {
7308         LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
7309         goto end;
7310     }
7311
7312     // Non-dictionary is treated as non-existent dictionary
7313     if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
7314     {
7315         BTMMDict = NULL;
7316         LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
7317         goto end;
7318     }
7319
7320     CFRetain(BTMMDict);
7321
7322 end:
7323     if (connd) CFRelease(connd);
7324
7325     return BTMMDict;
7326 }
7327
7328 #define MAX_IPV6_TEXTUAL 40
7329
7330 mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey)
7331 {
7332     mDNSv6Addr retVal = zerov6Addr;
7333     CFTypeRef string = NULL;
7334     char ifname[IFNAMSIZ];
7335     char address[MAX_IPV6_TEXTUAL];
7336
7337     if (!BTMMDict)
7338         return zerov6Addr;
7339
7340     if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string))
7341     {
7342         LogInfo("ParseBackToMyMacAddr: interface key does not exist");
7343         return zerov6Addr;
7344     }
7345
7346     if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8))
7347     {
7348         LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
7349         return zerov6Addr;
7350     }
7351
7352     if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string))
7353     {
7354         LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
7355         return zerov6Addr;
7356     }
7357
7358     if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8))
7359     {
7360         LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
7361         return zerov6Addr;
7362     }
7363
7364     retVal = IPv6AddressFromString(address);
7365     LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal);
7366
7367     if (mDNSIPv6AddressIsZero(retVal))
7368         return zerov6Addr;
7369
7370     if (!IPv6AddressIsOnInterface(retVal, ifname))
7371     {
7372         LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname);
7373         return zerov6Addr;
7374     }
7375
7376     return retVal;
7377 }
7378
7379 mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict)
7380 {
7381     CFTypeRef zones = NULL;
7382
7383     if (!BTMMDict)
7384         return NULL;
7385
7386     if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones))
7387     {
7388         LogInfo("CopyBTMMZones: Zones key does not exist");
7389         return NULL;
7390     }
7391
7392     return zones;
7393 }
7394
7395 mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info)
7396 {
7397     mDNSv6Addr addr = zerov6Addr;
7398     char buffer[MAX_ESCAPED_DOMAIN_NAME];
7399     CFStringRef domain = NULL;
7400     CFTypeRef theZone = NULL;
7401
7402     if (!zones)
7403         return addr;
7404
7405     ConvertDomainNameToCString(&info->domain, buffer);
7406     domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
7407     if (!domain)
7408         return addr;
7409
7410     if (CFDictionaryGetValueIfPresent(zones, domain, &theZone))
7411         addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address"));
7412
7413     CFRelease(domain);
7414
7415     return addr;
7416 }
7417
7418 mDNSlocal void SetupBackToMyMacInnerAddresses(CFDictionaryRef BTMMDict)
7419 {
7420     mDNS *const m = &mDNSStorage;
7421     DomainAuthInfo* info;
7422     CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
7423     mDNSv6Addr newAddr;
7424
7425     for (info = m->AuthInfoList; info; info = info->next)
7426     {
7427         if (!info->AutoTunnel)
7428             continue;
7429
7430         newAddr = ParseBackToMyMacZone(zones, info);
7431
7432         if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress))
7433             continue;
7434
7435         info->AutoTunnelInnerAddress = newAddr;
7436         DeregisterAutoTunnelHostRecord(m, info);
7437         UpdateAutoTunnelHostRecord(m, info);
7438         UpdateAutoTunnelDomainStatus(info);
7439     }
7440 }
7441
7442 // MUST be called holding the lock
7443 mDNSlocal void ProcessConndConfigChanges(void)
7444 {
7445     mDNS *const m = &mDNSStorage;
7446     CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
7447     if (!dict)
7448         LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
7449     mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
7450
7451     LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
7452
7453     SetupBackToMyMacInnerAddresses(dict);
7454
7455     if (dict) CFRelease(dict);
7456
7457     if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr))
7458     {
7459         m->AutoTunnelRelayAddr = relayAddr;
7460
7461         DomainAuthInfo* info;
7462         for (info = m->AuthInfoList; info; info = info->next)
7463             if (info->AutoTunnel)
7464             {
7465                 DeregisterAutoTunnel6Record(m, info);
7466                 UpdateAutoTunnel6Record(m, info);
7467                 UpdateAutoTunnelDomainStatus(info);
7468             }
7469
7470         // Determine whether we need racoon to accept incoming connections
7471         UpdateAnonymousRacoonConfig(m);
7472     }
7473
7474     // If awacsd crashes or exits for some reason, restart it
7475     UpdateBTMMRelayConnection(m);
7476 }
7477 #endif // !TARGET_OS_EMBEDDED
7478 #endif /* APPLE_OSX_mDNSResponder */
7479
7480 mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
7481 {
7482     DNSServer *s;
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)
7485     {
7486         if (s->addr.ip.v4.b[0] == 17)
7487         {     
7488             LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s->domain.c, &s->addr);
7489             return mDNStrue;
7490         }     
7491     }
7492     return mDNSfalse;
7493 }
7494
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)
7498 {
7499     mDNS *const m = &mDNSStorage;
7500     mDNS_CheckLock(m);
7501     if (!m->NetworkChanged || m->NetworkChanged - NonZeroTime(m->timenow + delay) > 0)
7502     {
7503         m->NetworkChanged = NonZeroTime(m->timenow + delay);
7504         LogInfo("SetNetworkChanged: Scheduling in %d ticks", delay);
7505     }
7506     else
7507         LogInfo("SetNetworkChanged: *NOT* increasing delay from %d to %d", m->NetworkChanged - m->timenow, delay);
7508 }
7509
7510 // Called with KQueueLock & mDNS lock
7511 mDNSlocal void SetKeyChainTimer(mDNSs32 delay)
7512 {
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)
7516     {
7517         m->p->KeyChainTimer = NonZeroTime(m->timenow + delay);
7518         LogInfo("SetKeyChainTimer: %d", delay);
7519     }
7520 }
7521
7522 mDNSexport void mDNSMacOSXNetworkChanged(void)
7523 {
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
7529
7530     // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring
7531     int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
7532     if (InfoSocket > 0)
7533     {
7534         mDNSBool tentative = mDNSfalse;
7535         struct ifaddrs *ifa = myGetIfAddrs(1);
7536         while (ifa)
7537         {
7538             if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6)
7539             {
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)
7549                 {
7550                     if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
7551                     {
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
7555                         break;
7556                     }
7557                 }
7558             }
7559             ifa = ifa->ifa_next;
7560         }
7561         close(InfoSocket);
7562         if (tentative)
7563         {
7564             mDNS_Lock(m);
7565             SetNetworkChanged(mDNSPlatformOneSecond / 2);
7566             mDNS_Unlock(m);
7567             return;
7568         }
7569         LogInfo("***   Network Configuration Change   ***  No IPv6 address TENTATIVE, will continue");
7570     }
7571
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();
7580
7581 #if APPLE_OSX_mDNSResponder
7582 #if !TARGET_OS_EMBEDDED
7583     mDNS_Lock(m);
7584     ProcessConndConfigChanges();
7585     mDNS_Unlock(m);
7586
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
7589     ClientTunnel *p;
7590     for (p = m->TunnelClients; p; p = p->next)
7591         if (p->q.ThisQInterval < 0)
7592         {
7593             DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname);
7594             if (!info)
7595             {
7596                 LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c);
7597                 AutoTunnelSetKeys(p, mDNSfalse);
7598             }
7599             else
7600             {
7601                 mDNSv6Addr inner = info->AutoTunnelInnerAddress;
7602
7603                 if (!mDNSIPPortIsZero(p->rmt_outer_port))
7604                 {
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))
7611                     {
7612                         AutoTunnelSetKeys(p, mDNSfalse);
7613                         p->loc_inner = inner;
7614                         p->loc_outer = tmpSrc.ip.v4;
7615                         AutoTunnelSetKeys(p, mDNStrue);
7616                     }
7617                 }
7618                 else
7619                 {
7620                     if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7621                         !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
7622                     {
7623                         AutoTunnelSetKeys(p, mDNSfalse);
7624                         p->loc_inner = inner;
7625                         p->loc_outer6 = m->AutoTunnelRelayAddr;
7626                         AutoTunnelSetKeys(p, mDNStrue);
7627                     }
7628                 }
7629             }
7630         }
7631 #endif //!TARGET_OS_EMBEDDED
7632
7633     SetSPS(m);
7634
7635     NetworkInterfaceInfoOSX *i;
7636     for (i = m->p->InterfaceList; i; i = i->next)
7637     {
7638         if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
7639         {
7640             if (i->BPF_fd >= 0 && CountProxyTargets(i, mDNSNULL, mDNSNULL) == 0)
7641                 CloseBPF(i);
7642         }
7643         else // else, we're Sleep Proxy Server; open BPF fds
7644         {
7645             if (i->Exists && (i->Registered == i) && SPSInterface(i) && i->BPF_fd == -1)
7646             {
7647                 LogMsg("%s mDNSMacOSXNetworkChanged: requesting BPF", i->ifinfo.ifname);
7648                 i->BPF_fd = -2;
7649                 mDNSRequestBPF();
7650             }
7651         }
7652     }
7653
7654 #endif // APPLE_OSX_mDNSResponder
7655
7656     uDNS_SetupDNSConfig(m);
7657     mDNS_ConfigChanged(m);
7658
7659     if (IsAppleNetwork(m) != mDNS_McastTracingEnabled)
7660     {
7661         mDNS_McastTracingEnabled = mDNS_McastTracingEnabled ? mDNSfalse : mDNStrue; 
7662         LogInfo("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
7663         UpdateDebugState();
7664     }
7665
7666 }
7667
7668 // Copy the fourth slash-delimited element from either:
7669 //   State:/Network/Interface/<bsdname>/IPv4
7670 // or
7671 //   Setup:/Network/Service/<servicename>/Interface
7672 mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
7673 {
7674     CFArrayRef a;
7675     CFStringRef name = NULL;
7676
7677     a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
7678     if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
7679     if (a != NULL) CFRelease(a);
7680
7681     return name;
7682 }
7683
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)
7687 {
7688     CFDictionaryRef dict = NULL;
7689     CFMutableArrayRef a;
7690     const void **keys = NULL, **vals = NULL;
7691     CFStringRef pattern = NULL;
7692     int i, ic, j, jc;
7693     int found = 0;
7694
7695     jc = CFArrayGetCount(inkeys);
7696     if (!jc) goto done;
7697
7698     a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7699     if (a == NULL) goto done;
7700
7701     // Setup:/Network/Service/[^/]+/Interface
7702     pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
7703     if (pattern == NULL) goto done;
7704     CFArrayAppendValue(a, pattern);
7705     CFRelease(pattern);
7706
7707     // Setup:/Network/Service/[^/]+/IPv4
7708     pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
7709     if (pattern == NULL) goto done;
7710     CFArrayAppendValue(a, pattern);
7711     CFRelease(pattern);
7712
7713     dict = SCDynamicStoreCopyMultiple(NULL, NULL, a);
7714     CFRelease(a);
7715
7716     if (!dict)
7717     {
7718         LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
7719         goto done;
7720     }
7721
7722     ic = CFDictionaryGetCount(dict);
7723     vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7724     keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7725     CFDictionaryGetKeysAndValues(dict, keys, vals);
7726
7727     // For each key we were given...
7728     for (j = 0; j < jc; j++)
7729     {
7730         CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
7731         CFStringRef ifname = NULL;
7732
7733         char buf[256];
7734
7735         // It would be nice to use a regex here
7736         if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
7737
7738         if ((ifname = CopyNameFromKey(key)) == NULL) continue;
7739         if (mDNS_LoggingEnabled)
7740         {
7741             if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7742             LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
7743         }
7744
7745         // Loop over the interfaces to find matching the ifname, and see if that one has kSCValNetIPv4ConfigMethodLinkLocal
7746         for (i = 0; i < ic; i++)
7747         {
7748             CFDictionaryRef ipv4dict;
7749             CFStringRef name;
7750             CFStringRef serviceid;
7751             CFStringRef configmethod;
7752
7753             if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
7754
7755             if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
7756
7757             if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
7758
7759             if (!CFEqual(ifname, name)) continue;
7760
7761             if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
7762             if (mDNS_LoggingEnabled)
7763             {
7764                 if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7765                 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
7766             }
7767
7768             pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
7769             CFRelease(serviceid);
7770             if (pattern == NULL) continue;
7771
7772             ipv4dict = CFDictionaryGetValue(dict, pattern);
7773             CFRelease(pattern);
7774             if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
7775
7776             configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
7777             if (!configmethod) continue;
7778
7779             if (mDNS_LoggingEnabled)
7780             {
7781                 if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7782                 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
7783             }
7784
7785             if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found++; break; }
7786         }
7787
7788         CFRelease(ifname);
7789     }
7790
7791 done:
7792     if (vals != NULL) mDNSPlatformMemFree(vals);
7793     if (keys != NULL) mDNSPlatformMemFree(keys);
7794     if (dict != NULL) CFRelease(dict);
7795
7796     return found;
7797 }
7798
7799 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
7800 {
7801     (void)store;        // Parameter not used
7802     mDNS *const m = (mDNS *const)context;
7803     KQueueLock();
7804     mDNS_Lock(m);
7805
7806     //mDNSs32 delay = mDNSPlatformOneSecond * 2;                // Start off assuming a two-second delay
7807     const mDNSs32 delay = (mDNSPlatformOneSecond + 39) / 40;    // 25 ms delay
7808
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);
7817     int c_fast = 0;
7818     
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
7821     // hosted SSID.
7822     {
7823         CFArrayRef  labels;
7824         CFIndex     n;
7825         for (int i = 0; i < c; i++)
7826         {
7827             CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i);
7828
7829             // Only look at keys with prefix "State:/Network/Interface/"
7830             if (!CFStringHasPrefix(key, NetworkChangedKey_StateInterfacePrefix))
7831                 continue;
7832
7833             // And suffix "IPv6" or "IPv4".
7834             if (!CFStringHasSuffix(key, kSCEntNetIPv6) && !CFStringHasSuffix(key, kSCEntNetIPv4))
7835                 continue;
7836
7837             labels = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
7838             if (labels == NULL)
7839                 break;
7840             n = CFArrayGetCount(labels);
7841
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.
7845             if (n == 5)
7846             {
7847                 char buf[256];
7848
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)))
7852                 {
7853                     LogInfo("NetworkChanged: interface %s qualifies for reduced change handling delay", buf);
7854                     c_fast++;
7855                     CFRelease(labels);
7856                     break;
7857                 }
7858             }
7859             CFRelease(labels);
7860         }
7861     }
7862
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
7865
7866     if (mDNS_LoggingEnabled)
7867     {
7868         int i;
7869         for (i=0; i<c; i++)
7870         {
7871             char buf[256];
7872             if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7873             LogInfo("***   Network Configuration Change   *** SC key: %s", buf);
7874         }
7875         LogInfo("***   Network Configuration Change   *** %d change%s %s%s%s%s%s%s%sdelay %d%s",
7876                 c, c>1 ? "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) "  : "",
7884                 delay,
7885                 (c_ddns || c_btmm) ? " + SetKeyChainTimer" : "");
7886     }
7887
7888     SetNetworkChanged(delay);
7889
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);
7897
7898     // Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
7899
7900     mDNS_Unlock(m);
7901     KQueueUnlock("NetworkChanged");
7902 }
7903
7904 #if APPLE_OSX_mDNSResponder
7905 mDNSlocal void RefreshSPSStatus(const void *key, const void *value, void *context)
7906 {
7907     (void)context;
7908     char buf[IFNAMSIZ];
7909
7910     CFStringRef ifnameStr = (CFStringRef)key;
7911     CFArrayRef array = (CFArrayRef)value;
7912     if (!CFStringGetCString(ifnameStr, buf, sizeof(buf), kCFStringEncodingUTF8)) 
7913         buf[0] = 0;
7914
7915     LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf, CFArrayGetCount(array));
7916     mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, buf, value);
7917 }
7918 #endif
7919
7920 mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
7921 {
7922     mDNS *const m = (mDNS *const)info;
7923     (void)store;
7924
7925     KQueueLock();   // serialize with KQueueLoop()
7926
7927     LogInfo("DynamicStoreReconnected: Reconnected");
7928
7929     // State:/Network/MulticastDNS
7930     SetLocalDomains();
7931
7932     // State:/Network/DynamicDNS
7933     if (m->FQDN.c[0])
7934         mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
7935
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.
7939
7940     // State:/Network/PrivateDNS
7941     if (privateDnsArray)
7942         mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
7943
7944 #if APPLE_OSX_mDNSResponder
7945     // State:/Network/BackToMyMac
7946     UpdateAutoTunnelDomainStatuses(m);
7947
7948     // State:/Network/Interface/en0/SleepProxyServers
7949     if (spsStatusDict) 
7950         CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
7951 #endif
7952     KQueueUnlock("DynamicStoreReconnected");
7953 }
7954
7955 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
7956 {
7957     mStatus err = -1;
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);
7964
7965     if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
7966     if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
7967
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; }
7982
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; }
7986 #else
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);
7990 #endif
7991     SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected);
7992     m->p->Store = store;
7993     err = 0;
7994     goto exit;
7995
7996 error:
7997     if (store) CFRelease(store);
7998
7999 exit:
8000     if (patterns) CFRelease(patterns);
8001     if (pattern2) CFRelease(pattern2);
8002     if (pattern1) CFRelease(pattern1);
8003     if (keys) CFRelease(keys);
8004
8005     return(err);
8006 }
8007
8008 #if !TARGET_OS_EMBEDDED     // don't setup packet filter rules on embedded
8009
8010 mDNSlocal void mDNSSetPacketFilterRules(char * ifname, const ResourceRecord *const excludeRecord)
8011 {
8012     mDNS *const m = &mDNSStorage;
8013     AuthRecord  *rr;
8014     pfArray_t portArray;
8015     pfArray_t protocolArray;
8016     uint32_t count = 0;
8017
8018     for (rr = m->ResourceRecords; rr; rr=rr->next)
8019     {
8020         if ((rr->resrec.rrtype == kDNSServiceType_SRV) 
8021             && ((rr->ARType == AuthRecordAnyIncludeP2P) || (rr->ARType == AuthRecordAnyIncludeAWDLandP2P)))
8022         {
8023             const mDNSu8    *p;
8024
8025             if (count >= PFPortArraySize)
8026             {
8027                 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize, ARDisplayString(m, rr));
8028                 continue;
8029             }
8030
8031             if (excludeRecord && IdenticalResourceRecord(&rr->resrec, excludeRecord))
8032             {
8033                 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m, rr));
8034                 continue;
8035             }
8036
8037             LogMsg("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr));
8038
8039             portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger;
8040
8041             // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
8042             p = rr->resrec.name->c;
8043
8044             // Skip to App Protocol
8045             if (p[0])
8046                 p += 1 + p[0];
8047
8048             // Skip to Transport Protocol
8049             if (p[0])
8050                 p += 1 + p[0];
8051
8052             if      (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp"))
8053             {
8054                 protocolArray[count] = IPPROTO_TCP;
8055             }
8056             else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp"))
8057             {
8058                 protocolArray[count] = IPPROTO_UDP;
8059             }
8060             else
8061             {
8062                 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
8063                 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m, rr));
8064                 return;
8065             }
8066             count++;
8067         }
8068     }
8069     mDNSPacketFilterControl(PF_SET_RULES, ifname, count, portArray, protocolArray);
8070 }
8071
8072 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
8073 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8074 {
8075     mDNS *const m = &mDNSStorage;
8076
8077     NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
8078     while (intf)
8079     {
8080         if (strncmp(intf->ifname, "p2p", 3) == 0)
8081         {
8082             LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname);
8083             mDNSSetPacketFilterRules(intf->ifname, excludeRecord);
8084             break;
8085         }
8086         intf = GetFirstActiveInterface(intf->next);
8087     }
8088 }
8089
8090 #else // !TARGET_OS_EMBEDDED
8091
8092 // Currently no packet filter setup required on embedded platforms.
8093 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8094 {
8095     (void) excludeRecord; // unused
8096 }
8097
8098 #endif // !TARGET_OS_EMBEDDED
8099
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)
8102 {
8103     char        ifname[IFNAMSIZ];
8104     mDNSu32     interfaceIndex;
8105
8106     snprintf(ifname, IFNAMSIZ, "%s%d", ptr->if_name, ptr->if_unit);
8107     interfaceIndex  = if_nametoindex(ifname);
8108
8109     if (!interfaceIndex)
8110     {
8111         LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname);
8112         return;
8113     }
8114
8115     LogInfo("newMasterElected: KEV_DL_MASTER_ELECTED received on ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
8116 }
8117
8118 // An ssth array of all zeroes indicates the peer has no services registered.
8119 mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op)
8120 {
8121     int i;
8122     int *intp = (int *) op->ssth;
8123
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
8127     // is received.
8128     if (MAX_SSTH_SIZE % sizeof(int))
8129     {
8130         LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE);
8131         return mDNSfalse;
8132     }
8133
8134     for (i = 0; i < (int)(MAX_SSTH_SIZE / sizeof(int)); i++, intp++)
8135     {
8136         if (*intp)
8137             return mDNSfalse;
8138     }
8139     return mDNStrue;
8140 }
8141
8142 // Mark records from this peer for deletion from the cache.
8143 mDNSlocal void removeCachedPeerRecords(mDNSu32 ifindex, mDNSAddr *ap, bool purgeNow)
8144 {
8145     mDNS *const m = &mDNSStorage;
8146     mDNSu32     slot;
8147     CacheGroup  *cg;
8148     CacheRecord *cr;
8149     NetworkInterfaceInfoOSX *infoOSX;
8150     mDNSInterfaceID InterfaceID;
8151
8152     // Using mDNSPlatformInterfaceIDfromInterfaceIndex() would lead to recursive
8153     // locking issues, see: <rdar://problem/21332983>
8154     infoOSX = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
8155     if (!infoOSX)
8156     {
8157         LogInfo("removeCachedPeerRecords: interface %d not yet active", ifindex);
8158         return;
8159     }
8160     InterfaceID = infoOSX->ifinfo.InterfaceID;
8161
8162     FORALL_CACHERECORDS(slot, cg, cr)
8163     {
8164         if ((InterfaceID == cr->resrec.InterfaceID) && mDNSSameAddress(ap, & cr->sourceAddress))
8165         {
8166             LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
8167                  DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c);
8168
8169             if (purgeNow)
8170                 mDNS_PurgeCacheResourceRecord(m, cr);
8171             else
8172                 mDNS_Reconfirm_internal(m, cr, 0);  // use default minimum reconfirm time 
8173         }
8174     }
8175 }
8176
8177 // Handle KEV_DL_NODE_PRESENCE event.
8178 mDNSlocal void nodePresence(struct kev_dl_node_presence * p)
8179 {
8180     char buf[INET6_ADDRSTRLEN];
8181     struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info;
8182
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);
8185     else
8186         LogInfo("nodePresence:  inet_ntop() error");
8187  
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))
8191     {
8192         mDNSAddr    peerAddr;
8193
8194         peerAddr.type = mDNSAddrType_IPv6;
8195         peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8196
8197         LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer");
8198         removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, false);
8199     }
8200 }
8201
8202 // Handle KEV_DL_NODE_ABSENCE event.
8203 mDNSlocal void nodeAbsence(struct kev_dl_node_absence * p)
8204 {
8205     mDNSAddr    peerAddr;
8206     char buf[INET6_ADDRSTRLEN];
8207
8208     if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
8209         LogInfo("nodeAbsence:  IPv6 address: %s", buf);
8210     else
8211         LogInfo("nodeAbsence:  inet_ntop() error");
8212
8213     peerAddr.type = mDNSAddrType_IPv6;
8214     peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8215
8216     LogInfo("nodeAbsence: immediately purge cached records from this peer");
8217     removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, true);
8218 }
8219
8220 mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context, __unused mDNSBool encounteredEOF)
8221 {
8222     mDNS *const m = (mDNS *const)context;
8223
8224     mDNS_Lock(m);
8225
8226     struct { struct kern_event_msg k; char extra[256]; } msg;
8227     int bytes = recv(s1, &msg, sizeof(msg), 0);
8228     if (bytes < 0)
8229         LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
8230     else
8231     {
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"       :
8261                  "?");
8262
8263         if (msg.k.event_code == KEV_DL_NODE_PRESENCE)
8264             nodePresence((struct kev_dl_node_presence *) &msg.k.event_data);
8265
8266         if (msg.k.event_code == KEV_DL_NODE_ABSENCE)
8267             nodeAbsence((struct kev_dl_node_absence *) &msg.k.event_data);
8268
8269         if (msg.k.event_code == KEV_DL_MASTER_ELECTED)
8270             newMasterElected((struct net_event_data *) &msg.k.event_data);
8271
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.
8277
8278         if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
8279             SetNetworkChanged(mDNSPlatformOneSecond * 2);
8280
8281 #if !TARGET_OS_EMBEDDED     // don't setup packet filter rules on embedded
8282
8283         // For p2p interfaces, need to open the advertised service port in the firewall.
8284         if (msg.k.event_code == KEV_DL_IF_ATTACHED)
8285         {
8286             struct net_event_data   * p;
8287             p = (struct net_event_data *) &msg.k.event_data;
8288
8289             if (strncmp(p->if_name, "p2p", 3) == 0)
8290             {
8291                 char ifname[IFNAMSIZ];
8292                 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8293
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);
8295
8296                 mDNSSetPacketFilterRules(ifname, NULL);
8297             }
8298         }
8299
8300         // For p2p interfaces, need to clear the firewall rules on interface detach
8301         if (msg.k.event_code == KEV_DL_IF_DETACHED)
8302         {
8303             struct net_event_data   * p;
8304             p = (struct net_event_data *) &msg.k.event_data;
8305
8306             if (strncmp(p->if_name, "p2p", 3) == 0)
8307             {
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);
8311
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);
8313
8314                 mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
8315             }
8316         }
8317 #endif // !TARGET_OS_EMBEDDED
8318
8319     }
8320
8321     mDNS_Unlock(m);
8322 }
8323
8324 mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
8325 {
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); }
8329
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);
8332     if (err < 0)
8333     {
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);
8338     }
8339
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);
8344
8345     return(mStatus_NoError);
8346 }
8347
8348 #ifndef NO_SECURITYFRAMEWORK
8349 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
8350 {
8351     LogInfo("***   Keychain Changed   ***");
8352     mDNS *const m = (mDNS *const)context;
8353     SecKeychainRef skc;
8354     OSStatus err = SecKeychainCopyDefault(&skc);
8355     if (!err)
8356     {
8357         if (info->keychain == skc)
8358         {
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);
8361             if (!relevant)
8362             {
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);
8367                 if (!err)
8368                 {
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);
8373                 }
8374             }
8375             if (relevant)
8376             {
8377                 LogInfo("***   Keychain Changed   *** KeychainEvent=%d %s",
8378                         keychainEvent,
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
8383                 KQueueLock();
8384                 mDNS_Lock(m);
8385
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.
8389                 //
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.
8394                 //
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);
8398
8399                 mDNS_Unlock(m);
8400                 KQueueUnlock("KeychainChanged");
8401             }
8402         }
8403         CFRelease(skc);
8404     }
8405
8406     return 0;
8407 }
8408 #endif
8409
8410 mDNSlocal void PowerOn(mDNS *const m)
8411 {
8412     mDNSCoreMachineSleep(m, false);     // Will set m->SleepState = SleepState_Awake;
8413
8414     if (m->p->WakeAtUTC)
8415     {
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)
8419         {
8420             LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
8421         }
8422         else if (utc - m->p->WakeAtUTC > 30)
8423         {
8424             LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
8425         }
8426         else if (IsAppleTV())
8427         {
8428             LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC);
8429         }
8430         else
8431         {
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;
8434         }
8435     }
8436
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");
8441
8442 }
8443
8444 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
8445 {
8446     mDNS *const m = (mDNS *const)refcon;
8447     KQueueLock();
8448     (void)service;    // Parameter not used
8449     debugf("PowerChanged %X %lX", messageType, messageArgument);
8450
8451     // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8452     m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8453
8454     switch(messageType)
8455     {
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();
8460         break;
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);
8465         break;
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
8469         if (m->SleepState)
8470         {
8471             LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
8472             PowerOn(m);
8473         }
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
8477         mDNS_Lock(m);
8478         SetNetworkChanged(mDNSPlatformOneSecond * 2);
8479         mDNS_Unlock(m);
8480
8481         break;
8482     case kIOMessageSystemWillRestart:       LogSPS("PowerChanged kIOMessageSystemWillRestart     (no action)"); break;          // E0000310
8483     case kIOMessageSystemWillPowerOn:       LogSPS("PowerChanged kIOMessageSystemWillPowerOn");                                 // E0000320
8484
8485         // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
8486         if (m->SleepState != SleepState_Sleeping)
8487         {
8488             LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
8489             m->SleepState = SleepState_Sleeping;
8490             mDNSMacOSXNetworkChanged();
8491         }
8492         PowerOn(m);
8493         break;
8494     default:                                LogSPS("PowerChanged unknown message %X", messageType); break;
8495     }
8496
8497     if (messageType == kIOMessageSystemWillSleep)
8498         m->p->SleepCookie = (long)messageArgument;
8499     else if (messageType == kIOMessageCanSystemSleep)
8500         IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
8501
8502     KQueueUnlock("PowerChanged Sleep/Wake");
8503 }
8504
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)
8509 {
8510     mDNS *const m = (mDNS *const)refcon;
8511     KQueueLock();
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"    : "");
8519
8520     // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8521     m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8522
8523     if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
8524     {
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.
8529         if (m->SleepLimit)
8530         {
8531             LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8532             IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie);
8533             m->SleepLimit = 0;
8534         }
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)
8538         {
8539                         PowerOn(m);
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.
8542                         mDNS_Lock(m);
8543                         SetNetworkChanged(mDNSPlatformOneSecond * 2);
8544                         mDNS_Unlock(m);
8545         }
8546         IOPMConnectionAcknowledgeEvent(connection, token);
8547     }
8548     else
8549     {
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);
8553         //sleep(5);
8554         //mDNSMacOSXNetworkChanged(m);
8555         mDNSCoreMachineSleep(m, true);
8556         //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
8557         m->p->SleepCookie = token;
8558     }
8559
8560     KQueueUnlock("SnowLeopardPowerChanged Sleep/Wake");
8561 }
8562 #endif
8563
8564 #if COMPILER_LIKES_PRAGMA_MARK
8565 #pragma mark -
8566 #pragma mark - /etc/hosts support
8567 #endif
8568
8569 // Implementation Notes
8570 //
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
8574 //
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
8580 //    not a duplicate
8581 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
8582 //
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
8586
8587 #define ETCHOSTS_BUFSIZE    1024    // Buffer size to parse a single line in /etc/hosts
8588
8589 mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
8590 {
8591     (void)m;  // unused
8592     (void)rr;
8593     (void)result;
8594     if (result == mStatus_MemFree)
8595     {
8596         LogInfo("FreeEtcHosts: %s", ARDisplayString(m, rr));
8597         freeL("etchosts", rr);
8598     }
8599 }
8600
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)
8603 {
8604     AuthRecord *rr;
8605     mDNSu32 namehash;
8606     AuthGroup *ag;
8607     mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly;
8608     mDNSu16 rrtype;
8609
8610     if (!domain)
8611     {
8612         LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
8613         return mDNSfalse;
8614     }
8615     if (!sa && !cname)
8616     {
8617         LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
8618         return mDNSfalse;
8619     }
8620
8621     if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
8622     {
8623         LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa->sa_family);
8624         return mDNSfalse;
8625     }
8626
8627
8628     if (ifname)
8629     {
8630         mDNSu32 ifindex = if_nametoindex(ifname);
8631         if (!ifindex)
8632         {
8633             LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain->c, ifname);
8634             return mDNSfalse;
8635         }
8636         InterfaceID = (mDNSInterfaceID)(uintptr_t)ifindex;
8637     }
8638
8639     if (sa)
8640         rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA);
8641     else
8642         rrtype = kDNSType_CNAME;
8643
8644     // Check for duplicates. See whether we parsed an entry before like this ?
8645     namehash = DomainNameHashValue(domain);
8646     ag = AuthGroupForName(auth, namehash, domain);
8647     if (ag)
8648     {
8649         rr = ag->members;
8650         while (rr)
8651         {
8652             if (rr->resrec.rrtype == rrtype)
8653             {
8654                 if (rrtype == kDNSType_A)
8655                 {
8656                     mDNSv4Addr ip;
8657                     ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
8658                     if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip))
8659                     {
8660                         LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c);
8661                         return mDNSfalse;
8662                     }
8663                 }
8664                 else if (rrtype == kDNSType_AAAA)
8665                 {
8666                     mDNSv6Addr ip6;
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))
8672                     {
8673                         LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c);
8674                         return mDNSfalse;
8675                     }
8676                 }
8677                 else if (rrtype == kDNSType_CNAME)
8678                 {
8679                     if (SameDomainName(&rr->resrec.rdata->u.name, cname))
8680                     {
8681                         LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname->c, domain->c);
8682                         return mDNSfalse;
8683                     }
8684                 }
8685             }
8686             rr = rr->next;
8687         }
8688     }
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);
8694
8695     if (sa)
8696     {
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;
8700         else
8701         {
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];
8706         }
8707     }
8708     else
8709     {
8710         rr->resrec.rdlength = DomainNameLength(cname);
8711         rr->resrec.rdata->u.name.c[0] = 0;
8712         AssignDomainName(&rr->resrec.rdata->u.name, cname);
8713     }
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);
8718     return mDNStrue;
8719 }
8720
8721 mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **name)
8722 {
8723     int i;
8724
8725     *name = NULL;
8726     for (i = start; i < length; i++)
8727     {
8728         if (buffer[i] == '#')
8729             return -1;
8730         if (buffer[i] != ' ' && buffer[i] != ',' && buffer[i] != '\t')
8731         {
8732             *name = &buffer[i];
8733
8734             // Found the start of a name, find the end and null terminate
8735             for (i++; i < length; i++)
8736             {
8737                 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
8738                 {
8739                     buffer[i] = 0;
8740                     break;
8741                 }
8742             }
8743             return i;
8744         }
8745     }
8746     return -1;
8747 }
8748
8749 mDNSlocal void mDNSMacOSXParseEtcHostsLine(char *buffer, ssize_t length, AuthHash *auth)
8750 {
8751     int i;
8752     int ifStart = 0;
8753     char *ifname = NULL;
8754     domainname name1d;
8755     domainname name2d;
8756     char *name1;
8757     char *name2;
8758     int aliasIndex;
8759
8760     //Ignore leading whitespaces and tabs
8761     while (*buffer == ' ' || *buffer == '\t')
8762     {
8763         buffer++;
8764         length--;
8765     }
8766
8767     // Find the end of the address string
8768     for (i = 0; i < length; i++)
8769     {
8770         if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t' || buffer[i] == '%')
8771         {
8772             if (buffer[i] == '%')
8773                 ifStart = i + 1;
8774             buffer[i] = 0;
8775             break;
8776         }
8777     }
8778
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)
8785     {
8786         LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
8787         return;
8788     }
8789
8790     if (ifStart)
8791     {
8792         // Parse the interface
8793         ifname = &buffer[ifStart];
8794         for (i = ifStart + 1; i < length; i++)
8795         {
8796             if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
8797             {
8798                 buffer[i] = 0;
8799                 break;
8800             }
8801         }
8802     }
8803
8804     i = EtcHostsParseOneName(i + 1, length, buffer, &name1);
8805     if (i == length)
8806     {
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))
8809         {
8810             LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
8811             freeaddrinfo(gairesults);
8812             return;
8813         }
8814         mDNSMacOSXCreateEtcHostsEntry(&name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
8815     }
8816     else if (i != -1)
8817     {
8818         domainname first;
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.
8822         
8823         if (!MakeDomainNameFromDNSNameString(&first, name1))
8824         {
8825             LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
8826             freeaddrinfo(gairesults);
8827             return;
8828         }
8829         mDNSMacOSXCreateEtcHostsEntry(&first, gairesults->ai_addr, mDNSNULL, ifname, auth);
8830         
8831         // /etc/hosts alias discussion:
8832         //
8833         // If the /etc/hosts has an entry like this
8834         //
8835         //  ip_address cname [aliases...]
8836         //  1.2.3.4    sun    star    bright
8837         //
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")
8840         //
8841         // To achieve this, we need to add the entry like this:
8842         //
8843         // sun A 1.2.3.4
8844         // star CNAME sun
8845         // bright CNAME sun
8846         //
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.
8849         
8850         aliasIndex = 0;
8851         while (i < length)
8852         {
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
8856             
8857             i = EtcHostsParseOneName(i + 1, length, buffer, &name2);
8858             
8859             if (name2)
8860             {
8861                 if ((aliasIndex) && (*buffer == *name2))
8862                     break; // break out of the loop if we wrap around
8863                 
8864                 if (!MakeDomainNameFromDNSNameString(&name2d, name2))
8865                 {
8866                     LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2);
8867                     freeaddrinfo(gairesults);
8868                     return;
8869                 }
8870                 // Ignore if it points to itself
8871                 if (!SameDomainName(&first, &name2d))
8872                 {
8873                     if (!mDNSMacOSXCreateEtcHostsEntry(&name2d, mDNSNULL, &first, ifname, auth))
8874                     {
8875                         freeaddrinfo(gairesults);
8876                         return;
8877                     }
8878                 }
8879                 else
8880                 {
8881                     LogInfo("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names first %##s, name2 %##s", first.c, name2d.c);
8882                 }
8883                 aliasIndex++;
8884             }
8885             else if (!aliasIndex)
8886             {
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);
8890                 break;
8891             }
8892         }
8893     }
8894     freeaddrinfo(gairesults);
8895 }
8896
8897 mDNSlocal void mDNSMacOSXParseEtcHosts(int fd, AuthHash *auth)
8898 {
8899     mDNSBool good;
8900     char buf[ETCHOSTS_BUFSIZE];
8901     ssize_t len;
8902     FILE *fp;
8903
8904     if (fd == -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
8905
8906     fp = fopen("/etc/hosts", "r");
8907     if (!fp) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
8908
8909     while (1)
8910     {
8911         good = (fgets(buf, ETCHOSTS_BUFSIZE, fp) != NULL);
8912         if (!good) break;
8913
8914         // skip comment and empty lines
8915         if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n')
8916             continue;
8917
8918         len = strlen(buf);
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')
8922         {
8923             buf[len - 1] = '\0';
8924             len = len - 1;
8925         }
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.
8930         if (len)
8931         {
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')
8935             {
8936                 buf[len - 1] = '\0';
8937                 len = len - 1;
8938             }
8939         }
8940         if (!len) //Sanity Check: len should never be zero
8941         {
8942             LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
8943             continue;
8944         }
8945         mDNSMacOSXParseEtcHostsLine(buf, len, auth);
8946     }
8947     fclose(fp);
8948 }
8949
8950 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m);
8951
8952 mDNSlocal int mDNSMacOSXGetEtcHostsFD(void)
8953 {
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;
8960
8961     // First time through? just schedule ourselves on the main queue and we'll do the work later
8962     if (!etcq)
8963     {
8964         etcq = dispatch_get_main_queue();
8965         if (etcq)
8966         {
8967             // Do this work on the queue, not here - solves potential synchronization issues
8968             dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
8969         }
8970         return -1;
8971     }
8972
8973     if (hostssrc) return dispatch_source_get_handle(hostssrc);
8974 #endif
8975
8976     int fd = open("/etc/hosts", O_RDONLY);
8977
8978 #ifdef __DISPATCH_GROUP__
8979     // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
8980     if (fd == -1)
8981     {
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; }
8984
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);
8989         if (etcsrc == NULL)
8990         {
8991             close(fd);
8992             return -1;
8993         }
8994         dispatch_source_set_event_handler(etcsrc,
8995                                           ^{
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)
8999                                               {
9000                                                   dispatch_source_cancel(etcsrc);
9001                                                   dispatch_release(etcsrc);
9002                                                   etcsrc = NULL;
9003                                                   dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9004                                                   return;
9005                                               }
9006                                               if ((flags & DISPATCH_VNODE_WRITE) != 0 && hostssrc == NULL)
9007                                               {
9008                                                   mDNSMacOSXUpdateEtcHosts(m);
9009                                               }
9010                                           });
9011         dispatch_source_set_cancel_handler(etcsrc, ^{close(fd);});
9012         dispatch_resume(etcsrc);
9013
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; }
9017     }
9018
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)
9024     {
9025         close(fd);
9026         return -1;
9027     }
9028     dispatch_source_set_event_handler(hostssrc,
9029                                       ^{
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)
9033                                           {
9034                                               dispatch_source_cancel(hostssrc);
9035                                               dispatch_release(hostssrc);
9036                                               hostssrc = NULL;
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
9044                                               usleep(1000000);
9045                                               dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9046                                               return;
9047                                           }
9048                                           if ((flags & DISPATCH_VNODE_WRITE) != 0)
9049                                           {
9050                                               mDNSMacOSXUpdateEtcHosts(m);
9051                                           }
9052                                       });
9053     dispatch_source_set_cancel_handler(hostssrc, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd); close(fd);});
9054     dispatch_resume(hostssrc);
9055
9056     // Cleanup /etc source, no need to watch it if we already have /etc/hosts
9057     if (etcsrc)
9058     {
9059         dispatch_source_cancel(etcsrc);
9060         dispatch_release(etcsrc);
9061         etcsrc = NULL;
9062     }
9063
9064     LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
9065     return hostssrc ? (int)dispatch_source_get_handle(hostssrc) : -1;
9066 #else
9067     (void)m;
9068     return fd;
9069 #endif
9070 }
9071
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)
9075 {
9076     CacheRecord *cr;
9077     mDNSu32 slot;
9078     CacheGroup *cg;
9079
9080     FORALL_CACHERECORDS(slot, cg, cr)
9081     {
9082         // Skip multicast.
9083         if (cr->resrec.InterfaceID) continue;
9084
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))
9089         {
9090             LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr));
9091             mDNS_PurgeCacheResourceRecord(m, cr);
9092         }
9093     }
9094 }
9095
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)
9098 {
9099     mDNS *const m = &mDNSStorage;
9100     AuthGroup *ag;
9101     mDNSu32 slot;
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)
9105         {
9106             primary = NULL;
9107             for (rr = ag->members; rr; rr = rrnext)
9108             {
9109                 rrnext = rr->next;
9110                 AuthGroup *ag1;
9111                 AuthRecord *rr1;
9112                 mDNSBool found = mDNSfalse;
9113                 ag1 = AuthGroupForRecord(&m->rrauth, &rr->resrec);
9114                 if (ag1 && ag1->members)
9115                 {
9116                     if (!primary) primary = ag1->members;
9117                     rr1 = ag1->members;
9118                     while (rr1)
9119                     {
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))
9127                         {
9128                             LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
9129                             found = mDNStrue;
9130                             break;
9131                         }
9132                         rr1 = rr1->next;
9133                     }
9134                 }
9135                 if (!found)
9136                 {
9137                     if (justCheck)
9138                     {
9139                         LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m, rr));
9140                         return mDNStrue;
9141                     }
9142                     RemoveAuthRecord(m, newhosts, rr);
9143                     // if there is no primary, point to self
9144                     rr->RRSet = (primary ? primary : rr);
9145                     rr->next = NULL;
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));
9149                 }
9150             }
9151         }
9152     return mDNSfalse;
9153 }
9154
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)
9158 {
9159     mDNS *const m = &mDNSStorage;
9160     AuthGroup *ag;
9161     mDNSu32 slot;
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)
9166             {
9167                 mDNSBool found = mDNSfalse;
9168                 AuthGroup *ag1;
9169                 AuthRecord *rr1;
9170                 rrnext = rr->next;
9171                 if (rr->RecordCallback != FreeEtcHosts) continue;
9172                 ag1 = AuthGroupForRecord(newhosts, &rr->resrec);
9173                 if (ag1)
9174                 {
9175                     rr1 = ag1->members;
9176                     while (rr1)
9177                     {
9178                         if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9179                         {
9180                             LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m, rr));
9181                             found = mDNStrue;
9182                             break;
9183                         }
9184                         rr1 = rr1->next;
9185                     }
9186                 }
9187                 // there is no corresponding record in newhosts for the same name. This means
9188                 // we should delete this from the core.
9189                 if (!found)
9190                 {
9191                     if (justCheck)
9192                     {
9193                         LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m, rr));
9194                         return mDNStrue;
9195                     }
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)
9199                     {
9200                         AuthRecord *new_primary = rr->next;
9201                         AuthRecord *r = new_primary;
9202                         while (r)
9203                         {
9204                             if (r->RRSet == rr)
9205                             {
9206                                 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m, r));
9207                                 r->RRSet = new_primary;
9208                             }
9209                             else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m, r), r->resrec.name);
9210                             r = r->next;
9211                         }
9212                     }
9213                     LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m, rr));
9214                     mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
9215                 }
9216             }
9217     return mDNSfalse;
9218 }
9219
9220 mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context)
9221 {
9222     AuthHash *newhosts = (AuthHash *)context;
9223
9224     mDNS_CheckLock(m);
9225
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);
9230 }
9231
9232 mDNSlocal void FreeNewHosts(AuthHash *newhosts)
9233 {
9234     mDNSu32 slot;
9235     AuthGroup *ag, *agnext;
9236     AuthRecord *rr, *rrnext;
9237
9238     for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9239         for (ag = newhosts->rrauth_hash[slot]; ag; ag = agnext)
9240         {
9241             agnext = ag->next;
9242             for (rr = ag->members; rr; rr = rrnext)
9243             {
9244                 rrnext = rr->next;
9245                 freeL("etchosts", rr);
9246             }
9247             freeL("AuthGroups", ag);
9248         }
9249 }
9250
9251 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
9252 {
9253     AuthHash newhosts;
9254
9255     // As we will be modifying the core, we can only have one thread running at
9256     // any point in time.
9257     KQueueLock();
9258
9259     mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
9260
9261     // Get the file desecriptor (will trigger us to start watching for changes)
9262     int fd = mDNSMacOSXGetEtcHostsFD();
9263     if (fd != -1)
9264     {
9265         LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd);
9266         mDNSMacOSXParseEtcHosts(fd, &newhosts);
9267     }
9268     else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
9269
9270     // Optimization: Detect whether /etc/hosts changed or not.
9271     //
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.
9275     //
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
9278     //   do.
9279     //
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.
9284     mDNS_Lock(m);
9285     // Add the new entries to the core if not already present in the core
9286     if (!EtcHostsAddNewEntries(&newhosts, mDNStrue))
9287     {
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))
9291         {
9292             LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
9293             FreeNewHosts(&newhosts);
9294             mDNS_Unlock(m);
9295             KQueueUnlock("/etc/hosts changed");
9296             return;
9297         }
9298     }
9299
9300     // This will flush the cache, stop and start the query so that the queries
9301     // can look at the /etc/hosts again
9302     //
9303     // Notes:
9304     //
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.
9309     //
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
9316     // looks normal.
9317     mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts);
9318     FreeNewHosts(&newhosts);
9319     mDNS_Unlock(m);
9320     KQueueUnlock("/etc/hosts changed");
9321 }
9322
9323 #if COMPILER_LIKES_PRAGMA_MARK
9324 #pragma mark -
9325 #pragma mark - Initialization & Teardown
9326 #endif
9327
9328 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
9329 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
9330 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
9331 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
9332
9333 // Major version 13 is 10.9.x 
9334 mDNSexport void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
9335 {
9336     int major = 0, minor = 0;
9337     char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
9338     CFDictionaryRef vers = _CFCopySystemVersionDictionary();
9339     if (vers)
9340     {
9341         CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
9342         CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
9343         CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
9344         if (cfprodname) 
9345             CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
9346         if (cfprodvers) 
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);
9350         CFRelease(vers);
9351     }
9352     if (!major) 
9353     { 
9354         major = 13; 
9355         LogMsg("Note: No Major Build Version number found; assuming 13"); 
9356     }
9357     if (HINFO_SWstring) 
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);
9360
9361     // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
9362     if ((prodname[0] & 0xDF) == 'M') 
9363         OSXVers = major;
9364     else 
9365         iOSVers = major;
9366 }
9367
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)
9372 {
9373     int err = -1;
9374     int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
9375     if (s < 3)
9376         LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
9377     else
9378     {
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));
9384         close(s);
9385     }
9386
9387     if (err) LogMsg("No unicast UDP responses");
9388     else debugf("Unicast UDP responses okay");
9389     return(err == 0);
9390 }
9391
9392 mDNSlocal void CreatePTRRecord(const domainname *domain)
9393 {
9394     AuthRecord *rr;
9395     const domainname *pname = (domainname *)"\x9" "localhost";
9396
9397     rr= mallocL("localhosts", sizeof(*rr));
9398     if (rr == NULL) return;
9399     mDNSPlatformMemZero(rr, sizeof(*rr));
9400
9401     mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
9402     AssignDomainName(&rr->namestorage, domain);
9403
9404     rr->resrec.rdlength = DomainNameLength(pname);
9405     rr->resrec.rdata->u.name.c[0] = 0;
9406     AssignDomainName(&rr->resrec.rdata->u.name, pname);
9407
9408     rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
9409     SetNewRData(&rr->resrec, mDNSNULL, 0);  // Sets rr->rdatahash for us
9410     mDNS_Register(&mDNSStorage, rr);
9411 }
9412
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
9417 //
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)
9421 {
9422     char buffer[MAX_REVERSE_MAPPING_NAME];
9423     domainname name;
9424     int i;
9425     struct in6_addr addr;
9426     mDNSu8 *ptr = addr.__u6_addr.__u6_addr8;
9427
9428     if (inet_pton(AF_INET, "127.0.0.1", &addr) == 1)
9429     {
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);
9434     }
9435     else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET failed");
9436
9437     if (inet_pton(AF_INET6, "::1", &addr) == 1)
9438     {
9439         for (i = 0; i < 16; i++)
9440         {
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] = '.';
9446         }
9447         mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
9448         MakeDomainNameFromDNSNameString(&name, buffer);
9449         CreatePTRRecord(&name);
9450     }
9451     else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET6 failed");
9452 }
9453
9454 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
9455 mDNSlocal void setSameDomainLabelPointer(void);
9456 #endif
9457
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)
9467
9468 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
9469 {
9470     mStatus err;
9471
9472     char HINFO_SWstring[256] = "";
9473     mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
9474
9475 #if APPLE_OSX_mDNSResponder
9476     setSameDomainLabelPointer();
9477 #endif
9478
9479     err = mDNSHelperInit();
9480     if (err)
9481         return err;
9482     
9483     // Store mDNSResponder Platform 
9484     if (OSXVers)
9485     {
9486         m->mDNS_plat = platform_OSX;
9487     }
9488     else if (iOSVers)
9489     {
9490         if (IsAppleTV())
9491             m->mDNS_plat = platform_Atv;
9492         else
9493             m->mDNS_plat = platform_iOS;
9494     }
9495     else
9496     {
9497         m->mDNS_plat = platform_NonApple; 
9498     }   
9499         
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.
9502     int i;
9503     for (i=0; i<100; i++)
9504     {
9505         domainlabel testlabel;
9506         testlabel.c[0] = 0;
9507         GetUserSpecifiedLocalHostName(&testlabel);
9508         if (testlabel.c[0]) break;
9509         usleep(50000);
9510     }
9511
9512     m->hostlabel.c[0]        = 0;
9513
9514     int get_model[2] = { CTL_HW, HW_MODEL };
9515     size_t len_model = sizeof(HINFO_HWstring_buffer);
9516
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;
9524
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);
9528
9529     if (mDNSPlatformInit_CanReceiveUnicast()) 
9530         m->CanReceiveUnicastOn5353 = mDNStrue;
9531
9532     mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
9533     mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
9534     if (hlen + slen < 254)
9535     {
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);
9540     }
9541
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";
9552
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));
9557
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));
9562     else 
9563         m->UnicastPort4.NotAnInteger = s4.sin_port;
9564
9565     if (m->p->permanentsockets.sktv6 >= 0)
9566     {
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;
9571     }
9572
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;
9590
9591     m->AutoTunnelRelayAddr = zerov6Addr;
9592
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); }
9601
9602     err = WatchForNetworkChanges(m);
9603     if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
9604
9605     err = WatchForSysEvents(m);
9606     if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
9607
9608     mDNSs32 utc = mDNSPlatformUTC();
9609     m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
9610     myGetIfAddrs(1);
9611     UpdateInterfaceList(utc);
9612     SetupActiveInterfaces(utc);
9613     ReorderInterfaceList();
9614
9615     // Explicitly ensure that our Keychain operations utilize the system domain.
9616 #ifndef NO_SECURITYFRAMEWORK
9617     SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
9618 #endif
9619
9620     mDNS_Lock(m);
9621     SetDomainSecrets(m);
9622     SetLocalDomains();
9623     mDNS_Unlock(m);
9624
9625 #ifndef NO_SECURITYFRAMEWORK
9626     err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
9627     if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
9628 #endif
9629
9630 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
9631     LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
9632 #else
9633     IOPMConnection c;
9634     IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
9635     if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
9636     else
9637     {
9638         iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
9639         if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
9640         else
9641         {
9642 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9643             IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue());
9644             LogInfo("IOPMConnectionSetDispatchQueue is now running");
9645 #else
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 */
9650         }
9651     }
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
9655     {
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); }
9658         else
9659         {
9660 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9661             IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
9662 #else
9663             CFRunLoopAddSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
9664 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9665         }
9666     }
9667
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
9687
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);
9692 #else
9693     SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
9694 #endif
9695     if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
9696
9697     mDNSMacOSXUpdateEtcHosts(m);
9698     SetupLocalHostRecords();
9699
9700     return(mStatus_NoError);
9701 }
9702
9703 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
9704 {
9705 #if MDNS_NO_DNSINFO
9706     LogMsg("Note: Compiled without Apple-specific Split-DNS support");
9707 #endif
9708
9709     // Adding interfaces will use this flag, so set it now.
9710     m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
9711
9712 #if APPLE_OSX_mDNSResponder
9713     m->SPSBrowseCallback = UpdateSPSStatus;
9714 #endif // APPLE_OSX_mDNSResponder
9715
9716     mStatus result = mDNSPlatformInit_setup(m);
9717
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)
9721     {
9722         mDNSCoreInitComplete(m, mStatus_NoError);
9723         initializeD2DPlugins(m);
9724     }
9725     result = DNSSECCryptoInit(m);
9726     return(result);
9727 }
9728
9729 mDNSexport void mDNSPlatformClose(mDNS *const m)
9730 {
9731     if (m->p->PowerConnection)
9732     {
9733 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9734         IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);
9735 #else
9736         CFRunLoopRemoveSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
9737 #endif
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;
9744     }
9745
9746     if (m->p->Store)
9747     {
9748 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9749         if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
9750             LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
9751 #else
9752         CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode);
9753         CFRunLoopSourceInvalidate(m->p->StoreRLS);
9754         CFRelease(m->p->StoreRLS);
9755         m->p->StoreRLS = NULL;
9756 #endif
9757         CFRelease(m->p->Store);
9758         m->p->Store    = NULL;
9759     }
9760
9761     if (m->p->PMRLS)
9762     {
9763         CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->PMRLS, kCFRunLoopDefaultMode);
9764         CFRunLoopSourceInvalidate(m->p->PMRLS);
9765         CFRelease(m->p->PMRLS);
9766         m->p->PMRLS = NULL;
9767     }
9768
9769     if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
9770
9771     terminateD2DPlugins();
9772
9773     mDNSs32 utc = mDNSPlatformUTC();
9774     MarkAllInterfacesInactive(utc);
9775     ClearInactiveInterfaces(utc);
9776     CloseSocketSet(&m->p->permanentsockets);
9777
9778 #if APPLE_OSX_mDNSResponder
9779     // clean up tunnels
9780     while (m->TunnelClients)
9781     {
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);
9788     }
9789
9790     if (AnonymousRacoonConfig)
9791     {
9792         AnonymousRacoonConfig = mDNSNULL;
9793         LogInfo("mDNSPlatformClose: Deconfiguring autotunnel need not be done in mDNSResponder");
9794     }
9795 #endif // APPLE_OSX_mDNSResponder
9796 }
9797
9798 #if COMPILER_LIKES_PRAGMA_MARK
9799 #pragma mark -
9800 #pragma mark - General Platform Support Layer functions
9801 #endif
9802
9803 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
9804 {
9805     return(arc4random());
9806 }
9807
9808 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
9809 mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
9810
9811 mDNSexport mStatus mDNSPlatformTimeInit(void)
9812 {
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
9821     //
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;
9834     return(result);
9835 }
9836
9837 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
9838 {
9839     if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
9840
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)
9845     {
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”.");
9856     }
9857     last_mach_absolute_time = this_mach_absolute_time;
9858
9859     return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
9860 }
9861
9862 mDNSexport mDNSs32 mDNSPlatformUTC(void)
9863 {
9864     return time(NULL);
9865 }
9866
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 *))
9878 {
9879     return (qsort(base, nel, width, compar));
9880 }
9881 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
9882 mDNSexport void *   mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
9883 #endif
9884 mDNSexport void     mDNSPlatformMemFree    (void *mem)   { freeL("mDNSPlatformMemFree", mem); }
9885
9886 mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason)
9887 {
9888     mDNS *const m = &mDNSStorage;
9889     if (allowSleep && m->p->IOPMAssertion)
9890     {
9891         LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
9892         IOPMAssertionRelease(m->p->IOPMAssertion);
9893         m->p->IOPMAssertion = 0;
9894     }
9895     else if (!allowSleep)
9896     {
9897 #ifdef kIOPMAssertionTypeNoIdleSleep
9898         if (m->p->IOPMAssertion)
9899         {
9900             IOPMAssertionRelease(m->p->IOPMAssertion);
9901             m->p->IOPMAssertion = 0;
9902         }
9903
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__);
9908 #endif
9909     }
9910 }
9911
9912 mDNSexport void mDNSPlatformPreventSleep(mDNSu32 timeout, const char *reason)
9913 {
9914         mDNS *const m = &mDNSStorage;
9915     if (m->p->IOPMAssertion)
9916         {
9917                 LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout, reason);
9918         return;
9919         }
9920 #ifdef kIOPMAssertionTypeNoIdleSleep
9921
9922 #if TARGET_OS_EMBEDDED
9923     if (!IsAppleTV())
9924         return; // No need for maintenance wakes on non-AppleTV embedded devices.
9925 #endif
9926
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);
9933     if (IsAppleTV())
9934         CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertPreventUserIdleSystemSleep);
9935     else
9936         CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertMaintenanceActivity);
9937
9938     CFDictionarySetValue(assertionProperties, kIOPMAssertionTimeoutKey, Timeout_num);
9939     CFDictionarySetValue(assertionProperties, kIOPMAssertionNameKey,    str);
9940
9941     IOPMAssertionCreateWithProperties(assertionProperties, (IOPMAssertionID *)&m->p->IOPMAssertion);
9942     CFRelease(str);
9943     CFRelease(Timeout_num);
9944     CFRelease(assertionProperties);
9945     LogSPS("Got an idle sleep assertion for %d seconds for %s", timeout, reason);
9946 #endif
9947 }
9948
9949 mDNSexport void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
9950 {
9951     mDNSu32 ifindex;
9952
9953     // Sanity check
9954     ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, InterfaceID, mDNStrue);
9955     if (ifindex <= 0)
9956     {
9957         LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
9958         return;
9959     }
9960     mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration);
9961 }
9962
9963 mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
9964 {
9965     NetworkInterfaceInfoOSX *info;
9966
9967     if (InterfaceID == mDNSInterface_P2P)
9968         return mDNStrue;
9969
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)
9973         return mDNSfalse;
9974
9975     if (   (InterfaceID == mDNSInterface_Any) 
9976         || (InterfaceID == mDNSInterfaceMark)
9977         || (InterfaceID == mDNSInterface_LocalOnly)
9978         || (InterfaceID == mDNSInterface_Unicast))
9979         return mDNSfalse;
9980
9981     // Compare to cached AWDL interface ID.
9982     if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
9983         return mDNStrue;
9984
9985     info = IfindexToInterfaceInfoOSX(InterfaceID);
9986     if (info == NULL)
9987     {
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);
9990         return mDNSfalse;
9991     }
9992
9993     return (mDNSBool) info->D2DInterface;
9994 }
9995
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)
9999 {
10000     // For an explicit match to a valid interface ID, return true. 
10001     if (rr->resrec.InterfaceID == InterfaceID)
10002         return mDNStrue;
10003
10004     // Only filtering records for D2D type interfaces, return true for all other interface types.
10005     if (!mDNSPlatformInterfaceIsD2D(InterfaceID))
10006         return mDNStrue;
10007     
10008     // If it's an AWDL interface the record must be explicitly marked to include AWDL.
10009     if (InterfaceID == AWDLInterfaceID)
10010     {
10011         if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10012             return mDNStrue;
10013         else
10014             return mDNSfalse;
10015     }
10016     
10017     // Send record if it is explicitly marked to include all other P2P type interfaces.
10018     if (rr->ARType == AuthRecordAnyIncludeP2P || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10019         return mDNStrue;
10020
10021     // Don't send the record over this interface.
10022     return mDNSfalse;
10023 }
10024
10025 // Filter questions send over P2P (D2D) type interfaces.
10026 mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
10027 {
10028     // For an explicit match to a valid interface ID, return true. 
10029     if (q->InterfaceID == intf->InterfaceID)
10030         return mDNStrue;
10031
10032     // Only filtering questions for D2D type interfaces
10033     if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
10034         return mDNStrue;
10035
10036     // If it's an AWDL interface the question must be explicitly marked to include AWDL.
10037     if (intf->InterfaceID == AWDLInterfaceID)
10038     {
10039         if (q->flags & kDNSServiceFlagsIncludeAWDL)
10040             return mDNStrue;
10041         else
10042             return mDNSfalse;
10043     }
10044     
10045     // Sent question if it is explicitly marked to include all other P2P type interfaces.
10046     if (q->flags & kDNSServiceFlagsIncludeP2P)
10047         return mDNStrue;
10048
10049     // Don't send the question over this interface.
10050     return mDNSfalse;
10051 }
10052
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)
10057 {
10058     if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID))
10059         return mDNStrue;
10060
10061     if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL))
10062         return mDNSfalse;
10063
10064     return mDNStrue;
10065 }
10066
10067 // formating time to RFC 4034 format
10068 mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
10069 {
10070     struct tm tmTime;
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);
10076 }
10077
10078 mDNSexport mDNSs32 mDNSPlatformGetPID()
10079 {
10080     return getpid();
10081 }
10082
10083 // Schedule a function asynchronously on the main queue
10084 mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func)
10085 {
10086     // KQueueLock/Unlock is used for two purposes
10087     //
10088     // 1. We can't be running along with the KQueue thread and hence acquiring the lock
10089     //    serializes the access to the "core"
10090     //
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(), ^{
10096         KQueueLock();
10097         func(m, context);
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();
10103 #endif
10104     });
10105 }
10106
10107 // definitions for device-info record construction
10108 #define DEVINFO_MODEL       "model="
10109 #define DEVINFO_MODEL_LEN   sizeof_string(DEVINFO_MODEL)
10110
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
10114
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'
10118
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))
10122
10123 mDNSlocal mDNSu8 getModelIconColors(char *color)
10124 {
10125         mDNSPlatformMemZero(color, MODEL_RGB_VALUE_LEN + 1);
10126
10127 #if !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10128         mDNSu8   red      = 0;
10129         mDNSu8   green    = 0;
10130         mDNSu8   blue     = 0;
10131
10132         IOReturn rGetDeviceColor = IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey,
10133                                                                                                                 &red, &green, &blue);
10134         if (kIOReturnSuccess == rGetDeviceColor)
10135         {
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);
10138         }
10139 #endif // !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10140
10141         return 0;
10142 }
10143
10144
10145 // Initialize device-info TXT record contents and return total length of record data.
10146 mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
10147 {
10148     mDNSu8 *bufferStart = ptr;
10149     mDNSu8 len = m->HIHardware.c[0] < MAX_MODEL_NAME_LEN ? m->HIHardware.c[0] : MAX_MODEL_NAME_LEN;
10150
10151     *ptr = DEVINFO_MODEL_LEN + len; // total length of DEVINFO_MODEL string plus the hardware name string
10152     ptr++;
10153     mDNSPlatformMemCopy(ptr, DEVINFO_MODEL, DEVINFO_MODEL_LEN);
10154     ptr += DEVINFO_MODEL_LEN;
10155     mDNSPlatformMemCopy(ptr, m->HIHardware.c + 1, len);
10156     ptr += len;
10157
10158     // only include this string for OSX
10159     if (OSXVers)
10160     {
10161         char    ver_num[VER_NUM_LEN + 1]; // version digits + null written by snprintf
10162         *ptr = OSX_VER_LEN + VER_NUM_LEN; // length byte
10163         ptr++;
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;
10171
10172                 char rgb[MODEL_RGB_VALUE_LEN + 1]; // RGB value + null written by snprintf
10173                 len = getModelIconColors(rgb);
10174                 if (len)
10175                 {
10176                         *ptr = MODEL_COLOR_LEN + len; // length byte
10177                         ptr++;
10178
10179                         mDNSPlatformMemCopy(ptr, MODEL_COLOR, MODEL_COLOR_LEN);
10180                         ptr += MODEL_COLOR_LEN;
10181
10182                         mDNSPlatformMemCopy(ptr, rgb, len);
10183                         ptr += len;
10184                 }
10185     }
10186
10187     return (ptr - bufferStart);
10188 }
10189
10190 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
10191
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;
10196
10197 #include <System/machine/cpu_capabilities.h>
10198 #define _cpu_capabilities   ((uint32_t*) _COMM_PAGE_CPU_CAPABILITIES)[0]
10199
10200 #if TARGET_OS_EMBEDDED
10201
10202 #include <arm_neon.h>
10203
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
10223 };
10224
10225 // Neon version
10226 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10227 {
10228     const int len = *a++;
10229     
10230     if (len > MAX_DOMAIN_LABEL)
10231     {
10232         fprintf(stderr, "v: Malformed label (too long)\n");
10233         return(mDNSfalse);
10234     }
10235     
10236     if (len != *b++)
10237     {
10238         return(mDNSfalse);
10239     }
10240     
10241     uint32_t len_count = len;
10242     
10243     uint8x16_t vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
10244     
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;
10251     uint32_t sum;
10252 #endif
10253     
10254     while(len_count > 15)
10255     {
10256         vA = vld1q_u8(a);
10257         vB = vld1q_u8(b);
10258         a += 16;
10259         b += 16;
10260         
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.
10266         
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.
10272         
10273         //Compare vA & vB
10274         vA = vceqq_u8(vA, vB);
10275         
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)
10280         {
10281             return(mDNSfalse);
10282             
10283         }
10284 #else
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);
10292         
10293         //0x0001fffe + 0x0001fffe + 0x0001fffe + 0x0001fffe = 0x0007fff8U when all same.
10294         if(sum != 0x0007fff8U)
10295         {
10296             return(mDNSfalse);
10297         }
10298 #endif
10299         
10300         len_count -= 16;
10301     }
10302     
10303     uint8x8_t vAd, vBd, vARotatedd, vBRotatedd, vMaskAd, vMaskBd;
10304     
10305     uint8x8_t v32d = vdup_n_u8(32);
10306     uint8x8_t v37d = vdup_n_u8(37);
10307     uint8x8_t v101d = vdup_n_u8(101);
10308     
10309     while(len_count > 7)
10310     {
10311         vAd = vld1_u8(a);
10312         vBd = vld1_u8(b);
10313         a += 8;
10314         b += 8;
10315         
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.
10321         
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.
10327         
10328         //Compare vA & vB
10329         vAd = vceq_u8(vAd, vBd);
10330         
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)
10335         {
10336             return(mDNSfalse);
10337             
10338         }
10339 #else
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);
10346         
10347         //0x0001fffe + 0x0001fffe = 0x0003fffc when all same.
10348         if(sum != 0x0003fffcU)
10349         {
10350             return(mDNSfalse);
10351         }
10352 #endif
10353         
10354         len_count -= 8;
10355     }
10356     
10357     while(len_count > 0)
10358     {
10359         mDNSu8 ac = *a++;
10360         mDNSu8 bc = *b++;
10361         
10362         ac += upper_to_lower_case_table[ac];
10363         bc += upper_to_lower_case_table[bc];
10364         
10365         if (ac != bc)
10366         {
10367             return(mDNSfalse);
10368         }
10369         
10370         len_count -= 1;
10371     }
10372     return(mDNStrue);
10373 }
10374
10375 // Use vectorized implementation if it is supported on this platform.
10376 mDNSlocal void setSameDomainLabelPointer(void)
10377 {
10378     if(_cpu_capabilities & kHasNeon)
10379     {
10380         // Use Neon Code
10381         SameDomainLabelPointer = vectorSameDomainLabel;
10382         LogMsg("setSameDomainLabelPointer: using vector code");
10383     }
10384     else
10385         LogMsg("setSameDomainLabelPointer: using scalar code");
10386 }
10387
10388 #else   // TARGET_OS_EMBEDDED
10389
10390 #include <smmintrin.h>
10391
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
10411 };
10412
10413 // SSE2 version
10414 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10415 {
10416     const int len = *a++;
10417     
10418     if (len > MAX_DOMAIN_LABEL)
10419     {
10420         fprintf(stderr, "v: Malformed label (too long)\n");
10421         return(mDNSfalse);
10422     }
10423     
10424     if (len != *b++)
10425     {
10426         return(mDNSfalse);
10427     }
10428     
10429     uint32_t len_count = len;
10430     
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);
10437     
10438     uint32_t is_equal;
10439     __m128i vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
10440     
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)
10445     {
10446         vA = _mm_loadu_si128((__m128i*)a);
10447         vB = _mm_loadu_si128((__m128i*)b);
10448         a += 16;
10449         b += 16;
10450         
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.
10456         
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.
10462         
10463         //Compare vA & vB
10464         vA = _mm_cmpeq_epi8(vA, vB);
10465         
10466         //Return if any different.
10467         is_equal = _mm_movemask_epi8(vA);
10468         is_equal = is_equal & 0xffff;                 
10469         if(is_equal != 0xffff)
10470         {
10471             return(mDNSfalse);
10472         }
10473         
10474         len_count -= 16;
10475     }
10476     
10477     while(len_count > 0)
10478     {
10479         mDNSu8 ac = *a++;
10480         mDNSu8 bc = *b++;
10481         
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];
10486         
10487         //Return if a & b are different.
10488         if (ac != bc)
10489         {
10490             return(mDNSfalse);
10491         }
10492         
10493         len_count -= 1;
10494     }
10495     return(mDNStrue);
10496 }
10497
10498 // Use vectorized implementation if it is supported on this platform.
10499 mDNSlocal void setSameDomainLabelPointer(void)
10500 {
10501     if(_cpu_capabilities & kHasSSE4_1)
10502     {
10503         // Use SSE Code
10504         SameDomainLabelPointer = vectorSameDomainLabel;
10505         LogMsg("setSameDomainLabelPointer: using vector code");
10506     }
10507     else
10508         LogMsg("setSameDomainLabelPointer: using scalar code");
10509 }
10510
10511 #endif  // TARGET_OS_EMBEDDED
10512
10513 // Original SameDomainLabel() implementation.
10514 mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10515 {
10516     int i;
10517     const int len = *a++;
10518
10519     if (len > MAX_DOMAIN_LABEL)
10520     { debugf("Malformed label (too long)"); return(mDNSfalse); }
10521
10522     if (len != *b++) return(mDNSfalse);
10523     for (i=0; i<len; i++)
10524     {
10525         mDNSu8 ac = *a++;
10526         mDNSu8 bc = *b++;
10527         if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
10528         if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
10529         if (ac != bc) return(mDNSfalse);
10530     }
10531     return(mDNStrue);
10532 }
10533
10534 mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10535 {
10536     return (*SameDomainLabelPointer)(a, b);
10537 }
10538
10539 #endif // APPLE_OSX_mDNSResponder
10540
10541
10542 #ifdef UNIT_TEST
10543 #include "../unittests/mdns_macosx_ut.c"
10544 #endif
10545