]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mDNSMacOSX.c
mDNSResponder-878.70.2.tar.gz
[apple/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