]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mDNSMacOSX.c
mDNSResponder-878.270.2.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / mDNSMacOSX.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2018 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 #include <MobileWiFi/WiFiManagerClient.h> // For WiFiManagerClientRef etc, declarations.
90 #include <dlfcn.h>
91 #include <os/variant_private.h> // For os_variant_has_internal_diagnostics().
92 #endif // TARGET_OS_IPHONE
93
94 // Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
95 #include <Kernel/IOKit/apple80211/apple80211_var.h>
96
97 #if MDNSRESPONDER_BTMM_SUPPORT
98 #include <AWACS.h>
99 #endif
100
101 #if APPLE_OSX_mDNSResponder
102 #include <ne_session.h> // for ne_session_set_socket_attributes()
103 #endif
104
105 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
106 #include <IOKit/platform/IOPlatformSupportPrivate.h>
107 #endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
108
109 #ifdef UNIT_TEST
110 #include "unittest.h"
111 #endif
112
113 #define kInterfaceSpecificOption "interface="
114
115 #define mDNS_IOREG_KEY "mDNS_KEY"
116 #define mDNS_IOREG_VALUE "2009-07-30"
117 #define mDNS_IOREG_KA_KEY "mDNS_Keepalive"
118 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
119
120 #define DARK_WAKE_TIME 16 // Time we hold an idle sleep assertion for maintenance after a wake notification
121
122 // cache the InterfaceID of the AWDL interface
123 mDNSInterfaceID AWDLInterfaceID;
124
125 // ***************************************************************************
126 // Globals
127
128 #if COMPILER_LIKES_PRAGMA_MARK
129 #pragma mark - Globals
130 #endif
131
132 // By default we don't offer sleep proxy service
133 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
134 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
135 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
136 mDNSexport int OfferSleepProxyService = 0;
137 mDNSexport int DisableSleepProxyClient = 0;
138 mDNSexport int UseInternalSleepProxy = 1; // Set to non-zero to use internal (in-NIC) Sleep Proxy
139
140 mDNSexport int OSXVers, iOSVers;
141 mDNSexport int KQueueFD;
142
143 #ifndef NO_SECURITYFRAMEWORK
144 static CFArrayRef ServerCerts;
145 OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
146 #endif /* NO_SECURITYFRAMEWORK */
147
148 static CFStringRef NetworkChangedKey_IPv4;
149 static CFStringRef NetworkChangedKey_IPv6;
150 static CFStringRef NetworkChangedKey_Hostnames;
151 static CFStringRef NetworkChangedKey_Computername;
152 static CFStringRef NetworkChangedKey_DNS;
153 static CFStringRef NetworkChangedKey_StateInterfacePrefix;
154 static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
155 static CFStringRef NetworkChangedKey_PowerSettings = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
156 #if MDNSRESPONDER_BTMM_SUPPORT
157 static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
158 static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity");
159 #endif
160
161 static char HINFO_HWstring_buffer[32];
162 static char *HINFO_HWstring = "Device";
163 static int HINFO_HWstring_prefixlen = 6;
164
165 mDNSexport int WatchDogReportingThreshold = 250;
166
167 dispatch_queue_t SSLqueue;
168
169 #if TARGET_OS_EMBEDDED
170 #define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
171 #endif
172
173 #if APPLE_OSX_mDNSResponder
174 static mDNSu8 SPMetricPortability = 99;
175 static mDNSu8 SPMetricMarginalPower = 99;
176 static mDNSu8 SPMetricTotalPower = 99;
177 static mDNSu8 SPMetricFeatures = 1; /* The current version supports TCP Keep Alive Feature */
178 mDNSexport domainname ActiveDirectoryPrimaryDomain;
179 mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
180 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
181 #endif // APPLE_OSX_mDNSResponder
182
183 // Don't send triggers too often. We arbitrarily limit it to three minutes.
184 #define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
185
186 // Used by AutoTunnel
187 const char btmmprefix[] = "btmmdns:";
188 const char dnsprefix[] = "dns:";
189
190 // String Array used to write list of private domains to Dynamic Store
191 static CFArrayRef privateDnsArray = NULL;
192
193 // ***************************************************************************
194 // Functions
195
196 #if COMPILER_LIKES_PRAGMA_MARK
197 #pragma mark -
198 #pragma mark - Utility Functions
199 #endif
200
201 // We only attempt to send and receive multicast packets on interfaces that are
202 // (a) flagged as multicast-capable
203 // (b) *not* flagged as point-to-point (e.g. modem)
204 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
205 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
206 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
207
208 #if BONJOUR_ON_DEMAND
209 #define MulticastInterface(i) ((i)->m->BonjourEnabled && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
210 #else
211 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
212 #endif
213 #define SPSInterface(i) ((i)->ifinfo.McastTxRx && !((i)->ifa_flags & IFF_LOOPBACK) && !(i)->D2DInterface)
214
215 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
216 {
217 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
218 #if !ForceAlerts
219 {
220 // Determine if we're at Apple (17.*.*.*)
221 NetworkInterfaceInfoOSX *i;
222 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
223 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
224 break;
225 if (!i)
226 return; // If not at Apple, don't show the alert
227 }
228 #endif
229
230 LogMsg("NotifyOfElusiveBug: %s", title);
231 LogMsg("NotifyOfElusiveBug: %s", msg);
232
233 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
234 // To avoid this, we don't try to display alerts in the first three minutes after boot.
235 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180))
236 {
237 LogMsg("Suppressing notification early in boot: %d", mDNSPlatformRawTime());
238 return;
239 }
240
241 #ifndef NO_CFUSERNOTIFICATION
242 static int notifyCount = 0; // To guard against excessive display of warning notifications
243 if (notifyCount < 5)
244 {
245 notifyCount++;
246 mDNSNotify(title, msg);
247 }
248 #endif /* NO_CFUSERNOTIFICATION */
249
250 }
251
252 // Write a syslog message and display an alert, then if ForceAlerts is set, generate a stack trace
253 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
254 mDNSexport void LogMemCorruption(const char *format, ...)
255 {
256 char buffer[512];
257 va_list ptr;
258 va_start(ptr,format);
259 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
260 va_end(ptr);
261 LogMsg("!!!! %s !!!!", buffer);
262 NotifyOfElusiveBug("Memory Corruption", buffer);
263 #if ForceAlerts
264 *(volatile long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
265 #endif
266 }
267 #endif
268
269 // Like LogMemCorruption above, but only display the alert if ForceAlerts is set and we're going to generate a stack trace
270 #if APPLE_OSX_mDNSResponder
271 mDNSexport void LogFatalError(const char *format, ...)
272 {
273 char buffer[512];
274 va_list ptr;
275 va_start(ptr,format);
276 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
277 va_end(ptr);
278 LogMsg("!!!! %s !!!!", buffer);
279 #if ForceAlerts
280 NotifyOfElusiveBug("Fatal Error. See /Library/Logs/DiagnosticReports", buffer);
281 *(volatile long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
282 #endif
283 }
284 #endif
285
286 // Returns true if it is an AppleTV based hardware running iOS, false otherwise
287 mDNSlocal mDNSBool IsAppleTV(void)
288 {
289 #if TARGET_OS_EMBEDDED
290 static mDNSBool sInitialized = mDNSfalse;
291 static mDNSBool sIsAppleTV = mDNSfalse;
292 CFStringRef deviceClass = NULL;
293
294 if(!sInitialized)
295 {
296 deviceClass = (CFStringRef) MGCopyAnswer(kMGQDeviceClass, NULL);
297 if(deviceClass)
298 {
299 if(CFEqual(deviceClass, kMGDeviceClassAppleTV))
300 sIsAppleTV = mDNStrue;
301 CFRelease(deviceClass);
302 }
303 sInitialized = mDNStrue;
304 }
305 return(sIsAppleTV);
306 #else
307 return mDNSfalse;
308 #endif // TARGET_OS_EMBEDDED
309 }
310
311 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
312 {
313 static struct ifaddrs *ifa = NULL;
314
315 if (refresh && ifa)
316 {
317 freeifaddrs(ifa);
318 ifa = NULL;
319 }
320
321 if (ifa == NULL)
322 getifaddrs(&ifa);
323 return ifa;
324 }
325
326 mDNSlocal void DynamicStoreWrite(int key, const char* subkey, uintptr_t value, signed long valueCnt)
327 {
328 CFStringRef sckey = NULL;
329 Boolean release_sckey = FALSE;
330 CFDataRef bytes = NULL;
331 CFPropertyListRef plist = NULL;
332
333 switch ((enum mDNSDynamicStoreSetConfigKey)key)
334 {
335 case kmDNSMulticastConfig:
336 sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
337 break;
338 case kmDNSDynamicConfig:
339 sckey = CFSTR("State:/Network/DynamicDNS");
340 break;
341 case kmDNSPrivateConfig:
342 sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
343 break;
344 case kmDNSBackToMyMacConfig:
345 sckey = CFSTR("State:/Network/BackToMyMac");
346 break;
347 case kmDNSSleepProxyServersState:
348 {
349 CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0);
350 CFStringAppend(tmp, CFSTR("State:/Network/Interface/"));
351 CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8);
352 CFStringAppend(tmp, CFSTR("/SleepProxyServers"));
353 sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp);
354 release_sckey = TRUE;
355 CFRelease(tmp);
356 break;
357 }
358 case kmDNSDebugState:
359 sckey = CFSTR("State:/Network/mDNSResponder/DebugState");
360 break;
361 default:
362 LogMsg("unrecognized key %d", key);
363 goto fin;
364 }
365 if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
366 valueCnt, kCFAllocatorNull)))
367 {
368 LogMsg("CFDataCreateWithBytesNoCopy of value failed");
369 goto fin;
370 }
371 if (NULL == (plist = CFPropertyListCreateWithData(NULL, bytes, kCFPropertyListImmutable, NULL, NULL)))
372 {
373 LogMsg("CFPropertyListCreateWithData of bytes failed");
374 goto fin;
375 }
376 CFRelease(bytes);
377 bytes = NULL;
378 SCDynamicStoreSetValue(NULL, sckey, plist);
379
380 fin:
381 if (NULL != bytes)
382 CFRelease(bytes);
383 if (NULL != plist)
384 CFRelease(plist);
385 if (release_sckey && sckey)
386 CFRelease(sckey);
387 }
388
389 mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value)
390 {
391 CFPropertyListRef valueCopy;
392 char *subkeyCopy = NULL;
393 if (!value)
394 return;
395
396 // We need to copy the key and value before we dispatch off the block below as the
397 // caller will free the memory once we return from this function.
398 valueCopy = CFPropertyListCreateDeepCopy(NULL, value, kCFPropertyListImmutable);
399 if (!valueCopy)
400 {
401 LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
402 return;
403 }
404 if (subkey)
405 {
406 int len = strlen(subkey);
407 subkeyCopy = mDNSPlatformMemAllocate(len + 1);
408 if (!subkeyCopy)
409 {
410 LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
411 CFRelease(valueCopy);
412 return;
413 }
414 mDNSPlatformMemCopy(subkeyCopy, subkey, len);
415 subkeyCopy[len] = 0;
416 }
417
418 dispatch_async(dispatch_get_main_queue(), ^{
419 CFWriteStreamRef stream = NULL;
420 CFDataRef bytes = NULL;
421 CFIndex ret;
422 KQueueLock();
423
424 if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL)))
425 {
426 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
427 goto END;
428 }
429 CFWriteStreamOpen(stream);
430 ret = CFPropertyListWrite(valueCopy, stream, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
431 if (ret == 0)
432 {
433 LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
434 goto END;
435 }
436 if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten)))
437 {
438 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
439 goto END;
440 }
441 CFWriteStreamClose(stream);
442 CFRelease(stream);
443 stream = NULL;
444 DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes));
445
446 END:
447 CFRelease(valueCopy);
448 if (NULL != stream)
449 {
450 CFWriteStreamClose(stream);
451 CFRelease(stream);
452 }
453 if (NULL != bytes)
454 CFRelease(bytes);
455 if (subkeyCopy)
456 mDNSPlatformMemFree(subkeyCopy);
457
458 KQueueUnlock("mDNSDynamicStoreSetConfig");
459 });
460 }
461
462 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
463 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(const char *ifname, int type)
464 {
465 NetworkInterfaceInfoOSX *i;
466 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
467 if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
468 ((type == AF_UNSPEC ) ||
469 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
470 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
471 return(NULL);
472 }
473
474 mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
475 {
476 struct ifaddrs *ifa;
477 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
478 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
479 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
480 { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
481 return -1;
482 }
483
484 mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(mDNSInterfaceID ifindex)
485 {
486 mDNS *const m = &mDNSStorage;
487 mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
488 NetworkInterfaceInfoOSX *i;
489
490 // Don't get tricked by inactive interfaces
491 for (i = m->p->InterfaceList; i; i = i->next)
492 if (i->Registered && i->scope_id == scope_id) return(i);
493
494 return mDNSNULL;
495 }
496
497 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
498 {
499 (void) m;
500 if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
501 if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
502 if (ifindex == kDNSServiceInterfaceIndexBLE ) return(mDNSInterface_BLE);
503 if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
504
505 NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
506 if (!ifi)
507 {
508 // Not found. Make sure our interface list is up to date, then try again.
509 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
510 mDNSMacOSXNetworkChanged();
511 ifi = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
512 }
513
514 if (!ifi) return(mDNSNULL);
515
516 return(ifi->ifinfo.InterfaceID);
517 }
518
519
520 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
521 {
522 NetworkInterfaceInfoOSX *i;
523 if (id == mDNSInterface_Any ) return(0);
524 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
525 if (id == mDNSInterface_Unicast ) return(0);
526 if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
527 if (id == mDNSInterface_BLE ) return(kDNSServiceInterfaceIndexBLE);
528
529 mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
530
531 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
532 for (i = m->p->InterfaceList; i; i = i->next)
533 if (i->scope_id == scope_id) return(i->scope_id);
534
535 // If we are supposed to suppress network change, return "id" back
536 if (suppressNetworkChange) return scope_id;
537
538 // Not found. Make sure our interface list is up to date, then try again.
539 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
540 mDNSMacOSXNetworkChanged();
541 for (i = m->p->InterfaceList; i; i = i->next)
542 if (i->scope_id == scope_id) return(i->scope_id);
543
544 return(0);
545 }
546
547 #if COMPILER_LIKES_PRAGMA_MARK
548 #pragma mark -
549 #pragma mark - UDP & TCP send & receive
550 #endif
551
552 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
553 {
554 mDNSBool result = mDNSfalse;
555 SCNetworkConnectionFlags flags;
556 CFDataRef remote_addr;
557 CFMutableDictionaryRef options;
558 SCNetworkReachabilityRef ReachRef = NULL;
559
560 options = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
561 remote_addr = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len);
562 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, remote_addr);
563 CFDictionarySetValue(options, kSCNetworkReachabilityOptionServerBypass, kCFBooleanTrue);
564 ReachRef = SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault, options);
565 CFRelease(options);
566 CFRelease(remote_addr);
567
568 if (!ReachRef)
569 {
570 LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions");
571 goto end;
572 }
573 if (!SCNetworkReachabilityGetFlags(ReachRef, &flags))
574 {
575 LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags");
576 goto end;
577 }
578 result = flags & kSCNetworkFlagsConnectionRequired;
579
580 end:
581 if (ReachRef)
582 CFRelease(ReachRef);
583 return result;
584 }
585
586 // Set traffic class for socket
587 mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass)
588 {
589 int traffic_class;
590
591 if (useBackgroundTrafficClass)
592 traffic_class = SO_TC_BK_SYS;
593 else
594 traffic_class = SO_TC_CTL;
595
596 (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class));
597 }
598
599 #ifdef UNIT_TEST
600 // Run the unit test main
601 UNITTEST_SETSOCKOPT
602 #else
603 mDNSlocal int mDNSPlatformGetSocktFd(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType)
604 {
605 if (transType == mDNSTransport_UDP)
606 {
607 UDPSocket* sock = (UDPSocket*) sockCxt;
608 return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6;
609 }
610 else if (transType == mDNSTransport_TCP)
611 {
612 TCPSocket* sock = (TCPSocket*) sockCxt;
613 return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6;
614 }
615 else
616 {
617 LogInfo("mDNSPlatformGetSocktFd: invalid transport %d", transType);
618 return kInvalidSocketRef;
619 }
620 }
621
622 mDNSexport void mDNSPlatformSetSocktOpt(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType, const DNSQuestion *q)
623 {
624 int sockfd;
625 char unenc_name[MAX_ESCAPED_DOMAIN_NAME];
626
627 // verify passed-in arguments exist and that sockfd is valid
628 if (q == mDNSNULL || sockCxt == mDNSNULL || (sockfd = mDNSPlatformGetSocktFd(sockCxt, transType, addrType)) < 0)
629 return;
630
631 if (q->pid)
632 {
633 if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1)
634 LogMsg("mDNSPlatformSetSocktOpt: Delegate PID failed %s for PID %d", strerror(errno), q->pid);
635 }
636 else
637 {
638 if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1)
639 LogMsg("mDNSPlatformSetSocktOpt: Delegate UUID failed %s", strerror(errno));
640 }
641
642 // set the domain on the socket
643 ConvertDomainNameToCString(&q->qname, unenc_name);
644 if (!(ne_session_set_socket_attributes(sockfd, unenc_name, NULL)))
645 LogInfo("mDNSPlatformSetSocktOpt: ne_session_set_socket_attributes()-> setting domain failed for %s", unenc_name);
646
647 int nowake = 1;
648 if (setsockopt(sockfd, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
649 LogInfo("mDNSPlatformSetSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
650 }
651 #endif // UNIT_TEST
652
653 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
654 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
655 // OR send via our primary v4 unicast socket
656 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
657 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
658 mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
659 mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
660 {
661 NetworkInterfaceInfoOSX *info = mDNSNULL;
662 struct sockaddr_storage to;
663 int s = -1, err;
664 mStatus result = mStatus_NoError;
665 int sendto_errno;
666
667 if (InterfaceID)
668 {
669 info = IfindexToInterfaceInfoOSX(InterfaceID);
670 if (info == NULL)
671 {
672 // We may not have registered interfaces with the "core" as we may not have
673 // seen any interface notifications yet. This typically happens during wakeup
674 // where we might try to send DNS requests (non-SuppressUnusable questions internal
675 // to mDNSResponder) before we receive network notifications.
676 LogInfo("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
677 return mStatus_BadParamErr;
678 }
679 }
680
681 char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
682
683 if (dst->type == mDNSAddrType_IPv4)
684 {
685 struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
686 sin_to->sin_len = sizeof(*sin_to);
687 sin_to->sin_family = AF_INET;
688 sin_to->sin_port = dstPort.NotAnInteger;
689 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
690 s = (src ? src->ss : m->p->permanentsockets).sktv4;
691
692 if (!mDNSAddrIsDNSMulticast(dst))
693 {
694 #ifdef IP_BOUND_IF
695 const mDNSu32 ifindex = info ? info->scope_id : IFSCOPE_NONE;
696 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
697 #else
698 static int displayed = 0;
699 if (displayed < 1000)
700 {
701 displayed++;
702 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
703 }
704 #endif
705 }
706 else if (info)
707 {
708 #ifdef IP_MULTICAST_IFINDEX
709 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IFINDEX, &info->scope_id, sizeof(info->scope_id));
710 // We get an error when we compile on a machine that supports this option and run the binary on
711 // a different machine that does not support it
712 if (err < 0)
713 {
714 if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno);
715 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
716 if (err < 0 && !m->NetworkChanged)
717 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
718 }
719 #else
720 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
721 if (err < 0 && !m->NetworkChanged)
722 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
723 #endif
724 }
725 }
726 else if (dst->type == mDNSAddrType_IPv6)
727 {
728 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
729 sin6_to->sin6_len = sizeof(*sin6_to);
730 sin6_to->sin6_family = AF_INET6;
731 sin6_to->sin6_port = dstPort.NotAnInteger;
732 sin6_to->sin6_flowinfo = 0;
733 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
734 sin6_to->sin6_scope_id = info ? info->scope_id : 0;
735 s = (src ? src->ss : m->p->permanentsockets).sktv6;
736 if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
737 {
738 err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
739 if (err < 0)
740 {
741 const int setsockopt_errno = errno;
742 char name[IFNAMSIZ];
743 if (if_indextoname(info->scope_id, name) != NULL)
744 LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, setsockopt_errno, strerror(setsockopt_errno));
745 else
746 LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id);
747 }
748 }
749 #ifdef IPV6_BOUND_IF
750 if (info) // Specify outgoing interface for non-multicast destination
751 {
752 if (!mDNSAddrIsDNSMulticast(dst))
753 {
754 if (info->scope_id == 0)
755 LogInfo("IPV6_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
756 else
757 setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
758 }
759 }
760 #endif
761 }
762
763 else
764 {
765 LogFatalError("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
766 return mStatus_BadParamErr;
767 }
768
769 if (s >= 0)
770 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
771 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
772 else
773 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
774 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
775
776 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
777 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
778 if (s < 0) return(mStatus_Invalid);
779
780 // switch to background traffic class for this message if requested
781 if (useBackgroundTrafficClass)
782 setTrafficClass(s, useBackgroundTrafficClass);
783
784 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
785 sendto_errno = (err < 0) ? errno : 0;
786
787 // set traffic class back to default value
788 if (useBackgroundTrafficClass)
789 setTrafficClass(s, mDNSfalse);
790
791 if (err < 0)
792 {
793 static int MessageCount = 0;
794 LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
795 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
796 if (!mDNSAddressIsAllDNSLinkGroup(dst))
797 {
798 if ((sendto_errno == EHOSTUNREACH) || (sendto_errno == ENETUNREACH)) return(mStatus_HostUnreachErr);
799 if ((sendto_errno == EHOSTDOWN) || (sendto_errno == ENETDOWN)) return(mStatus_TransientErr);
800 }
801 // Don't report EHOSTUNREACH in the first three minutes after boot
802 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
803 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
804 if (sendto_errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
805 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
806 if (sendto_errno == EADDRNOTAVAIL && m->NetworkChanged) return(mStatus_TransientErr);
807 if (sendto_errno == EHOSTUNREACH || sendto_errno == EADDRNOTAVAIL || sendto_errno == ENETDOWN)
808 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
809 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
810 else
811 {
812 MessageCount++;
813 if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs
814 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",
815 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
816 else // If logging is enabled, remove the cap and log aggressively
817 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",
818 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
819 }
820
821 result = mStatus_UnknownErr;
822 }
823
824 return(result);
825 }
826
827 mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
828 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
829 {
830 static unsigned int numLogMessages = 0;
831 struct iovec databuffers = { (char *)buffer, max };
832 struct msghdr msg;
833 ssize_t n;
834 struct cmsghdr *cmPtr;
835 char ancillary[1024];
836
837 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
838
839 // Set up the message
840 msg.msg_name = (caddr_t)from;
841 msg.msg_namelen = *fromlen;
842 msg.msg_iov = &databuffers;
843 msg.msg_iovlen = 1;
844 msg.msg_control = (caddr_t)&ancillary;
845 msg.msg_controllen = sizeof(ancillary);
846 msg.msg_flags = 0;
847
848 // Receive the data
849 n = recvmsg(s, &msg, 0);
850 if (n<0)
851 {
852 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
853 return(-1);
854 }
855 if (msg.msg_flags & MSG_CTRUNC)
856 {
857 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
858 return(-1);
859 }
860 *fromlen = msg.msg_namelen;
861
862 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
863 {
864 if (numLogMessages++ < 100)
865 {
866 LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %ld msg.msg_controllen %lu < sizeof(struct cmsghdr) %lu",
867 s, (long)n, (unsigned long)msg.msg_controllen, (unsigned long)sizeof(struct cmsghdr));
868 }
869 goto exit;
870 }
871 // Parse each option out of the ancillary data.
872 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
873 {
874 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
875 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
876 {
877 dstaddr->type = mDNSAddrType_IPv4;
878 dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
879 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
880 }
881 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
882 {
883 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
884 if (sdl->sdl_nlen < IF_NAMESIZE)
885 {
886 mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
887 ifname[sdl->sdl_nlen] = 0;
888 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
889 }
890 }
891 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
892 *ttl = *(u_char*)CMSG_DATA(cmPtr);
893 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
894 {
895 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
896 dstaddr->type = mDNSAddrType_IPv6;
897 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
898 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
899 }
900 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
901 *ttl = *(int*)CMSG_DATA(cmPtr);
902 }
903
904 exit:
905 return(n);
906 }
907
908 // What is this for, and why does it use xor instead of a simple quality check? -- SC
909 mDNSlocal mDNSInterfaceID FindMyInterface(const mDNSAddr *addr)
910 {
911 NetworkInterfaceInfo *intf;
912
913 if (addr->type == mDNSAddrType_IPv4)
914 {
915 for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
916 {
917 if (intf->ip.type == addr->type && intf->McastTxRx)
918 {
919 if ((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) == 0)
920 {
921 return(intf->InterfaceID);
922 }
923 }
924 }
925 }
926
927 if (addr->type == mDNSAddrType_IPv6)
928 {
929 for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
930 {
931 if (intf->ip.type == addr->type && intf->McastTxRx)
932 {
933 if (((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) == 0) &&
934 ((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) == 0) &&
935 ((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) == 0) &&
936 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) == 0)))
937 {
938 return(intf->InterfaceID);
939 }
940 }
941 }
942 }
943 return(mDNSInterface_Any);
944 }
945
946 mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool encounteredEOF)
947 {
948 KQSocketSet *const ss = (KQSocketSet *)context;
949 mDNS *const m = ss->m;
950 int err = 0, count = 0, closed = 0;
951
952 if (filter != EVFILT_READ)
953 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
954
955 if (s1 != ss->sktv4 && s1 != ss->sktv6)
956 {
957 LogMsg("myKQSocketCallBack: native socket %d", s1);
958 LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6);
959 }
960
961 if (encounteredEOF)
962 {
963 LogMsg("myKQSocketCallBack: socket %d is no longer readable (EOF)", s1);
964 if (s1 == ss->sktv4)
965 {
966 ss->sktv4EOF = mDNStrue;
967 KQueueSet(ss->sktv4, EV_DELETE, EVFILT_READ, &ss->kqsv4);
968 }
969 else if (s1 == ss->sktv6)
970 {
971 ss->sktv6EOF = mDNStrue;
972 KQueueSet(ss->sktv6, EV_DELETE, EVFILT_READ, &ss->kqsv6);
973 }
974 return;
975 }
976
977 while (!closed)
978 {
979 mDNSAddr senderAddr, destAddr = zeroAddr;
980 mDNSIPPort senderPort;
981 struct sockaddr_storage from;
982 size_t fromlen = sizeof(from);
983 char packetifname[IF_NAMESIZE] = "";
984 mDNSu8 ttl;
985 err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
986 if (err < 0) break;
987
988 if ((destAddr.type == mDNSAddrType_IPv4 && (destAddr.ip.v4.b[0] & 0xF0) == 0xE0) ||
989 (destAddr.type == mDNSAddrType_IPv6 && (destAddr.ip.v6.b[0] == 0xFF))) m->p->num_mcasts++;
990
991 count++;
992 if (from.ss_family == AF_INET)
993 {
994 struct sockaddr_in *s = (struct sockaddr_in*)&from;
995 senderAddr.type = mDNSAddrType_IPv4;
996 senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
997 senderPort.NotAnInteger = s->sin_port;
998 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
999 }
1000 else if (from.ss_family == AF_INET6)
1001 {
1002 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
1003 senderAddr.type = mDNSAddrType_IPv6;
1004 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
1005 senderPort.NotAnInteger = sin6->sin6_port;
1006 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1007 }
1008 else
1009 {
1010 LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
1011 return;
1012 }
1013
1014 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1015 mDNSInterfaceID InterfaceID = mDNSNULL;
1016 NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
1017 while (intf)
1018 {
1019 if (intf->Exists && !strcmp(intf->ifinfo.ifname, packetifname))
1020 break;
1021 intf = intf->next;
1022 }
1023
1024 // When going to sleep we deregister all our interfaces, but if the machine
1025 // takes a few seconds to sleep we may continue to receive multicasts
1026 // during that time, which would confuse mDNSCoreReceive, because as far
1027 // as it's concerned, we should have no active interfaces any more.
1028 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1029 if (intf)
1030 InterfaceID = intf->ifinfo.InterfaceID;
1031 else if (mDNSAddrIsDNSMulticast(&destAddr))
1032 continue;
1033
1034 if (!InterfaceID)
1035 {
1036 InterfaceID = FindMyInterface(&destAddr);
1037 }
1038
1039 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1040 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
1041
1042 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
1043 // loop when that happens, or we may try to read from an invalid FD. We do this by
1044 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
1045 // if it closes the socketset.
1046 ss->closeFlag = &closed;
1047
1048 if (ss->proxy)
1049 {
1050 m->p->UDPProxyCallback(&m->p->UDPProxy, &m->imsg.m, (unsigned char*)&m->imsg + err, &senderAddr,
1051 senderPort, &destAddr, ss->port, InterfaceID, NULL);
1052 }
1053 else
1054 {
1055 mDNSCoreReceive(m, &m->imsg.m, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
1056 }
1057
1058 // if we didn't close, we can safely dereference the socketset, and should to
1059 // reset the closeFlag, since it points to something on the stack
1060 if (!closed) ss->closeFlag = mDNSNULL;
1061 }
1062
1063 // If a client application's sockets are marked as defunct
1064 // sockets we have delegated to it with SO_DELEGATED will also go defunct.
1065 // We get an ENOTCONN error for defunct sockets and should just close the socket in that case.
1066 if (err < 0 && errno == ENOTCONN)
1067 {
1068 LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
1069 close(s1);
1070 return;
1071 }
1072
1073 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
1074 {
1075 // Something is busted here.
1076 // kqueue says there is a packet, but myrecvfrom says there is not.
1077 // Try calling select() to get another opinion.
1078 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1079 // All of this is racy, as data may have arrived after the call to select()
1080 static unsigned int numLogMessages = 0;
1081 const int save_errno = errno;
1082 int so_error = -1;
1083 int so_nread = -1;
1084 int fionread = -1;
1085 socklen_t solen = sizeof(int);
1086 fd_set readfds;
1087 struct timeval timeout;
1088 int selectresult;
1089 FD_ZERO(&readfds);
1090 FD_SET(s1, &readfds);
1091 timeout.tv_sec = 0;
1092 timeout.tv_usec = 0;
1093 selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
1094 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
1095 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
1096 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
1097 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
1098 if (ioctl(s1, FIONREAD, &fionread) == -1)
1099 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
1100 if (numLogMessages++ < 100)
1101 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1102 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
1103 if (numLogMessages > 5)
1104 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1105 "Congratulations, you've reproduced an elusive bug.\r"
1106 "Please send email to radar-3387020@group.apple.com.)\r"
1107 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1108
1109 sleep(1); // After logging this error, rate limit so we don't flood syslog
1110 }
1111 }
1112
1113 mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
1114 {
1115 mDNSBool c = !sock->connected;
1116 sock->connected = mDNStrue;
1117 sock->callback(sock, sock->context, c, sock->err);
1118 // Note: the callback may call CloseConnection here, which frees the context structure!
1119 }
1120
1121 #ifndef NO_SECURITYFRAMEWORK
1122
1123 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
1124 {
1125 int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1126 if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1127 if (ret >= 0) { *dataLength = ret; return(noErr); }
1128 *dataLength = 0;
1129 if (errno == EAGAIN ) return(errSSLWouldBlock);
1130 if (errno == ENOENT ) return(errSSLClosedGraceful);
1131 if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
1132 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
1133 return(errSSLClosedAbort);
1134 }
1135
1136 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
1137 {
1138 int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1139 if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1140 if (ret > 0) { *dataLength = ret; return(noErr); }
1141 *dataLength = 0;
1142 if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
1143 if ( errno == EAGAIN ) return(errSSLWouldBlock);
1144 if ( errno == ECONNRESET) return(errSSLClosedAbort);
1145 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
1146 return(errSSLClosedAbort);
1147 }
1148
1149 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConnectionType ctype)
1150 {
1151 char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
1152
1153 sock->tlsContext = SSLCreateContext(kCFAllocatorDefault, pside, ctype);
1154 if (!sock->tlsContext)
1155 {
1156 LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
1157 return(mStatus_UnknownErr);
1158 }
1159
1160 mStatus err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
1161 if (err)
1162 {
1163 LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err);
1164 goto fail;
1165 }
1166
1167 err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
1168 if (err)
1169 {
1170 LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err);
1171 goto fail;
1172 }
1173
1174 // Set the default ciphersuite configuration
1175 err = SSLSetSessionConfig(sock->tlsContext, CFSTR("default"));
1176 if (err)
1177 {
1178 LogMsg("ERROR: tlsSetupSock: SSLSetSessionConfig failed with error code: %d", err);
1179 goto fail;
1180 }
1181
1182 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
1183 // (error not in OSStatus space) is okay.
1184 if (!sock->hostname.c[0])
1185 {
1186 LogMsg("ERROR: tlsSetupSock: hostname NULL");
1187 err = -1;
1188 goto fail;
1189 }
1190
1191 ConvertDomainNameToCString(&sock->hostname, domname_cstr);
1192 err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
1193 if (err)
1194 {
1195 LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err);
1196 goto fail;
1197 }
1198
1199 return(err);
1200
1201 fail:
1202 if (sock->tlsContext)
1203 CFRelease(sock->tlsContext);
1204 return(err);
1205 }
1206
1207 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1208 mDNSlocal void doSSLHandshake(TCPSocket *sock)
1209 {
1210 mStatus err = SSLHandshake(sock->tlsContext);
1211
1212 //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
1213 //defined, KQueueLock is a noop. Hence we need to serialize here
1214 //
1215 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
1216 //We need the rest of the logic also. Otherwise, we can enable the READ
1217 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
1218 //ConnFailed which means we are going to free the tcpInfo. While it
1219 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
1220 //and potentially call doTCPCallback with error which can close the fd and free the
1221 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
1222 //is already freed.
1223
1224 dispatch_async(dispatch_get_main_queue(), ^{
1225
1226 LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1227
1228 if (sock->handshake == handshake_to_be_closed)
1229 {
1230 LogInfo("SSLHandshake completed after close");
1231 mDNSPlatformTCPCloseConnection(sock);
1232 }
1233 else
1234 {
1235 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1236 else LogMsg("doSSLHandshake: sock->fd is -1");
1237
1238 if (err == errSSLWouldBlock)
1239 sock->handshake = handshake_required;
1240 else
1241 {
1242 if (err)
1243 {
1244 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1245 CFRelease(sock->tlsContext);
1246 sock->tlsContext = NULL;
1247 }
1248
1249 sock->err = err ? mStatus_ConnFailed : 0;
1250 sock->handshake = handshake_completed;
1251
1252 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1253 doTcpSocketCallback(sock);
1254 }
1255 }
1256
1257 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1258 return;
1259 });
1260 }
1261 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1262 mDNSlocal void *doSSLHandshake(TCPSocket *sock)
1263 {
1264 // Warning: Touching sock without the kqueue lock!
1265 // We're protected because sock->handshake == handshake_in_progress
1266 mStatus err = SSLHandshake(sock->tlsContext);
1267
1268 KQueueLock();
1269 debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1270
1271 if (sock->handshake == handshake_to_be_closed)
1272 {
1273 LogInfo("SSLHandshake completed after close");
1274 mDNSPlatformTCPCloseConnection(sock);
1275 }
1276 else
1277 {
1278 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1279 else LogMsg("doSSLHandshake: sock->fd is -1");
1280
1281 if (err == errSSLWouldBlock)
1282 sock->handshake = handshake_required;
1283 else
1284 {
1285 if (err)
1286 {
1287 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1288 CFRelease(sock->tlsContext);
1289 sock->tlsContext = NULL;
1290 }
1291
1292 sock->err = err ? mStatus_ConnFailed : 0;
1293 sock->handshake = handshake_completed;
1294
1295 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1296 doTcpSocketCallback(sock);
1297 }
1298 }
1299
1300 debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1301 KQueueUnlock("doSSLHandshake");
1302 return NULL;
1303 }
1304 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1305
1306 mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
1307 {
1308 debugf("spawnSSLHandshake %p: entry", sock);
1309
1310 if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
1311 sock->handshake = handshake_in_progress;
1312 KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
1313
1314 // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
1315 // to limit the number of threads used for SSLHandshake
1316 dispatch_async(SSLqueue, ^{doSSLHandshake(sock);});
1317
1318 debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
1319 }
1320
1321 #endif /* NO_SECURITYFRAMEWORK */
1322
1323 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context, __unused mDNSBool encounteredEOF)
1324 {
1325 TCPSocket *sock = context;
1326 sock->err = mStatus_NoError;
1327
1328 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1329 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1330 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1331 if (filter == EVFILT_WRITE)
1332 KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
1333
1334 if (sock->flags & kTCPSocketFlags_UseTLS)
1335 {
1336 #ifndef NO_SECURITYFRAMEWORK
1337 if (!sock->setup)
1338 {
1339 sock->setup = mDNStrue;
1340 sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
1341 if (sock->err)
1342 {
1343 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
1344 return;
1345 }
1346 }
1347 if (sock->handshake == handshake_required)
1348 {
1349 spawnSSLHandshake(sock);
1350 return;
1351 }
1352 else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
1353 {
1354 return;
1355 }
1356 else if (sock->handshake != handshake_completed)
1357 {
1358 if (!sock->err)
1359 sock->err = mStatus_UnknownErr;
1360 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
1361 }
1362 #else /* NO_SECURITYFRAMEWORK */
1363 sock->err = mStatus_UnsupportedErr;
1364 #endif /* NO_SECURITYFRAMEWORK */
1365 }
1366
1367 doTcpSocketCallback(sock);
1368 }
1369
1370 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1371 mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef)
1372 {
1373 dispatch_queue_t queue = dispatch_get_main_queue();
1374 dispatch_source_t source;
1375 if (flags == EV_DELETE)
1376 {
1377 if (filter == EVFILT_READ)
1378 {
1379 dispatch_source_cancel(entryRef->readSource);
1380 dispatch_release(entryRef->readSource);
1381 entryRef->readSource = mDNSNULL;
1382 debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource);
1383 }
1384 else if (filter == EVFILT_WRITE)
1385 {
1386 dispatch_source_cancel(entryRef->writeSource);
1387 dispatch_release(entryRef->writeSource);
1388 entryRef->writeSource = mDNSNULL;
1389 debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource);
1390 }
1391 else
1392 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
1393 return 0;
1394 }
1395 if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
1396
1397 if (filter == EVFILT_READ)
1398 {
1399 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
1400 }
1401 else if (filter == EVFILT_WRITE)
1402 {
1403 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
1404 }
1405 else
1406 {
1407 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
1408 return -1;
1409 }
1410 if (!source) return -1;
1411 dispatch_source_set_event_handler(source, ^{
1412
1413 mDNSs32 stime = mDNSPlatformRawTime();
1414 entryRef->KQcallback(fd, filter, entryRef->KQcontext);
1415 mDNSs32 etime = mDNSPlatformRawTime();
1416 if (etime - stime >= WatchDogReportingThreshold)
1417 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime);
1418
1419 // Trigger the event delivery to the application. Even though we trigger the
1420 // event completion after handling every event source, these all will hopefully
1421 // get merged
1422 TriggerEventCompletion();
1423
1424 });
1425 dispatch_source_set_cancel_handler(source, ^{
1426 if (entryRef->fdClosed)
1427 {
1428 //LogMsg("CancelHandler: closing fd %d", fd);
1429 close(fd);
1430 }
1431 });
1432 dispatch_resume(source);
1433 if (filter == EVFILT_READ)
1434 entryRef->readSource = source;
1435 else
1436 entryRef->writeSource = source;
1437
1438 return 0;
1439 }
1440
1441 mDNSexport void KQueueLock()
1442 {
1443 }
1444 mDNSexport void KQueueUnlock(const char const *task)
1445 {
1446 (void)task; //unused
1447 }
1448 #else
1449 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
1450 {
1451 struct kevent new_event;
1452 EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
1453 return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
1454 }
1455
1456 mDNSexport void KQueueLock()
1457 {
1458 mDNS *const m = &mDNSStorage;
1459 pthread_mutex_lock(&m->p->BigMutex);
1460 m->p->BigMutexStartTime = mDNSPlatformRawTime();
1461 }
1462
1463 mDNSexport void KQueueUnlock(const char* task)
1464 {
1465 mDNS *const m = &mDNSStorage;
1466 mDNSs32 end = mDNSPlatformRawTime();
1467 (void)task;
1468 if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
1469 LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
1470
1471 pthread_mutex_unlock(&m->p->BigMutex);
1472
1473 char wake = 1;
1474 if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
1475 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
1476 }
1477 #endif
1478
1479 mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
1480 {
1481 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1482 (void) fd; //unused
1483 if (kq->readSource)
1484 {
1485 dispatch_source_cancel(kq->readSource);
1486 kq->readSource = mDNSNULL;
1487 }
1488 if (kq->writeSource)
1489 {
1490 dispatch_source_cancel(kq->writeSource);
1491 kq->writeSource = mDNSNULL;
1492 }
1493 // Close happens in the cancellation handler
1494 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
1495 kq->fdClosed = mDNStrue;
1496 #else
1497 (void)kq; //unused
1498 close(fd);
1499 #endif
1500 }
1501
1502 mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
1503 {
1504 KQSocketSet *cp = &sock->ss;
1505 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
1506 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
1507 const int on = 1; // "on" for setsockopt
1508 mStatus err;
1509
1510 int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
1511 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
1512
1513 // for TCP sockets, the traffic class is set once and not changed
1514 setTrafficClass(skt, useBackgroundTrafficClass);
1515
1516 if (sa_family == AF_INET)
1517 {
1518 // Bind it
1519 struct sockaddr_in addr;
1520 mDNSPlatformMemZero(&addr, sizeof(addr));
1521 addr.sin_family = AF_INET;
1522 addr.sin_port = port->NotAnInteger;
1523 err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
1524 if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); close(skt); return err; }
1525
1526 // Receive interface identifiers
1527 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
1528 if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); close(skt); return err; }
1529
1530 mDNSPlatformMemZero(&addr, sizeof(addr));
1531 socklen_t len = sizeof(addr);
1532 err = getsockname(skt, (struct sockaddr*) &addr, &len);
1533 if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); close(skt); return err; }
1534
1535 port->NotAnInteger = addr.sin_port;
1536 }
1537 else
1538 {
1539 // Bind it
1540 struct sockaddr_in6 addr6;
1541 mDNSPlatformMemZero(&addr6, sizeof(addr6));
1542 addr6.sin6_family = AF_INET6;
1543 addr6.sin6_port = port->NotAnInteger;
1544 err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
1545 if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); close(skt); return err; }
1546
1547 // We want to receive destination addresses and receive interface identifiers
1548 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
1549 if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); close(skt); return err; }
1550
1551 mDNSPlatformMemZero(&addr6, sizeof(addr6));
1552 socklen_t len = sizeof(addr6);
1553 err = getsockname(skt, (struct sockaddr *) &addr6, &len);
1554 if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); close(skt); return err; }
1555
1556 port->NotAnInteger = addr6.sin6_port;
1557
1558 }
1559 *s = skt;
1560 k->KQcallback = tcpKQSocketCallback;
1561 k->KQcontext = sock;
1562 k->KQtask = "mDNSPlatformTCPSocket";
1563 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1564 k->readSource = mDNSNULL;
1565 k->writeSource = mDNSNULL;
1566 k->fdClosed = mDNSfalse;
1567 #endif
1568 return mStatus_NoError;
1569 }
1570
1571 mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
1572 {
1573 mStatus err;
1574
1575 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
1576 if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
1577
1578 mDNSPlatformMemZero(sock, sizeof(TCPSocket));
1579
1580 sock->ss.m = &mDNSStorage;
1581 sock->ss.sktv4 = -1;
1582 sock->ss.sktv6 = -1;
1583 err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
1584
1585 if (!err)
1586 {
1587 err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass);
1588 if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
1589 }
1590 if (err)
1591 {
1592 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
1593 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
1594 return(mDNSNULL);
1595 }
1596 // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
1597 sock->fd = sock->ss.sktv4;
1598 sock->callback = mDNSNULL;
1599 sock->flags = flags;
1600 sock->context = mDNSNULL;
1601 sock->setup = mDNSfalse;
1602 sock->connected = mDNSfalse;
1603 sock->handshake = handshake_required;
1604 sock->m = &mDNSStorage;
1605 sock->err = mStatus_NoError;
1606
1607 return sock;
1608 }
1609
1610 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
1611 {
1612 KQSocketSet *cp = &sock->ss;
1613 int *s = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
1614 KQueueEntry *k = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
1615 mStatus err = mStatus_NoError;
1616 struct sockaddr_storage ss;
1617
1618 sock->callback = callback;
1619 sock->context = context;
1620 sock->setup = mDNSfalse;
1621 sock->connected = mDNSfalse;
1622 sock->handshake = handshake_required;
1623 sock->err = mStatus_NoError;
1624
1625 if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
1626
1627 if (dst->type == mDNSAddrType_IPv4)
1628 {
1629 struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
1630 mDNSPlatformMemZero(saddr, sizeof(*saddr));
1631 saddr->sin_family = AF_INET;
1632 saddr->sin_port = dstport.NotAnInteger;
1633 saddr->sin_len = sizeof(*saddr);
1634 saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1635 }
1636 else
1637 {
1638 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss;
1639 mDNSPlatformMemZero(saddr6, sizeof(*saddr6));
1640 saddr6->sin6_family = AF_INET6;
1641 saddr6->sin6_port = dstport.NotAnInteger;
1642 saddr6->sin6_len = sizeof(*saddr6);
1643 saddr6->sin6_addr = *(struct in6_addr *)&dst->ip.v6;
1644 }
1645
1646 // Watch for connect complete (write is ready)
1647 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1648 if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
1649 {
1650 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1651 return errno;
1652 }
1653
1654 // Watch for incoming data
1655 if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
1656 {
1657 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1658 return errno;
1659 }
1660
1661 if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
1662 {
1663 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
1664 return mStatus_UnknownErr;
1665 }
1666
1667 // We bind to the interface and all subsequent packets including the SYN will be sent out
1668 // on this interface
1669 //
1670 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
1671 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
1672 if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
1673 {
1674 NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(InterfaceID);
1675 if (dst->type == mDNSAddrType_IPv4)
1676 {
1677 #ifdef IP_BOUND_IF
1678 if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1679 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
1680 #else
1681 (void)InterfaceID; // Unused
1682 (void)info; // Unused
1683 #endif
1684 }
1685 else
1686 {
1687 #ifdef IPV6_BOUND_IF
1688 if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1689 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
1690 #else
1691 (void)InterfaceID; // Unused
1692 (void)info; // Unused
1693 #endif
1694 }
1695 }
1696
1697 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
1698 // from which we can infer the destination address family. Hence we need to remember that here.
1699 // Instead of remembering the address family, we remember the right fd.
1700 sock->fd = *s;
1701 sock->kqEntry = k;
1702 // initiate connection wth peer
1703 if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
1704 {
1705 if (errno == EINPROGRESS) return mStatus_ConnPending;
1706 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
1707 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
1708 else
1709 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
1710 return mStatus_ConnFailed;
1711 }
1712
1713 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1714 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1715 return err;
1716 }
1717
1718 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1719 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
1720 {
1721 mStatus err = mStatus_NoError;
1722
1723 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
1724 if (!sock) return(mDNSNULL);
1725
1726 mDNSPlatformMemZero(sock, sizeof(*sock));
1727 sock->fd = fd;
1728 sock->flags = flags;
1729
1730 if (flags & kTCPSocketFlags_UseTLS)
1731 {
1732 #ifndef NO_SECURITYFRAMEWORK
1733 if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
1734
1735 err = tlsSetupSock(sock, kSSLServerSide, kSSLStreamType);
1736 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
1737
1738 err = SSLSetCertificate(sock->tlsContext, ServerCerts);
1739 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
1740 #else
1741 err = mStatus_UnsupportedErr;
1742 #endif /* NO_SECURITYFRAMEWORK */
1743 }
1744 #ifndef NO_SECURITYFRAMEWORK
1745 exit:
1746 #endif
1747
1748 if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
1749 return(sock);
1750 }
1751
1752 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
1753 {
1754 mDNSu16 port;
1755
1756 port = -1;
1757 if (sock)
1758 {
1759 port = sock->ss.port.NotAnInteger;
1760 }
1761 return port;
1762 }
1763
1764 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
1765 {
1766 if (ss->sktv4 != -1)
1767 {
1768 mDNSPlatformCloseFD(&ss->kqsv4, ss->sktv4);
1769 ss->sktv4 = -1;
1770 }
1771 if (ss->sktv6 != -1)
1772 {
1773 mDNSPlatformCloseFD(&ss->kqsv6, ss->sktv6);
1774 ss->sktv6 = -1;
1775 }
1776 if (ss->closeFlag) *ss->closeFlag = 1;
1777 }
1778
1779 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
1780 {
1781 if (sock)
1782 {
1783 #ifndef NO_SECURITYFRAMEWORK
1784 if (sock->tlsContext)
1785 {
1786 if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
1787 {
1788 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
1789 // When we come back from SSLHandshake, we will notice that a close was here and
1790 // call this function again which will do the cleanup then.
1791 sock->handshake = handshake_to_be_closed;
1792 return;
1793 }
1794
1795 SSLClose(sock->tlsContext);
1796 CFRelease(sock->tlsContext);
1797 sock->tlsContext = NULL;
1798 }
1799 #endif /* NO_SECURITYFRAMEWORK */
1800 if (sock->ss.sktv4 != -1)
1801 shutdown(sock->ss.sktv4, 2);
1802 if (sock->ss.sktv6 != -1)
1803 shutdown(sock->ss.sktv6, 2);
1804 CloseSocketSet(&sock->ss);
1805 sock->fd = -1;
1806
1807 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
1808 }
1809 }
1810
1811 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
1812 {
1813 ssize_t nread = 0;
1814 *closed = mDNSfalse;
1815
1816 if (sock->flags & kTCPSocketFlags_UseTLS)
1817 {
1818 #ifndef NO_SECURITYFRAMEWORK
1819 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
1820 else if (sock->handshake == handshake_in_progress) return 0;
1821 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
1822
1823 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
1824 mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t *)&nread);
1825 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
1826 if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
1827 else if (err && err != errSSLWouldBlock)
1828 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
1829 #else
1830 nread = -1;
1831 *closed = mDNStrue;
1832 #endif /* NO_SECURITYFRAMEWORK */
1833 }
1834 else
1835 {
1836 static int CLOSEDcount = 0;
1837 static int EAGAINcount = 0;
1838 nread = recv(sock->fd, buf, buflen, 0);
1839
1840 if (nread > 0)
1841 {
1842 CLOSEDcount = 0;
1843 EAGAINcount = 0;
1844 } // On success, clear our error counters
1845 else if (nread == 0)
1846 {
1847 *closed = mDNStrue;
1848 if ((++CLOSEDcount % 1000) == 0)
1849 {
1850 LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount);
1851 assert(CLOSEDcount < 1000);
1852 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
1853 // crash mDNSResponder using assert() and restart fresh. See advantages below:
1854 // 1.Better User Experience
1855 // 2.CrashLogs frequency can be monitored
1856 // 3.StackTrace can be used for more info
1857 }
1858 }
1859 // else nread is negative -- see what kind of error we got
1860 else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
1861 else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
1862 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
1863 {
1864 nread = 0;
1865 if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
1866 }
1867 }
1868
1869 return nread;
1870 }
1871
1872 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
1873 {
1874 int nsent;
1875
1876 if (sock->flags & kTCPSocketFlags_UseTLS)
1877 {
1878 #ifndef NO_SECURITYFRAMEWORK
1879 size_t processed;
1880 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
1881 if (sock->handshake == handshake_in_progress) return 0;
1882 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
1883
1884 mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
1885
1886 if (!err) nsent = (int) processed;
1887 else if (err == errSSLWouldBlock) nsent = 0;
1888 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
1889 #else
1890 nsent = -1;
1891 #endif /* NO_SECURITYFRAMEWORK */
1892 }
1893 else
1894 {
1895 nsent = send(sock->fd, msg, len, 0);
1896 if (nsent < 0)
1897 {
1898 if (errno == EAGAIN) nsent = 0;
1899 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
1900 }
1901 }
1902
1903 return nsent;
1904 }
1905
1906 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
1907 {
1908 return sock->fd;
1909 }
1910
1911 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1912 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1913 mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
1914 {
1915 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
1916 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
1917 const int on = 1;
1918 const int twofivefive = 255;
1919 mStatus err = mStatus_NoError;
1920 char *errstr = mDNSNULL;
1921 const int mtu = 0;
1922 int saved_errno;
1923
1924 cp->closeFlag = mDNSNULL;
1925
1926 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
1927 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
1928
1929 // set default traffic class
1930 setTrafficClass(skt, mDNSfalse);
1931
1932 #ifdef SO_RECV_ANYIF
1933 // Enable inbound packets on IFEF_AWDL interface.
1934 // Only done for multicast sockets, since we don't expect unicast socket operations
1935 // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
1936 if (mDNSSameIPPort(port, MulticastDNSPort))
1937 {
1938 err = setsockopt(skt, SOL_SOCKET, SO_RECV_ANYIF, &on, sizeof(on));
1939 if (err < 0) { errstr = "setsockopt - SO_RECV_ANYIF"; goto fail; }
1940 }
1941 #endif // SO_RECV_ANYIF
1942
1943 // ... with a shared UDP port, if it's for multicast receiving
1944 if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort))
1945 {
1946 err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
1947 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
1948 }
1949
1950 // Don't want to wake from sleep for inbound packets on the mDNS sockets
1951 if (mDNSSameIPPort(port, MulticastDNSPort))
1952 {
1953 int nowake = 1;
1954 if (setsockopt(skt, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
1955 LogInfo("SetupSocket: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
1956 }
1957
1958 if (sa_family == AF_INET)
1959 {
1960 // We want to receive destination addresses
1961 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
1962 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
1963
1964 // We want to receive interface identifiers
1965 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
1966 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
1967
1968 // We want to receive packet TTL value so we can check it
1969 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
1970 if (err < 0) { errstr = "setsockopt - IP_RECVTTL"; goto fail; }
1971
1972 // Send unicast packets with TTL 255
1973 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
1974 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
1975
1976 // And multicast packets with TTL 255 too
1977 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
1978 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
1979
1980 // And start listening for packets
1981 struct sockaddr_in listening_sockaddr;
1982 listening_sockaddr.sin_family = AF_INET;
1983 listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
1984 listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0;
1985 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
1986 if (err) { errstr = "bind"; goto fail; }
1987 if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
1988 }
1989 else if (sa_family == AF_INET6)
1990 {
1991 // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
1992 if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; close(skt); return mStatus_NoError; }
1993
1994 // We want to receive destination addresses and receive interface identifiers
1995 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
1996 if (err < 0) { errstr = "setsockopt - IPV6_RECVPKTINFO"; goto fail; }
1997
1998 // We want to receive packet hop count value so we can check it
1999 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
2000 if (err < 0) { errstr = "setsockopt - IPV6_RECVHOPLIMIT"; goto fail; }
2001
2002 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
2003 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
2004 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
2005 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
2006
2007 // Send unicast packets with TTL 255
2008 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
2009 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
2010
2011 // And multicast packets with TTL 255 too
2012 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
2013 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
2014
2015 // Want to receive our own packets
2016 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
2017 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
2018
2019 // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
2020 err = setsockopt(skt, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &mtu, sizeof(mtu));
2021 if (err < 0) // Since it is an optimization if we fail just log the err, no need to close the skt
2022 LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
2023 skt, err, errno, strerror(errno));
2024
2025 // And start listening for packets
2026 struct sockaddr_in6 listening_sockaddr6;
2027 mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
2028 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
2029 listening_sockaddr6.sin6_family = AF_INET6;
2030 listening_sockaddr6.sin6_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
2031 listening_sockaddr6.sin6_flowinfo = 0;
2032 listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
2033 listening_sockaddr6.sin6_scope_id = 0;
2034 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
2035 if (err) { errstr = "bind"; goto fail; }
2036 if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
2037 }
2038
2039 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
2040 fcntl(skt, F_SETFD, 1); // set close-on-exec
2041 *s = skt;
2042 k->KQcallback = myKQSocketCallBack;
2043 k->KQcontext = cp;
2044 k->KQtask = "UDP packet reception";
2045 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2046 k->readSource = mDNSNULL;
2047 k->writeSource = mDNSNULL;
2048 k->fdClosed = mDNSfalse;
2049 #endif
2050 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
2051
2052 return(mStatus_NoError);
2053
2054 fail:
2055 saved_errno = errno;
2056 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
2057 if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
2058 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, saved_errno, strerror(saved_errno));
2059
2060 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
2061 if (!strcmp(errstr, "bind") && saved_errno == EADDRINUSE)
2062 {
2063 err = EADDRINUSE;
2064 if (mDNSSameIPPort(port, MulticastDNSPort))
2065 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
2066 "Congratulations, you've reproduced an elusive bug.\r"
2067 "Please contact the current assignee of <rdar://problem/3814904>.\r"
2068 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2069 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2070 }
2071
2072 mDNSPlatformCloseFD(k, skt);
2073 return(err);
2074 }
2075
2076 mDNSexport UDPSocket *mDNSPlatformUDPSocket(const mDNSIPPort requestedport)
2077 {
2078 mStatus err;
2079 mDNSIPPort port = requestedport;
2080 mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
2081 int i = 10000; // Try at most 10000 times to get a unique random port
2082 UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
2083 if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
2084 mDNSPlatformMemZero(p, sizeof(UDPSocket));
2085 p->ss.port = zeroIPPort;
2086 p->ss.m = &mDNSStorage;
2087 p->ss.sktv4 = -1;
2088 p->ss.sktv6 = -1;
2089 p->ss.proxy = mDNSfalse;
2090
2091 do
2092 {
2093 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
2094 if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
2095 err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
2096 if (!err)
2097 {
2098 err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
2099 if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
2100 }
2101 i--;
2102 } while (err == EADDRINUSE && randomizePort && i);
2103
2104 if (err)
2105 {
2106 // In customer builds we don't want to log failures with port 5351, because this is a known issue
2107 // of failing to bind to this port when Internet Sharing has already bound to it
2108 // We also don't want to log about port 5350, due to a known bug when some other
2109 // process is bound to it.
2110 if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
2111 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2112 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2113 freeL("UDPSocket", p);
2114 return(mDNSNULL);
2115 }
2116 return(p);
2117 }
2118
2119 #ifdef UNIT_TEST
2120 UNITTEST_UDPCLOSE
2121 #else
2122 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
2123 {
2124 CloseSocketSet(&sock->ss);
2125 freeL("UDPSocket", sock);
2126 }
2127 #endif
2128
2129 mDNSexport mDNSBool mDNSPlatformUDPSocketEncounteredEOF(const UDPSocket *sock)
2130 {
2131 return (sock->ss.sktv4EOF || sock->ss.sktv6EOF);
2132 }
2133
2134 #if COMPILER_LIKES_PRAGMA_MARK
2135 #pragma mark -
2136 #pragma mark - BPF Raw packet sending/receiving
2137 #endif
2138
2139 #if APPLE_OSX_mDNSResponder
2140
2141 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
2142 {
2143 if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2144 NetworkInterfaceInfoOSX *info;
2145
2146 info = IfindexToInterfaceInfoOSX(InterfaceID);
2147 if (info == NULL)
2148 {
2149 LogMsg("mDNSPlatformSendRawPacket: Invalid interface index %p", InterfaceID);
2150 return;
2151 }
2152 if (info->BPF_fd < 0)
2153 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
2154 else
2155 {
2156 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
2157 if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
2158 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
2159 }
2160 }
2161
2162 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
2163 {
2164 if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
2165 NetworkInterfaceInfoOSX *info;
2166 info = IfindexToInterfaceInfoOSX(InterfaceID);
2167 if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; }
2168 // Manually inject an entry into our local ARP cache.
2169 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
2170 if (!mDNS_AddressIsLocalSubnet(&mDNSStorage, InterfaceID, tpa))
2171 LogSPS("Don't need address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
2172 else
2173 {
2174 int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b);
2175 if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
2176 else LogSPS("Set local address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
2177 }
2178 }
2179
2180 mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
2181 {
2182 LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
2183 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2184 // close will happen in the cancel handler
2185 dispatch_source_cancel(i->BPF_source);
2186 #else
2187
2188 // Note: MUST NOT close() the underlying native BSD sockets.
2189 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
2190 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
2191 CFRunLoopRemoveSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode);
2192 CFRelease(i->BPF_rls);
2193 CFSocketInvalidate(i->BPF_cfs);
2194 CFRelease(i->BPF_cfs);
2195 #endif
2196 i->BPF_fd = -1;
2197 if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
2198 }
2199
2200 mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
2201 {
2202 KQueueLock();
2203
2204 // 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
2205 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
2206 if (info->BPF_fd < 0) goto exit;
2207
2208 ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
2209 const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
2210 const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
2211 debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
2212
2213 if (n<0)
2214 {
2215 /* <rdar://problem/10287386>
2216 * sometimes there can be a race condition btw when the bpf socket
2217 * gets data and the callback get scheduled and when we call BIOCSETF (which
2218 * clears the socket). this can cause the read to hang for a really long time
2219 * and effectively prevent us from responding to requests for long periods of time.
2220 * to prevent this make the socket non blocking and just bail if we dont get anything
2221 */
2222 if (errno == EAGAIN)
2223 {
2224 LogMsg("bpf_callback got EAGAIN bailing");
2225 goto exit;
2226 }
2227 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
2228 CloseBPF(info);
2229 goto exit;
2230 }
2231
2232 while (ptr < end)
2233 {
2234 const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr;
2235 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
2236 info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen,
2237 ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
2238 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
2239 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
2240 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
2241 mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
2242 ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
2243 }
2244 exit:
2245 KQueueUnlock("bpf_callback");
2246 }
2247 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2248 mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
2249 {
2250 bpf_callback_common(info);
2251 }
2252 #else
2253 mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
2254 {
2255 (void)cfs;
2256 (void)CallBackType;
2257 (void)address;
2258 (void)data;
2259 bpf_callback_common((NetworkInterfaceInfoOSX *)context);
2260 }
2261 #endif
2262
2263 mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
2264 {
2265 LogMsg("mDNSPlatformSendKeepalive called\n");
2266 mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win);
2267 }
2268
2269 mDNSexport mStatus mDNSPlatformClearSPSData(void)
2270 {
2271 CFStringRef spsAddressKey = NULL;
2272 CFStringRef ownerOPTRecKey = NULL;
2273 SCDynamicStoreRef addrStore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SPSAddresses"), NULL, NULL);
2274 SCDynamicStoreRef optStore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SPSOPTRecord"), NULL, NULL);
2275
2276 spsAddressKey = SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyAddress"));
2277 if (spsAddressKey != NULL)
2278 {
2279 CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, spsAddressKey);
2280 if (keyList != NULL)
2281 {
2282 if (SCDynamicStoreSetMultiple(addrStore, NULL, keyList, NULL) == false)
2283 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr( spsAddressKey, kCFStringEncodingASCII), SCErrorString(SCError()));
2284 }
2285 if (keyList) CFRelease(keyList);
2286 }
2287 ownerOPTRecKey= SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyOPTRecord"));
2288 if(ownerOPTRecKey != NULL)
2289 {
2290 CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, ownerOPTRecKey);
2291 if (keyList != NULL)
2292 {
2293 if (SCDynamicStoreSetMultiple(optStore, NULL, keyList, NULL) == false)
2294 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr(ownerOPTRecKey, kCFStringEncodingASCII), SCErrorString(SCError()));
2295 }
2296 if (keyList) CFRelease(keyList);
2297 }
2298
2299 if (addrStore) CFRelease(addrStore);
2300 if (optStore) CFRelease(optStore);
2301 if (spsAddressKey) CFRelease(spsAddressKey);
2302 if (ownerOPTRecKey) CFRelease(ownerOPTRecKey);
2303 return KERN_SUCCESS;
2304 }
2305
2306 mDNSlocal int getMACAddress(int family, v6addr_t raddr, v6addr_t gaddr, int *gfamily, ethaddr_t eth)
2307 {
2308 struct
2309 {
2310 struct rt_msghdr m_rtm;
2311 char m_space[512];
2312 } m_rtmsg;
2313
2314 struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
2315 char *cp = m_rtmsg.m_space;
2316 int seq = 6367, sock, rlen, i;
2317 struct sockaddr_in *sin = NULL;
2318 struct sockaddr_in6 *sin6 = NULL;
2319 struct sockaddr_dl *sdl = NULL;
2320 struct sockaddr_storage sins;
2321 struct sockaddr_dl sdl_m;
2322
2323 #define NEXTADDR(w, s, len) \
2324 if (rtm->rtm_addrs & (w)) \
2325 { \
2326 bcopy((char *)s, cp, len); \
2327 cp += len; \
2328 }
2329
2330 bzero(&sins, sizeof(struct sockaddr_storage));
2331 bzero(&sdl_m, sizeof(struct sockaddr_dl));
2332 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
2333
2334 sock = socket(PF_ROUTE, SOCK_RAW, 0);
2335 if (sock < 0)
2336 {
2337 const int socket_errno = errno;
2338 LogMsg("getMACAddress: Can not open the socket - %s", strerror(socket_errno));
2339 return socket_errno;
2340 }
2341
2342 rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY;
2343 rtm->rtm_type = RTM_GET;
2344 rtm->rtm_flags = 0;
2345 rtm->rtm_version = RTM_VERSION;
2346 rtm->rtm_seq = ++seq;
2347
2348 sdl_m.sdl_len = sizeof(sdl_m);
2349 sdl_m.sdl_family = AF_LINK;
2350 if (family == AF_INET)
2351 {
2352 sin = (struct sockaddr_in*)&sins;
2353 sin->sin_family = AF_INET;
2354 sin->sin_len = sizeof(struct sockaddr_in);
2355 memcpy(&sin->sin_addr, raddr, sizeof(struct in_addr));
2356 NEXTADDR(RTA_DST, sin, sin->sin_len);
2357 }
2358 else if (family == AF_INET6)
2359 {
2360 sin6 = (struct sockaddr_in6 *)&sins;
2361 sin6->sin6_len = sizeof(struct sockaddr_in6);
2362 sin6->sin6_family = AF_INET6;
2363 memcpy(&sin6->sin6_addr, raddr, sizeof(struct in6_addr));
2364 NEXTADDR(RTA_DST, sin6, sin6->sin6_len);
2365 }
2366 NEXTADDR(RTA_GATEWAY, &sdl_m, sdl_m.sdl_len);
2367 rtm->rtm_msglen = rlen = cp - (char *)&m_rtmsg;
2368
2369 if (write(sock, (char *)&m_rtmsg, rlen) < 0)
2370 {
2371 const int write_errno = errno;
2372 LogMsg("getMACAddress: writing to routing socket: %s", strerror(write_errno));
2373 close(sock);
2374 return write_errno;
2375 }
2376
2377 do
2378 {
2379 rlen = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
2380 }
2381 while (rlen > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid()));
2382
2383 if (rlen < 0)
2384 LogMsg("getMACAddress: Read from routing socket failed");
2385
2386 if (family == AF_INET)
2387 {
2388 sin = (struct sockaddr_in *) (rtm + 1);
2389 sdl = (struct sockaddr_dl *) (sin->sin_len + (char *) sin);
2390 }
2391 else if (family == AF_INET6)
2392 {
2393 sin6 = (struct sockaddr_in6 *) (rtm +1);
2394 sdl = (struct sockaddr_dl *) (sin6->sin6_len + (char *) sin6);
2395 }
2396
2397 if (!sdl)
2398 {
2399 LogMsg("getMACAddress: sdl is NULL for family %d", family);
2400 close(sock);
2401 return -1;
2402 }
2403
2404 // If the address is not on the local net, we get the IP address of the gateway.
2405 // We would have to repeat the process to get the MAC address of the gateway
2406 *gfamily = sdl->sdl_family;
2407 if (sdl->sdl_family == AF_INET)
2408 {
2409 if (sin)
2410 {
2411 struct sockaddr_in *new_sin = (struct sockaddr_in *)(sin->sin_len +(char*) sin);
2412 memcpy(gaddr, &new_sin->sin_addr, sizeof(struct in_addr));
2413 }
2414 else
2415 {
2416 LogMsg("getMACAddress: sin is NULL");
2417 }
2418 close(sock);
2419 return -1;
2420 }
2421 else if (sdl->sdl_family == AF_INET6)
2422 {
2423 if (sin6)
2424 {
2425 struct sockaddr_in6 *new_sin6 = (struct sockaddr_in6 *)(sin6->sin6_len +(char*) sin6);
2426 memcpy(gaddr, &new_sin6->sin6_addr, sizeof(struct in6_addr));
2427 }
2428 else
2429 {
2430 LogMsg("getMACAddress: sin6 is NULL");
2431 }
2432 close(sock);
2433 return -1;
2434 }
2435
2436 unsigned char *ptr = (unsigned char *)LLADDR(sdl);
2437 for (i = 0; i < ETHER_ADDR_LEN; i++)
2438 (eth)[i] = *(ptr +i);
2439
2440 close(sock);
2441
2442 return KERN_SUCCESS;
2443 }
2444
2445 mDNSlocal int GetRemoteMacinternal(int family, v6addr_t raddr, ethaddr_t eth)
2446 {
2447 int ret = 0;
2448 v6addr_t gateway;
2449 int gfamily = 0;
2450 int count = 0;
2451
2452 do
2453 {
2454 ret = getMACAddress(family, raddr, gateway, &gfamily, eth);
2455 if (ret == -1)
2456 {
2457 memcpy(raddr, gateway, (gfamily == AF_INET) ? 4 : 16);
2458 family = gfamily;
2459 count++;
2460 }
2461 }
2462 while ((ret == -1) && (count < 5));
2463 return ret;
2464 }
2465
2466 mDNSlocal int StoreSPSMACAddressinternal(int family, v6addr_t spsaddr, const char *ifname)
2467 {
2468 ethaddr_t eth;
2469 char spsip[INET6_ADDRSTRLEN];
2470 int ret = 0;
2471 CFStringRef sckey = NULL;
2472 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL, NULL);
2473 SCDynamicStoreRef ipstore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL, NULL);
2474 CFMutableDictionaryRef dict = NULL;
2475 CFStringRef entityname = NULL;
2476 CFDictionaryRef ipdict = NULL;
2477 CFArrayRef addrs = NULL;
2478
2479 if ((store == NULL) || (ipstore == NULL))
2480 {
2481 LogMsg("StoreSPSMACAddressinternal: Unable to accesss SC Dynamic Store");
2482 ret = -1;
2483 goto fin;
2484 }
2485
2486 // Get the MAC address of the Sleep Proxy Server
2487 memset(eth, 0, sizeof(eth));
2488 ret = GetRemoteMacinternal(family, spsaddr, eth);
2489 if (ret != 0)
2490 {
2491 LogMsg("StoreSPSMACAddressinternal: Failed to determine the MAC address");
2492 goto fin;
2493 }
2494
2495 // Create/Update the dynamic store entry for the specified interface
2496 sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyAddress");
2497 dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2498 if (!dict)
2499 {
2500 LogMsg("StoreSPSMACAddressinternal: SPSCreateDict() Could not create CFDictionary dict");
2501 ret = -1;
2502 goto fin;
2503 }
2504
2505 CFStringRef macaddr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
2506 CFDictionarySetValue(dict, CFSTR("MACAddress"), macaddr);
2507 if (NULL != macaddr)
2508 CFRelease(macaddr);
2509
2510 if( NULL == inet_ntop(family, (void *)spsaddr, spsip, sizeof(spsip)))
2511 {
2512 LogMsg("StoreSPSMACAddressinternal: inet_ntop failed: %s", strerror(errno));
2513 ret = -1;
2514 goto fin;
2515 }
2516
2517 CFStringRef ipaddr = CFStringCreateWithCString(NULL, spsip, kCFStringEncodingUTF8);
2518 CFDictionarySetValue(dict, CFSTR("IPAddress"), ipaddr);
2519 if (NULL != ipaddr)
2520 CFRelease(ipaddr);
2521
2522 // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup
2523 if ((entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/IPv6"), ifname)) != NULL)
2524 {
2525 if ((ipdict = SCDynamicStoreCopyValue(ipstore, entityname)) != NULL)
2526 {
2527 if((addrs = CFDictionaryGetValue(ipdict, CFSTR("Addresses"))) != NULL)
2528 {
2529 addrs = CFRetain(addrs);
2530 CFDictionarySetValue(dict, CFSTR("RegisteredAddresses"), addrs);
2531 }
2532 }
2533 }
2534 SCDynamicStoreSetValue(store, sckey, dict);
2535
2536 fin:
2537 if (store) CFRelease(store);
2538 if (ipstore) CFRelease(ipstore);
2539 if (sckey) CFRelease(sckey);
2540 if (dict) CFRelease(dict);
2541 if (ipdict) CFRelease(ipdict);
2542 if (entityname) CFRelease(entityname);
2543 if (addrs) CFRelease(addrs);
2544
2545 return ret;
2546 }
2547
2548 mDNSlocal void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname)
2549 {
2550 struct
2551 {
2552 v6addr_t saddr;
2553 } addr;
2554 int err = 0;
2555
2556 mDNSPlatformMemCopy(addr.saddr, spsaddr, sizeof(v6addr_t));
2557
2558 err = StoreSPSMACAddressinternal(family, (uint8_t *)addr.saddr, ifname);
2559 if (err != 0)
2560 LogMsg("mDNSStoreSPSMACAddress : failed");
2561 }
2562
2563 mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
2564 {
2565 int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2566
2567 LogInfo("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname);
2568 mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname);
2569
2570 return KERN_SUCCESS;
2571 }
2572
2573
2574 mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage* msg, int length)
2575 {
2576 int ret = 0;
2577 CFStringRef sckey = NULL;
2578 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreOwnerOPTRecord"), NULL, NULL);
2579 CFMutableDictionaryRef dict = NULL;
2580
2581 if (store == NULL)
2582 {
2583 LogMsg("mDNSPlatformStoreOwnerOptRecord: Unable to accesss SC Dynamic Store");
2584 ret = -1;
2585 goto fin;
2586 }
2587
2588 // Create/Update the dynamic store entry for the specified interface
2589 sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyOPTRecord");
2590 dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2591 if (!dict)
2592 {
2593 LogMsg("mDNSPlatformStoreOwnerOptRecord: Could not create CFDictionary dictionary to store OPT Record");
2594 ret =-1;
2595 goto fin;
2596 }
2597
2598 CFDataRef optRec = NULL;
2599 optRec = CFDataCreate(NULL, (const uint8_t *)msg, (CFIndex)length);
2600 CFDictionarySetValue(dict, CFSTR("OwnerOPTRecord"), optRec);
2601 if (NULL != optRec) CFRelease(optRec);
2602
2603 SCDynamicStoreSetValue(store, sckey, dict);
2604
2605 fin:
2606 if (NULL != store) CFRelease(store);
2607 if (NULL != sckey) CFRelease(sckey);
2608 if (NULL != dict) CFRelease(dict);
2609 return ret;
2610 }
2611
2612 mDNSlocal void mDNSGet_RemoteMAC(int family, v6addr_t raddr)
2613 {
2614 ethaddr_t eth;
2615 IPAddressMACMapping *addrMapping;
2616 int kr = KERN_FAILURE;
2617 struct
2618 {
2619 v6addr_t addr;
2620 } dst;
2621
2622 bzero(eth, sizeof(ethaddr_t));
2623 mDNSPlatformMemCopy(dst.addr, raddr, sizeof(v6addr_t));
2624
2625 kr = GetRemoteMacinternal(family, (uint8_t *)dst.addr, eth);
2626
2627 // If the call to get the remote MAC address succeeds, allocate and copy
2628 // the values and schedule a task to update the MAC address in the TCP Keepalive record.
2629 if (kr == 0)
2630 {
2631 addrMapping = mDNSPlatformMemAllocate(sizeof(IPAddressMACMapping));
2632 snprintf(addrMapping->ethaddr, sizeof(addrMapping->ethaddr), "%02x:%02x:%02x:%02x:%02x:%02x",
2633 eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
2634 if (family == AF_INET)
2635 {
2636 addrMapping->ipaddr.type = mDNSAddrType_IPv4;
2637 mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, raddr, sizeof(v6addr_t));
2638 }
2639 else
2640 {
2641 addrMapping->ipaddr.type = mDNSAddrType_IPv6;
2642 mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v6.b, raddr, sizeof(v6addr_t));
2643 }
2644 UpdateRMAC(&mDNSStorage, addrMapping);
2645 }
2646 }
2647
2648 mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr)
2649 {
2650 int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2651
2652 LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC");
2653 mDNSGet_RemoteMAC(family, raddr->ip.v6.b);
2654
2655 return KERN_SUCCESS;
2656 }
2657
2658 mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
2659 {
2660 mDNSs32 intfid;
2661 mDNSs32 error = 0;
2662 int family = (laddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2663
2664 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);
2665 if (error != KERN_SUCCESS)
2666 {
2667 LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error);
2668 return error;
2669 }
2670 mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, intfid);
2671 return error;
2672 }
2673
2674 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2675
2676 mDNSlocal int CountProxyTargets(NetworkInterfaceInfoOSX *x, int *p4, int *p6)
2677 {
2678 int numv4 = 0, numv6 = 0;
2679 AuthRecord *rr;
2680
2681 for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
2682 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2683 {
2684 if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
2685 numv4++;
2686 }
2687
2688 for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
2689 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2690 {
2691 if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
2692 numv6++;
2693 }
2694
2695 if (p4) *p4 = numv4;
2696 if (p6) *p6 = numv6;
2697 return(numv4 + numv6);
2698 }
2699
2700 mDNSexport void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)
2701 {
2702 mDNS *const m = &mDNSStorage;
2703 NetworkInterfaceInfoOSX *x;
2704
2705 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
2706 for (x = m->p->InterfaceList; x; x = x->next) if ((x->ifinfo.InterfaceID == InterfaceID) && (x->BPF_fd >= 0)) break;
2707
2708 if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
2709
2710 #define MAX_BPF_ADDRS 250
2711 int numv4 = 0, numv6 = 0;
2712
2713 if (CountProxyTargets(x, &numv4, &numv6) > MAX_BPF_ADDRS)
2714 {
2715 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
2716 if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
2717 numv6 = MAX_BPF_ADDRS - numv4;
2718 }
2719
2720 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
2721
2722 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
2723 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
2724 static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
2725 {
2726 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13)
2727
2728 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
2729 BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP
2730
2731 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
2732
2733 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
2734 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
2735 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
2736 BPF_STMT(BPF_RET + BPF_K, 86), // 7 Return 86-byte ND
2737
2738 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
2739 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
2740 };
2741
2742 // Special filter program to use when there are no address proxy records
2743 static struct bpf_insn nullfilter[] =
2744 {
2745 BPF_STMT(BPF_RET | BPF_K, 0) // 0 Match no packets and return size 0
2746 };
2747
2748 struct bpf_program prog;
2749 if (!numv4 && !numv6)
2750 {
2751 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
2752 if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
2753
2754 // Cancel any previous ND group memberships we had
2755 if (x->BPF_mcfd >= 0)
2756 {
2757 close(x->BPF_mcfd);
2758 x->BPF_mcfd = -1;
2759 }
2760
2761 // Schedule check to see if we can close this BPF_fd now
2762 if (!m->NetworkChanged) m->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
2763 if (x->BPF_fd < 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
2764 prog.bf_len = 1;
2765 prog.bf_insns = nullfilter;
2766 }
2767 else
2768 {
2769 struct bpf_insn *pc = &filter[9];
2770 struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0"
2771 struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks
2772 struct bpf_insn *ret4 = fail + 1;
2773 struct bpf_insn *ret6 = ret4 + 4;
2774
2775 static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing
2776
2777 static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
2778
2779 static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20)
2780 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)
2781 static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length
2782 static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
2783
2784 static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
2785
2786 BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail
2787 BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check
2788
2789 // BPF Byte-Order Note
2790 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
2791 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
2792 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
2793 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
2794 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
2795 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
2796 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
2797 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
2798 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
2799 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
2800
2801 // IPSEC capture size notes:
2802 // 8 bytes UDP header
2803 // 4 bytes Non-ESP Marker
2804 // 28 bytes IKE Header
2805 // --
2806 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
2807
2808 AuthRecord *rr;
2809 for (rr = m->ResourceRecords; rr; rr=rr->next)
2810 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2811 {
2812 mDNSv4Addr a = rr->AddressProxy.ip.v4;
2813 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2814 BPF_SetOffset(pc, jt, ret4);
2815 pc->jf = 0;
2816 pc->k = (bpf_u_int32)a.b[0] << 24 | (bpf_u_int32)a.b[1] << 16 | (bpf_u_int32)a.b[2] << 8 | (bpf_u_int32)a.b[3];
2817 pc++;
2818 }
2819 *pc++ = rf;
2820
2821 if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
2822 *pc++ = g6; // chk6 points here
2823
2824 // First cancel any previous ND group memberships we had, then create a fresh socket
2825 if (x->BPF_mcfd >= 0) close(x->BPF_mcfd);
2826 x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0);
2827
2828 for (rr = m->ResourceRecords; rr; rr=rr->next)
2829 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2830 {
2831 const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
2832 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2833 BPF_SetOffset(pc, jt, ret6);
2834 pc->jf = 0;
2835 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];
2836 pc++;
2837
2838 struct ipv6_mreq i6mr;
2839 i6mr.ipv6mr_interface = x->scope_id;
2840 i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix;
2841 i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD];
2842 i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE];
2843 i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF];
2844
2845 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
2846 mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
2847 if (err < 0 && (errno != EADDRNOTAVAIL))
2848 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2849
2850 err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
2851 if (err < 0 && (errno != EADDRINUSE)) // Joining same group twice can give "Address already in use" error -- no need to report that
2852 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2853
2854 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
2855 }
2856
2857 if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
2858 *pc++ = rf; // fail points here
2859
2860 if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
2861 *pc++ = r4a; // ret4 points here
2862 *pc++ = r4b;
2863 *pc++ = r4c;
2864 *pc++ = r4d;
2865
2866 if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
2867 *pc++ = r6a; // ret6 points here
2868 #if 0
2869 // For debugging BPF filter program
2870 unsigned int q;
2871 for (q=0; q<prog.bf_len; q++)
2872 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);
2873 #endif
2874 prog.bf_len = (u_int)(pc - filter);
2875 prog.bf_insns = filter;
2876 }
2877
2878 if (ioctl(x->BPF_fd, BIOCSETFNR, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
2879 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog.bf_len);
2880 }
2881
2882 mDNSexport void mDNSPlatformReceiveBPF_fd(int fd)
2883 {
2884 mDNS *const m = &mDNSStorage;
2885 mDNS_Lock(m);
2886
2887 NetworkInterfaceInfoOSX *i;
2888 for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
2889 if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
2890 else
2891 {
2892 LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd);
2893
2894 struct bpf_version v;
2895 if (ioctl(fd, BIOCVERSION, &v) < 0)
2896 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2897 else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
2898 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
2899 fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
2900
2901 if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
2902 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2903
2904 if (i->BPF_len > sizeof(m->imsg))
2905 {
2906 i->BPF_len = sizeof(m->imsg);
2907 if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
2908 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2909 else
2910 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd, i->ifinfo.ifname, i->BPF_len);
2911 }
2912
2913 static const u_int opt_one = 1;
2914 if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0)
2915 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2916
2917 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
2918 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2919
2920 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
2921 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2922
2923 /* <rdar://problem/10287386>
2924 * make socket non blocking see comments in bpf_callback_common for more info
2925 */
2926 if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
2927 {
2928 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2929 }
2930
2931 struct ifreq ifr;
2932 mDNSPlatformMemZero(&ifr, sizeof(ifr));
2933 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
2934 if (ioctl(fd, BIOCSETIF, &ifr) < 0)
2935 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
2936 else
2937 {
2938 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2939 i->BPF_fd = fd;
2940 i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());
2941 if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
2942 dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);});
2943 dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);});
2944 dispatch_resume(i->BPF_source);
2945 #else
2946 CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
2947 i->BPF_fd = fd;
2948 i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
2949 i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
2950 CFRunLoopAddSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode);
2951 #endif
2952 mDNSPlatformUpdateProxyList(i->ifinfo.InterfaceID);
2953 }
2954 }
2955
2956 mDNS_Unlock(m);
2957 }
2958
2959 #endif // APPLE_OSX_mDNSResponder
2960
2961 #if COMPILER_LIKES_PRAGMA_MARK
2962 #pragma mark -
2963 #pragma mark - Key Management
2964 #endif
2965
2966 #ifndef NO_SECURITYFRAMEWORK
2967 mDNSlocal CFArrayRef CopyCertChain(SecIdentityRef identity)
2968 {
2969 CFMutableArrayRef certChain = NULL;
2970 if (!identity) { LogMsg("CopyCertChain: identity is NULL"); return(NULL); }
2971 SecCertificateRef cert;
2972 OSStatus err = SecIdentityCopyCertificate(identity, &cert);
2973 if (err || !cert) LogMsg("CopyCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
2974 else
2975 {
2976 #pragma clang diagnostic push
2977 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2978 SecPolicySearchRef searchRef;
2979 err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
2980 if (err || !searchRef) LogMsg("CopyCertChain: SecPolicySearchCreate() returned %d", (int) err);
2981 else
2982 {
2983 SecPolicyRef policy;
2984 err = SecPolicySearchCopyNext(searchRef, &policy);
2985 if (err || !policy) LogMsg("CopyCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
2986 else
2987 {
2988 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
2989 if (!wrappedCert) LogMsg("CopyCertChain: wrappedCert is NULL");
2990 else
2991 {
2992 SecTrustRef trust;
2993 err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
2994 if (err || !trust) LogMsg("CopyCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
2995 else
2996 {
2997 err = SecTrustEvaluate(trust, NULL);
2998 if (err) LogMsg("CopyCertChain: SecTrustEvaluate() returned %d", (int) err);
2999 else
3000 {
3001 CFArrayRef rawCertChain;
3002 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
3003 err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
3004 if (err || !rawCertChain || !statusChain) LogMsg("CopyCertChain: SecTrustGetResult() returned %d", (int) err);
3005 else
3006 {
3007 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
3008 if (!certChain) LogMsg("CopyCertChain: certChain is NULL");
3009 else
3010 {
3011 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
3012 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
3013 CFArraySetValueAtIndex(certChain, 0, identity);
3014 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
3015 if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
3016 }
3017 CFRelease(rawCertChain);
3018 // Do not free statusChain:
3019 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
3020 // certChain: Call the CFRelease function to release this object when you are finished with it.
3021 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
3022 }
3023 }
3024 CFRelease(trust);
3025 }
3026 CFRelease(wrappedCert);
3027 }
3028 CFRelease(policy);
3029 }
3030 CFRelease(searchRef);
3031 }
3032 #pragma clang diagnostic pop
3033 CFRelease(cert);
3034 }
3035 return certChain;
3036 }
3037 #endif /* NO_SECURITYFRAMEWORK */
3038
3039 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
3040 {
3041 #ifdef NO_SECURITYFRAMEWORK
3042 return mStatus_UnsupportedErr;
3043 #else
3044 SecIdentityRef identity = nil;
3045 SecIdentitySearchRef srchRef = nil;
3046 OSStatus err;
3047
3048 #pragma clang diagnostic push
3049 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3050 // search for "any" identity matching specified key use
3051 // In this app, we expect there to be exactly one
3052 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
3053 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
3054
3055 err = SecIdentitySearchCopyNext(srchRef, &identity);
3056 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
3057 #pragma clang diagnostic pop
3058
3059 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
3060 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
3061
3062 // Found one. Call CopyCertChain to create the correct certificate chain.
3063 ServerCerts = CopyCertChain(identity);
3064 if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: CopyCertChain error"); return mStatus_UnknownErr; }
3065
3066 return mStatus_NoError;
3067 #endif /* NO_SECURITYFRAMEWORK */
3068 }
3069
3070 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
3071 {
3072 #ifndef NO_SECURITYFRAMEWORK
3073 if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
3074 #endif /* NO_SECURITYFRAMEWORK */
3075 }
3076
3077 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
3078 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
3079 {
3080 CFStringEncoding encoding = kCFStringEncodingUTF8;
3081 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
3082 if (cfs)
3083 {
3084 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3085 CFRelease(cfs);
3086 }
3087 }
3088
3089 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
3090 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
3091 {
3092 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
3093 if (cfs)
3094 {
3095 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3096 CFRelease(cfs);
3097 }
3098 }
3099
3100 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
3101 {
3102 mDNSs32 val;
3103 CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
3104 if (!state) return mDNSfalse;
3105 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
3106 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
3107 return val ? mDNStrue : mDNSfalse;
3108 }
3109
3110 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
3111 {
3112 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
3113
3114 if (sa->sa_family == AF_INET)
3115 {
3116 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
3117 ip->type = mDNSAddrType_IPv4;
3118 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
3119 return(mStatus_NoError);
3120 }
3121
3122 if (sa->sa_family == AF_INET6)
3123 {
3124 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
3125 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
3126 // value into the second word of the IPv6 link-local address, so they can just
3127 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
3128 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
3129 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
3130 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
3131 ip->type = mDNSAddrType_IPv6;
3132 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
3133 return(mStatus_NoError);
3134 }
3135
3136 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
3137 return(mStatus_Invalid);
3138 }
3139
3140 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
3141 {
3142 mDNSEthAddr eth = zeroEthAddr;
3143
3144 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
3145 if (entityname)
3146 {
3147 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, entityname);
3148 if (dict)
3149 {
3150 CFRange range = { 0, 6 }; // Offset, length
3151 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
3152 if (data && CFDataGetLength(data) == 6)
3153 CFDataGetBytes(data, range, eth.b);
3154 CFRelease(dict);
3155 }
3156 CFRelease(entityname);
3157 }
3158
3159 return(eth);
3160 }
3161
3162 mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
3163 {
3164 struct ifaddrs *ifa;
3165 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
3166 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
3167 {
3168 const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
3169 if (sdl->sdl_index == ifindex)
3170 { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
3171 }
3172 *eth = zeroEthAddr;
3173 return -1;
3174 }
3175
3176 #ifndef SIOCGIFWAKEFLAGS
3177 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
3178 #endif
3179
3180 #ifndef IF_WAKE_ON_MAGIC_PACKET
3181 #define IF_WAKE_ON_MAGIC_PACKET 0x01
3182 #endif
3183
3184 #ifndef ifr_wake_flags
3185 #define ifr_wake_flags ifr_ifru.ifru_intval
3186 #endif
3187
3188 mDNSlocal
3189 kern_return_t
3190 RegistryEntrySearchCFPropertyAndIOObject( io_registry_entry_t entry,
3191 const io_name_t plane,
3192 CFStringRef keystr,
3193 CFTypeRef * outProperty,
3194 io_registry_entry_t * outEntry)
3195 {
3196 kern_return_t kr;
3197
3198 IOObjectRetain(entry);
3199 while (entry)
3200 {
3201 CFTypeRef ref = IORegistryEntryCreateCFProperty(entry, keystr, kCFAllocatorDefault, mDNSNULL);
3202 if (ref)
3203 {
3204 if (outProperty) *outProperty = ref;
3205 else CFRelease(ref);
3206 break;
3207 }
3208 io_registry_entry_t parent;
3209 kr = IORegistryEntryGetParentEntry(entry, plane, &parent);
3210 if (kr != KERN_SUCCESS) parent = mDNSNULL;
3211 IOObjectRelease(entry);
3212 entry = parent;
3213 }
3214 if (!entry) kr = kIOReturnNoDevice;
3215 else
3216 {
3217 if (outEntry) *outEntry = entry;
3218 else IOObjectRelease(entry);
3219 kr = KERN_SUCCESS;
3220 }
3221 return(kr);
3222 }
3223
3224 mDNSlocal mDNSBool CheckInterfaceSupport(NetworkInterfaceInfo *const intf, const char *key)
3225 {
3226 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
3227 if (!service)
3228 {
3229 LogSPS("CheckInterfaceSupport: No service for interface %s", intf->ifname);
3230 return mDNSfalse;
3231 }
3232
3233 mDNSBool ret = mDNSfalse;
3234
3235 CFStringRef keystr = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
3236 kern_return_t kr = RegistryEntrySearchCFPropertyAndIOObject(service, kIOServicePlane, keystr, mDNSNULL, mDNSNULL);
3237 CFRelease(keystr);
3238 if (kr == KERN_SUCCESS) ret = mDNStrue;
3239 else
3240 {
3241 io_name_t n1;
3242 IOObjectGetClass(service, n1);
3243 LogSPS("CheckInterfaceSupport: No %s for interface %s/%s kr %d", key, intf->ifname, n1, kr);
3244 ret = mDNSfalse;
3245 }
3246
3247 IOObjectRelease(service);
3248 return ret;
3249 }
3250
3251
3252 mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
3253 {
3254 return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
3255 }
3256
3257 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
3258 {
3259 // We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D.
3260 if (!MulticastInterface(i) || (i->ifa_flags & IFF_LOOPBACK) || i->D2DInterface)
3261 {
3262 LogSPS("NetWakeInterface: returning false for %s", i->ifinfo.ifname);
3263 return(mDNSfalse);
3264 }
3265
3266 // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
3267 // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
3268 // when the power source is not AC Power.
3269 if (InterfaceSupportsKeepAlive(&i->ifinfo))
3270 {
3271 LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i->ifinfo.ifname);
3272 return mDNStrue;
3273 }
3274
3275 int s = socket(AF_INET, SOCK_DGRAM, 0);
3276 if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); }
3277
3278 struct ifreq ifr;
3279 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3280 if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
3281 {
3282 const int ioctl_errno = errno;
3283 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
3284 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
3285 // error code is being returned from the kernel, we need to use the kernel version.
3286 #define KERNEL_EOPNOTSUPP 102
3287 if (ioctl_errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
3288 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, ioctl_errno, strerror(ioctl_errno));
3289 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
3290 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
3291 ifr.ifr_wake_flags = (ioctl_errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
3292 }
3293
3294 close(s);
3295
3296 // 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
3297
3298 LogSPS("NetWakeInterface: %-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
3299
3300 return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
3301 }
3302
3303 mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
3304 {
3305 int sockFD;
3306 struct ifreq ifr;
3307
3308 sockFD = socket(AF_INET, SOCK_DGRAM, 0);
3309 if (sockFD < 0)
3310 {
3311 LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno, strerror(errno));
3312 return 0;
3313 }
3314
3315 ifr.ifr_addr.sa_family = AF_INET;
3316 strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
3317
3318 if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
3319 {
3320 LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno));
3321 ifr.ifr_eflags = 0;
3322 }
3323
3324 close(sockFD);
3325 return ifr.ifr_eflags;
3326 }
3327
3328 #if TARGET_OS_OSX
3329 // IFRTYPE_FUNCTIONAL_INTCOPROC type interfaces on macOS do not support Bonjour discovery.
3330 mDNSlocal mDNSBool isCoprocessorInterface(int sockFD, char * ifa_name)
3331 {
3332 struct ifreq ifr;
3333
3334 if (sockFD < 0)
3335 {
3336 LogMsg("isCoprocessorInterface: invalid socket FD passed: %d", sockFD);
3337 return mDNSfalse;
3338 }
3339
3340 memset(&ifr, 0, sizeof(struct ifreq));
3341 strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
3342
3343 if (ioctl(sockFD, SIOCGIFFUNCTIONALTYPE, (caddr_t)&ifr) == -1)
3344 {
3345 LogMsg("isCoprocessorInterface: SIOCGIFFUNCTIONALTYPE failed, errno = %d (%s)", errno, strerror(errno));
3346 return mDNSfalse;
3347 }
3348
3349 if (ifr.ifr_functional_type == IFRTYPE_FUNCTIONAL_INTCOPROC)
3350 {
3351 LogMsg("isCoprocessorInterface: %s marked as coprocessor interface", ifa_name);
3352 return mDNStrue;
3353 }
3354 else
3355 return mDNSfalse;
3356 }
3357
3358 #else // TARGET_OS_OSX
3359 #define isCoprocessorInterface(A, B) mDNSfalse
3360 #endif // TARGET_OS_OSX
3361
3362 #if TARGET_OS_IPHONE
3363
3364 // Function pointers for the routines we use in the MobileWiFi framework.
3365 static WiFiManagerClientRef (*WiFiManagerClientCreate_p)(CFAllocatorRef allocator, WiFiClientType type) = mDNSNULL;
3366 static CFArrayRef (*WiFiManagerClientCopyDevices_p)(WiFiManagerClientRef manager) = mDNSNULL;
3367 static WiFiNetworkRef (*WiFiDeviceClientCopyCurrentNetwork_p)(WiFiDeviceClientRef device) = mDNSNULL;
3368 static bool (*WiFiNetworkIsCarPlay_p)(WiFiNetworkRef network) = mDNSNULL;
3369
3370 mDNSlocal mDNSBool MobileWiFiLibLoad(void)
3371 {
3372 static mDNSBool isInitialized = mDNSfalse;
3373 static void *MobileWiFiLib_p = mDNSNULL;
3374 static const char path[] = "/System/Library/PrivateFrameworks/MobileWiFi.framework/MobileWiFi";
3375
3376 if (!isInitialized)
3377 {
3378 if (!MobileWiFiLib_p)
3379 {
3380 MobileWiFiLib_p = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
3381 if (!MobileWiFiLib_p)
3382 {
3383 LogInfo("MobileWiFiLibLoad: dlopen() failed.");
3384 goto exit;
3385 }
3386 }
3387
3388 if (!WiFiManagerClientCreate_p)
3389 {
3390 WiFiManagerClientCreate_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCreate");
3391 if (!WiFiManagerClientCreate_p)
3392 {
3393 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCreate symbol failed.");
3394 goto exit;
3395 }
3396 }
3397
3398 if (!WiFiManagerClientCopyDevices_p)
3399 {
3400 WiFiManagerClientCopyDevices_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCopyDevices");
3401 if (!WiFiManagerClientCopyDevices_p)
3402 {
3403 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCopyDevices symbol failed.");
3404 goto exit;
3405 }
3406 }
3407
3408 if (!WiFiDeviceClientCopyCurrentNetwork_p)
3409 {
3410 WiFiDeviceClientCopyCurrentNetwork_p = dlsym(MobileWiFiLib_p, "WiFiDeviceClientCopyCurrentNetwork");
3411 if (!WiFiDeviceClientCopyCurrentNetwork_p)
3412 {
3413 LogInfo("MobileWiFiLibLoad: load of WiFiDeviceClientCopyCurrentNetwork symbol failed.");
3414 goto exit;
3415 }
3416 }
3417
3418 if (!WiFiNetworkIsCarPlay_p)
3419 {
3420 WiFiNetworkIsCarPlay_p = dlsym(MobileWiFiLib_p, "WiFiNetworkIsCarPlay");
3421 if (!WiFiNetworkIsCarPlay_p)
3422 {
3423 LogInfo("MobileWiFiLibLoad: load of WiFiNetworkIsCarPlay symbol failed.");
3424 goto exit;
3425 }
3426 }
3427
3428 isInitialized = mDNStrue;
3429 }
3430
3431 exit:
3432 return isInitialized;
3433 }
3434
3435 #define CARPLAY_DEBUG 0
3436
3437 // Return true if the interface is associate to a CarPlay hosted SSID.
3438 // If we have associated with a CarPlay hosted SSID, then use the same
3439 // optimizations that are used when an interface has the IFEF_DIRECTLINK flag set.
3440 mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
3441 {
3442 static WiFiManagerClientRef manager = NULL;
3443 CFArrayRef devices;
3444 WiFiDeviceClientRef device;
3445 WiFiNetworkRef network;
3446 mDNSBool rvalue = mDNSfalse;
3447
3448 if (!MobileWiFiLibLoad())
3449 {
3450 LogInfo("IsCarPlaySSID: MobileWiFiLibLoad() failed!");
3451 return mDNSfalse;
3452 }
3453
3454 // Cache the WiFiManagerClientRef.
3455 if (manager == NULL)
3456 manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
3457
3458 if (manager == NULL)
3459 {
3460 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3461 return mDNSfalse;
3462 }
3463
3464 devices = WiFiManagerClientCopyDevices_p(manager);
3465
3466 // If the first call fails, update the cached WiFiManagerClientRef pointer and try again.
3467 if (devices == NULL)
3468 {
3469 LogInfo("IsCarPlaySSID: First call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
3470
3471 // Release the previously cached WiFiManagerClientRef which is apparently now stale.
3472 CFRelease(manager);
3473 manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
3474 if (manager == NULL)
3475 {
3476 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3477 return mDNSfalse;
3478 }
3479 devices = WiFiManagerClientCopyDevices_p(manager);
3480 if (devices == NULL)
3481 {
3482 LogInfo("IsCarPlaySSID: Second call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
3483 return mDNSfalse;
3484 }
3485 }
3486
3487 device = (WiFiDeviceClientRef)CFArrayGetValueAtIndex(devices, 0);
3488 network = WiFiDeviceClientCopyCurrentNetwork_p(device);
3489 if (network != NULL)
3490 {
3491 if (WiFiNetworkIsCarPlay_p(network))
3492 {
3493 LogInfo("IsCarPlaySSID: %s is CarPlay hosted", ifa_name);
3494 rvalue = mDNStrue;
3495 }
3496 #if CARPLAY_DEBUG
3497 else
3498 LogInfo("IsCarPlaySSID: %s is NOT CarPlay hosted", ifa_name);
3499 #endif // CARPLAY_DEBUG
3500
3501 CFRelease(network);
3502 }
3503 else
3504 LogInfo("IsCarPlaySSID: WiFiDeviceClientCopyCurrentNetwork() returned NULL for %s", ifa_name);
3505
3506 CFRelease(devices);
3507
3508 return rvalue;
3509 }
3510
3511 #else // TARGET_OS_IPHONE
3512
3513 mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
3514 {
3515 (void)ifa_name; // unused
3516
3517 // OSX WifiManager currently does not implement WiFiNetworkIsCarPlay()
3518 return mDNSfalse;;
3519 }
3520
3521 #endif // TARGET_OS_IPHONE
3522
3523 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
3524 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
3525 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
3526 // (e.g. sa_family not AF_INET or AF_INET6)
3527 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(struct ifaddrs *ifa, mDNSs32 utc)
3528 {
3529 mDNS *const m = &mDNSStorage;
3530 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
3531 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
3532 u_int64_t eflags = getExtendedFlags(ifa->ifa_name);
3533
3534 mDNSAddr ip, mask;
3535 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
3536 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
3537
3538 NetworkInterfaceInfoOSX **p;
3539 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
3540 if (scope_id == (*p)->scope_id &&
3541 mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
3542 mDNSSameEthAddress(&bssid, &(*p)->BSSID))
3543 {
3544 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);
3545 // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
3546 // When interfaces are created with same MAC address, kernel resurrects the old interface.
3547 // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
3548 // we get the corresponding name for the interface index on which the packet was received and check against
3549 // the InterfaceList for a matching name. So, keep the name in sync
3550 strlcpy((*p)->ifinfo.ifname, ifa->ifa_name, sizeof((*p)->ifinfo.ifname));
3551
3552 // Determine if multicast state has changed.
3553 const mDNSBool txrx = MulticastInterface(*p);
3554 if ((*p)->ifinfo.McastTxRx != txrx)
3555 {
3556 (*p)->ifinfo.McastTxRx = txrx;
3557 (*p)->Exists = MulticastStateChanged; // State change; need to deregister and reregister this interface
3558 }
3559 else
3560 (*p)->Exists = mDNStrue;
3561
3562 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
3563 if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
3564
3565 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
3566 // we may need to start or stop or sleep proxy browse operation
3567 const mDNSBool NetWake = NetWakeInterface(*p);
3568 if ((*p)->ifinfo.NetWake != NetWake)
3569 {
3570 (*p)->ifinfo.NetWake = NetWake;
3571 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
3572 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
3573 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
3574 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
3575 if ((*p)->Registered)
3576 {
3577 mDNS_Lock(m);
3578 if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo);
3579 else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
3580 mDNS_Unlock(m);
3581 }
3582 }
3583 // Reset the flag if it has changed this time.
3584 (*p)->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
3585
3586 return(*p);
3587 }
3588
3589 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
3590 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
3591 if (!i) return(mDNSNULL);
3592 mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
3593 i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
3594 i->ifinfo.ip = ip;
3595 i->ifinfo.mask = mask;
3596 strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
3597 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
3598 // We can be configured to disable multicast advertisement, but we want to to support
3599 // local-only services, which need a loopback address record.
3600 i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
3601 i->ifinfo.Loopback = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse;
3602 i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
3603
3604 // Setting DirectLink indicates we can do the optimization of skipping the probe phase
3605 // for the interface address records since they should be unique.
3606 // Unfortunately, the legacy p2p* interfaces do not set the IFEF_LOCALNET_PRIVATE
3607 // or IFEF_DIRECTLINK flags, so we have to match against the name.
3608 if ((eflags & (IFEF_DIRECTLINK | IFEF_AWDL)) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0))
3609 i->ifinfo.DirectLink = mDNStrue;
3610 else
3611 i->ifinfo.DirectLink = IsCarPlaySSID(ifa->ifa_name);
3612
3613 if (i->ifinfo.DirectLink)
3614 LogInfo("AddInterfaceToList: DirectLink set for %s", ifa->ifa_name);
3615
3616 i->next = mDNSNULL;
3617 i->m = m;
3618 i->Exists = mDNStrue;
3619 i->Flashing = mDNSfalse;
3620 i->Occulting = mDNSfalse;
3621
3622 i->D2DInterface = ((eflags & IFEF_LOCALNET_PRIVATE) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0)) ? mDNStrue: mDNSfalse;
3623 if (i->D2DInterface)
3624 LogInfo("AddInterfaceToList: D2DInterface set for %s", ifa->ifa_name);
3625
3626 i->isExpensive = (eflags & IFEF_EXPENSIVE) ? mDNStrue: mDNSfalse;
3627 i->isAWDL = (eflags & IFEF_AWDL) ? mDNStrue: mDNSfalse;
3628 if (eflags & IFEF_AWDL)
3629 {
3630 // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
3631 // limited AWDL resources so we don't set the kDNSQClass_UnicastResponse bit in
3632 // Bonjour requests over the AWDL interface.
3633 i->ifinfo.SupportsUnicastMDNSResponse = mDNSfalse;
3634 AWDLInterfaceID = i->ifinfo.InterfaceID;
3635 LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
3636 }
3637 else
3638 {
3639 i->ifinfo.SupportsUnicastMDNSResponse = mDNStrue;
3640 }
3641 i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
3642 i->LastSeen = utc;
3643 i->ifa_flags = ifa->ifa_flags;
3644 i->scope_id = scope_id;
3645 i->BSSID = bssid;
3646 i->sa_family = ifa->ifa_addr->sa_family;
3647 i->BPF_fd = -1;
3648 i->BPF_mcfd = -1;
3649 i->BPF_len = 0;
3650 i->Registered = mDNSNULL;
3651
3652 // MulticastInterface() depends on the "m" and "ifa_flags" values being initialized above.
3653 i->ifinfo.McastTxRx = MulticastInterface(i);
3654 // Do this AFTER i->BSSID has been set up
3655 i->ifinfo.NetWake = (eflags & IFEF_EXPENSIVE)? mDNSfalse : NetWakeInterface(i);
3656 GetMAC(&i->ifinfo.MAC, scope_id);
3657 if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
3658 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
3659
3660 *p = i;
3661 return(i);
3662 }
3663
3664 #if APPLE_OSX_mDNSResponder
3665
3666 #if COMPILER_LIKES_PRAGMA_MARK
3667 #pragma mark -
3668 #pragma mark - AutoTunnel
3669 #endif
3670
3671 #define kRacoonPort 4500
3672
3673 static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
3674
3675 #ifndef NO_SECURITYFRAMEWORK
3676
3677 static CFMutableDictionaryRef domainStatusDict = NULL;
3678
3679 mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
3680 {
3681 if (q->LongLived)
3682 {
3683 if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
3684 return mStatus_NoSuchRecord;
3685 else if (q->state == LLQ_Poll)
3686 return mStatus_PollingMode;
3687 else if (q->state != LLQ_Established && !q->DuplicateOf)
3688 return mStatus_TransientErr;
3689 }
3690
3691 return mStatus_NoError;
3692 }
3693
3694 mDNSlocal mStatus UpdateLLQStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
3695 {
3696 mStatus status = mStatus_NoError;
3697 DNSQuestion* q, *worst_q = mDNSNULL;
3698 for (q = mDNSStorage.Questions; q; q=q->next)
3699 if (q->AuthInfo == info)
3700 {
3701 mStatus newStatus = CheckQuestionForStatus(q);
3702 if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
3703 else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; }
3704 else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
3705 }
3706
3707 if (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success");
3708 else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
3709 else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
3710 else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
3711 return status;
3712 }
3713
3714 mDNSlocal mStatus UpdateRRStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
3715 {
3716 AuthRecord *r;
3717
3718 if (info->deltime) return mStatus_NoError;
3719 for (r = mDNSStorage.ResourceRecords; r; r = r->next)
3720 {
3721 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
3722 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
3723 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
3724 // has already checked
3725 const domainname *n = r->resrec.name;
3726 while (n->c[0])
3727 {
3728 DomainAuthInfo *ptr;
3729 for (ptr = mDNSStorage.AuthInfoList; ptr; ptr = ptr->next)
3730 if (SameDomainName(&ptr->domain, n))
3731 {
3732 if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime))
3733 {
3734 mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
3735 return r->updateError;
3736 }
3737 }
3738 n = (const domainname *)(n->c + 1 + n->c[0]);
3739 }
3740 }
3741 return mStatus_NoError;
3742 }
3743
3744 #endif // ndef NO_SECURITYFRAMEWORK
3745
3746 // MUST be called with lock held
3747 mDNSlocal void UpdateAutoTunnelDomainStatus(const DomainAuthInfo *const info)
3748 {
3749 #ifdef NO_SECURITYFRAMEWORK
3750 (void)info;
3751 #else
3752 // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
3753 // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
3754 mDNS *const m = &mDNSStorage;
3755 const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL;
3756 const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL;
3757 char buffer[1024];
3758 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3759 CFStringRef domain = NULL;
3760 CFStringRef tmp = NULL;
3761 CFNumberRef num = NULL;
3762 mStatus status = mStatus_NoError;
3763 mStatus llqStatus = mStatus_NoError;
3764 char llqBuffer[1024];
3765
3766 mDNS_CheckLock(m);
3767
3768 if (!domainStatusDict)
3769 {
3770 domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3771 if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
3772 }
3773
3774 if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
3775
3776 mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c);
3777 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3778 if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3779
3780 if (info->deltime)
3781 {
3782 if (CFDictionaryContainsKey(domainStatusDict, domain))
3783 {
3784 CFDictionaryRemoveValue(domainStatusDict, domain);
3785 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3786 }
3787 CFRelease(domain);
3788 CFRelease(dict);
3789
3790 return;
3791 }
3792
3793 mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
3794 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3795 if (!tmp)
3796 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
3797 else
3798 {
3799 CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
3800 CFRelease(tmp);
3801 }
3802
3803 if (llq)
3804 {
3805 mDNSu32 port = mDNSVal16(llq->ExternalPort);
3806
3807 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3808 if (!num)
3809 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
3810 else
3811 {
3812 CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
3813 CFRelease(num);
3814 }
3815
3816 if (llq->Result)
3817 {
3818 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
3819 if (!num)
3820 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
3821 else
3822 {
3823 CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
3824 CFRelease(num);
3825 }
3826 }
3827 }
3828
3829 if (tun)
3830 {
3831 mDNSu32 port = mDNSVal16(tun->ExternalPort);
3832
3833 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3834 if (!num)
3835 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
3836 else
3837 {
3838 CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
3839 CFRelease(num);
3840 }
3841
3842 mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress);
3843 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3844 if (!tmp)
3845 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
3846 else
3847 {
3848 CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
3849 CFRelease(tmp);
3850 }
3851
3852 if (tun->Result)
3853 {
3854 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
3855 if (!num)
3856 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
3857 else
3858 {
3859 CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
3860 CFRelease(num);
3861 }
3862 }
3863 }
3864 if (tun || llq)
3865 {
3866 mDNSu32 code = m->LastNATMapResultCode;
3867
3868 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
3869 if (!num)
3870 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
3871 else
3872 {
3873 CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
3874 CFRelease(num);
3875 }
3876 }
3877
3878 mDNS_snprintf(buffer, sizeof(buffer), "Success");
3879 llqStatus = UpdateLLQStatus(llqBuffer, sizeof(llqBuffer), info);
3880 status = UpdateRRStatus(buffer, sizeof(buffer), info);
3881
3882 // If we have a bad signature error updating a RR, it overrides any error as it needs to be
3883 // reported so that it can be fixed automatically (or the user needs to be notified)
3884 if (status != mStatus_NoError)
3885 {
3886 LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer);
3887 }
3888 else if (m->Router.type == mDNSAddrType_None)
3889 {
3890 status = mStatus_NoRouter;
3891 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
3892 }
3893 else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
3894 {
3895 status = mStatus_NoRouter;
3896 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
3897 }
3898 else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress))
3899 {
3900 status = mStatus_ServiceNotRunning;
3901 mDNS_snprintf(buffer, sizeof(buffer), "No inner address");
3902 }
3903 else if (!llq && !tun)
3904 {
3905 status = mStatus_NotInitializedErr;
3906 mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
3907 }
3908 else if (llqStatus == mStatus_NoSuchRecord)
3909 {
3910 status = llqStatus;
3911 mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
3912 }
3913 else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
3914 {
3915 status = mStatus_DoubleNAT;
3916 mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address");
3917 }
3918 else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) ||
3919 (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
3920 (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
3921 {
3922 status = mStatus_NATPortMappingDisabled;
3923 mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router");
3924 }
3925 else if ((llq && llq->Result) || (tun && tun->Result))
3926 {
3927 status = mStatus_NATTraversal;
3928 mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
3929 }
3930 else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
3931 {
3932 status = mStatus_NATTraversal;
3933 mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
3934 }
3935 else
3936 {
3937 status = llqStatus;
3938 mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
3939 LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer);
3940 }
3941
3942 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
3943 if (!num)
3944 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
3945 else
3946 {
3947 CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
3948 CFRelease(num);
3949 }
3950
3951 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3952 if (!tmp)
3953 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
3954 else
3955 {
3956 CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
3957 CFRelease(tmp);
3958 }
3959
3960 if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
3961 !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
3962 {
3963 CFDictionarySetValue(domainStatusDict, domain, dict);
3964 if (!m->ShutdownTime)
3965 {
3966 LogInfo("UpdateAutoTunnelDomainStatus: %s status %d", status ? "failure" : "success", status);
3967 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3968 }
3969 }
3970
3971 CFRelease(domain);
3972 CFRelease(dict);
3973
3974 debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
3975 #endif // def NO_SECURITYFRAMEWORK
3976 }
3977
3978 // MUST be called with lock held
3979 mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
3980 {
3981 #ifdef NO_SECURITYFRAMEWORK
3982 (void) m;
3983 #else
3984 mDNS_CheckLock(m);
3985 DomainAuthInfo* info;
3986 for (info = m->AuthInfoList; info; info = info->next)
3987 if (info->AutoTunnel && !info->deltime)
3988 UpdateAutoTunnelDomainStatus(info);
3989 #endif // def NO_SECURITYFRAMEWORK
3990 }
3991
3992 mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we need racoon to accept incoming connections
3993 {
3994 DomainAuthInfo *info;
3995
3996 for (info = m->AuthInfoList; info; info = info->next)
3997 if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
3998 break;
3999
4000 if (info != AnonymousRacoonConfig)
4001 {
4002 AnonymousRacoonConfig = info;
4003 LogInfo("UpdateAnonymousRacoonConfig need not be done in mDNSResponder");
4004 }
4005 }
4006
4007 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
4008
4009 // Caller must hold the lock
4010 mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record)
4011 {
4012 mDNS_CheckLock(m);
4013
4014 LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c);
4015
4016 if (record->resrec.RecordType > kDNSRecordTypeDeregistering)
4017 {
4018 mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal);
4019 if (err)
4020 {
4021 record->resrec.RecordType = kDNSRecordTypeUnregistered;
4022 LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c);
4023 return mDNSfalse;
4024 }
4025 else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
4026 }
4027 else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType);
4028
4029 return mDNStrue;
4030 }
4031
4032 // Caller must hold the lock
4033 mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
4034 {
4035 if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord))
4036 {
4037 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
4038 m->NextSRVUpdate = NonZeroTime(m->timenow);
4039 }
4040 }
4041
4042 // Caller must hold the lock
4043 mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
4044 {
4045 mStatus err;
4046 mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result;
4047
4048 mDNS_CheckLock(m);
4049
4050 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem))
4051 {
4052 LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
4053 info->domain.c, info->AutoTunnelServiceStarted, info->deltime, &info->AutoTunnelInnerAddress, m->SleepState);
4054 DeregisterAutoTunnelHostRecord(m, info);
4055 }
4056 else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
4057 {
4058 mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
4059 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4060 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
4061 AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
4062 AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
4063 info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = info->AutoTunnelInnerAddress;
4064 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
4065
4066 err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
4067 if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c);
4068 else
4069 {
4070 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
4071 m->NextSRVUpdate = NonZeroTime(m->timenow);
4072 LogInfo("UpdateAutoTunnelHostRecord registering %##s", info->AutoTunnelHostRecord.namestorage.c);
4073 }
4074 }
4075 else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType);
4076 }
4077
4078 // Caller must hold the lock
4079 mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4080 {
4081 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
4082
4083 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget);
4084 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService);
4085 UpdateAutoTunnelHostRecord(m, info);
4086 }
4087
4088 // Caller must hold the lock
4089 mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4090 {
4091 mDNS_CheckLock(m);
4092
4093 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)
4094 {
4095 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);
4096 DeregisterAutoTunnelServiceRecords(m, info);
4097 }
4098 else
4099 {
4100 if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
4101 {
4102 // 1. Set up our address record for the external tunnel address
4103 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
4104 mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL,
4105 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4106 AssignDomainName (&info->AutoTunnelTarget.namestorage, (const domainname*) "\x0B" "_autotunnel");
4107 AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->hostlabel);
4108 AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
4109 info->AutoTunnelTarget.resrec.rdata->u.ipv4 = m->AutoTunnelNAT.ExternalAddress;
4110 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
4111
4112 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelTarget);
4113 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelTarget.namestorage.c);
4114 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelTarget.namestorage.c);
4115 }
4116 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType);
4117
4118 if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
4119 {
4120 // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
4121 mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL,
4122 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4123 AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4124 AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
4125 AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
4126 info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
4127 info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
4128 info->AutoTunnelService.resrec.rdata->u.srv.port = m->AutoTunnelNAT.ExternalPort;
4129 AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
4130 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
4131
4132 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelService);
4133 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelService.namestorage.c);
4134 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelService.namestorage.c);
4135 }
4136 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType);
4137
4138 UpdateAutoTunnelHostRecord(m, info);
4139
4140 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
4141 info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(m->AutoTunnelNAT.IntPort),
4142 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4143
4144 }
4145 }
4146
4147 // Caller must hold the lock
4148 mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4149 {
4150 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo);
4151 }
4152
4153 // Caller must hold the lock
4154 mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4155 {
4156 mDNS_CheckLock(m);
4157
4158 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime)
4159 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4160 else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
4161 {
4162 mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4163 ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
4164
4165 info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data);
4166 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
4167
4168 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
4169 if (err) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
4170 else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info->AutoTunnelDeviceInfo.namestorage.c);
4171 }
4172 else
4173 LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType);
4174 }
4175
4176 // Caller must hold the lock
4177 mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4178 {
4179 LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
4180
4181 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
4182 UpdateAutoTunnelHostRecord(m, info);
4183 UpdateAutoTunnelDomainStatus(info);
4184 }
4185
4186 // Caller must hold the lock
4187 mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4188 {
4189 mDNS_CheckLock(m);
4190
4191 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr) || m->SleepState != SleepState_Awake)
4192 DeregisterAutoTunnel6Record(m, info);
4193 else if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
4194 {
4195 mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
4196 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4197 AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
4198 AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
4199 AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
4200 info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr;
4201 info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
4202
4203 mStatus err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
4204 if (err) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err, info->AutoTunnel6Record.namestorage.c);
4205 else LogInfo("UpdateAutoTunnel6Record registering %##s", info->AutoTunnel6Record.namestorage.c);
4206
4207 UpdateAutoTunnelHostRecord(m, info);
4208
4209 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
4210 info->AutoTunnel6Record.namestorage.c, &m->AutoTunnelRelayAddr,
4211 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4212
4213 }
4214 else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType);
4215 }
4216
4217 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
4218 {
4219 DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
4220 if (result == mStatus_MemFree)
4221 {
4222 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
4223
4224 mDNS_Lock(m);
4225
4226 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
4227 if (rr == &info->AutoTunnelHostRecord)
4228 {
4229 rr->namestorage.c[0] = 0;
4230 m->NextSRVUpdate = NonZeroTime(m->timenow);
4231 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4232 }
4233 if (m->ShutdownTime)
4234 {
4235 LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
4236 mDNS_Unlock(m);
4237 return;
4238 }
4239 if (rr == &info->AutoTunnelHostRecord)
4240 {
4241 LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
4242 UpdateAutoTunnelHostRecord(m,info);
4243 }
4244 else if (rr == &info->AutoTunnelDeviceInfo)
4245 {
4246 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
4247 UpdateAutoTunnelDeviceInfoRecord(m,info);
4248 }
4249 else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
4250 {
4251 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
4252 UpdateAutoTunnelServiceRecords(m,info);
4253 }
4254 else if (rr == &info->AutoTunnel6Record)
4255 {
4256 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
4257 UpdateAutoTunnel6Record(m,info);
4258 }
4259
4260 mDNS_Unlock(m);
4261 }
4262 }
4263
4264 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
4265 {
4266 DomainAuthInfo *info;
4267
4268 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
4269 n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort));
4270
4271 mDNS_Lock(m);
4272
4273 m->NextSRVUpdate = NonZeroTime(m->timenow);
4274 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4275
4276 for (info = m->AuthInfoList; info; info = info->next)
4277 if (info->AutoTunnel)
4278 UpdateAutoTunnelServiceRecords(m, info);
4279
4280 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
4281
4282 UpdateAutoTunnelDomainStatuses(m);
4283
4284 mDNS_Unlock(m);
4285 }
4286
4287 mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
4288 {
4289 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
4290
4291 mDNS_Lock(m);
4292 // We forcibly deregister the records that are based on the hostname.
4293 // When deregistration of each completes, the MemFree callback will make the
4294 // appropriate Update* call to use the new name to reregister.
4295 DeregisterAutoTunnelHostRecord(m, info);
4296 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4297 DeregisterAutoTunnelServiceRecords(m, info);
4298 DeregisterAutoTunnel6Record(m, info);
4299 m->NextSRVUpdate = NonZeroTime(m->timenow);
4300 mDNS_Unlock(m);
4301 }
4302
4303 // Must be called with the lock held
4304 mDNSexport void StartServerTunnel(DomainAuthInfo *const info)
4305 {
4306 mDNS *const m = &mDNSStorage;
4307 if (info->deltime) return;
4308
4309 if (info->AutoTunnelServiceStarted)
4310 {
4311 // On wake from sleep, this function will be called when determining SRV targets,
4312 // and needs to re-register the host record for the target to be set correctly
4313 UpdateAutoTunnelHostRecord(m, info);
4314 return;
4315 }
4316
4317 info->AutoTunnelServiceStarted = mDNStrue;
4318
4319 // Now that we have a service in this domain, we need to try to register the
4320 // AutoTunnel records, because the relay connection & NAT-T may have already been
4321 // started for another domain. If the relay connection is not up or the NAT-T has not
4322 // yet succeeded, the Update* functions are smart enough to not register the records.
4323 // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
4324 // decide whether to register the AutoTunnel records in the calls below.
4325 UpdateAutoTunnelServiceRecords(m, info);
4326 UpdateAutoTunnel6Record(m, info);
4327 UpdateAutoTunnelDeviceInfoRecord(m, info);
4328 UpdateAutoTunnelHostRecord(m, info);
4329
4330 // If the global AutoTunnel NAT-T is not yet started, start it.
4331 if (!m->AutoTunnelNAT.clientContext)
4332 {
4333 m->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
4334 m->AutoTunnelNAT.clientContext = (void*)1; // Means AutoTunnelNAT Traversal is active;
4335 m->AutoTunnelNAT.Protocol = NATOp_MapUDP;
4336 m->AutoTunnelNAT.IntPort = IPSECPort;
4337 m->AutoTunnelNAT.RequestedPort = IPSECPort;
4338 m->AutoTunnelNAT.NATLease = 0;
4339 mStatus err = mDNS_StartNATOperation_internal(m, &m->AutoTunnelNAT);
4340 if (err) LogMsg("StartServerTunnel: error %d starting NAT mapping", err);
4341 }
4342 }
4343
4344 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
4345 {
4346 mDNSv6Addr loc_outer6;
4347 mDNSv6Addr rmt_outer6;
4348
4349 // When we are tunneling over IPv6 Relay address, the port number is zero
4350 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4351 {
4352 loc_outer6 = tun->loc_outer6;
4353 rmt_outer6 = tun->rmt_outer6;
4354 }
4355 else
4356 {
4357 loc_outer6 = zerov6Addr;
4358 loc_outer6.b[0] = tun->loc_outer.b[0];
4359 loc_outer6.b[1] = tun->loc_outer.b[1];
4360 loc_outer6.b[2] = tun->loc_outer.b[2];
4361 loc_outer6.b[3] = tun->loc_outer.b[3];
4362
4363 rmt_outer6 = zerov6Addr;
4364 rmt_outer6.b[0] = tun->rmt_outer.b[0];
4365 rmt_outer6.b[1] = tun->rmt_outer.b[1];
4366 rmt_outer6.b[2] = tun->rmt_outer.b[2];
4367 rmt_outer6.b[3] = tun->rmt_outer.b[3];
4368 }
4369
4370 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)));
4371 }
4372
4373 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
4374 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
4375
4376 mDNSlocal void ReissueBlockedQuestionWithType(domainname *d, mDNSBool success, mDNSu16 qtype)
4377 {
4378 mDNS *const m = &mDNSStorage;
4379 DNSQuestion *q = m->Questions;
4380 while (q)
4381 {
4382 if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
4383 {
4384 LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4385 mDNSQuestionCallback *tmp = q->QuestionCallback;
4386 q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
4387 mDNS_StopQuery(m, q);
4388 mDNS_StartQuery(m, q);
4389 q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
4390 if (!success) q->NoAnswer = NoAnswer_Fail;
4391 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
4392 // In general we have to assume that the question list might have changed in arbitrary ways.
4393 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
4394 // already in use. The safest solution is just to go back to the start of the list and start again.
4395 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
4396 // just one suspended question, so it's really a 2n algorithm.
4397 q = m->Questions;
4398 }
4399 else
4400 q = q->next;
4401 }
4402 }
4403
4404 mDNSlocal void ReissueBlockedQuestions(domainname *d, mDNSBool success)
4405 {
4406 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
4407 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
4408 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
4409 // 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.
4410 // 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.
4411 ReissueBlockedQuestionWithType(d, success, kDNSType_AAAA);
4412 ReissueBlockedQuestionWithType(d, mDNStrue, kDNSType_A);
4413 }
4414
4415 mDNSlocal void UnlinkAndReissueBlockedQuestions(ClientTunnel *tun, mDNSBool success)
4416 {
4417 mDNS *const m = &mDNSStorage;
4418 ClientTunnel **p = &m->TunnelClients;
4419 while (*p != tun && *p) p = &(*p)->next;
4420 if (*p) *p = tun->next;
4421 ReissueBlockedQuestions(&tun->dstname, success);
4422 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
4423 freeL("ClientTunnel", tun);
4424 }
4425
4426 mDNSlocal mDNSBool TunnelClientDeleteMatching(ClientTunnel *tun, mDNSBool v6Tunnel)
4427 {
4428 mDNS *const m = &mDNSStorage;
4429 ClientTunnel **p;
4430 mDNSBool needSetKeys = mDNStrue;
4431
4432 p = &tun->next;
4433 while (*p)
4434 {
4435 // Is this a tunnel to the same host that we are trying to setup now?
4436 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4437 else
4438 {
4439 ClientTunnel *old = *p;
4440 if (v6Tunnel)
4441 {
4442 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4443 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4444 if (old->q.ThisQInterval >= 0)
4445 {
4446 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4447 mDNS_StopQuery(m, &old->q);
4448 }
4449 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4450 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4451 !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
4452 !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
4453 {
4454 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4455 // the other parameters of the tunnel are different
4456 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4457 AutoTunnelSetKeys(old, mDNSfalse);
4458 }
4459 else
4460 {
4461 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4462 // as "tun" and "old" are identical
4463 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
4464 &old->rmt_inner);
4465 needSetKeys = mDNSfalse;
4466 }
4467 }
4468 else
4469 {
4470 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4471 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4472 if (old->q.ThisQInterval >= 0)
4473 {
4474 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4475 mDNS_StopQuery(m, &old->q);
4476 }
4477 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4478 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4479 !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
4480 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
4481 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
4482 {
4483 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4484 // the other parameters of the tunnel are different
4485 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4486 AutoTunnelSetKeys(old, mDNSfalse);
4487 }
4488 else
4489 {
4490 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4491 // as "tun" and "old" are identical
4492 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
4493 &old->rmt_inner);
4494 needSetKeys = mDNSfalse;
4495 }
4496 }
4497
4498 *p = old->next;
4499 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
4500 freeL("ClientTunnel", old);
4501 }
4502 }
4503 return needSetKeys;
4504 }
4505
4506 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
4507 // tunnel will be deleted
4508 mDNSlocal void TunnelClientDeleteAny(ClientTunnel *tun, mDNSBool v6Tunnel)
4509 {
4510 ClientTunnel **p;
4511
4512 p = &tun->next;
4513 while (*p)
4514 {
4515 // If there is more than one client tunnel to the same host, delete all of them.
4516 // We do this by just checking against the EUI64 rather than the full address
4517 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4518 else
4519 {
4520 ClientTunnel *old = *p;
4521 if (v6Tunnel)
4522 {
4523 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4524 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4525 }
4526 else
4527 {
4528 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4529 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4530 }
4531 if (old->q.ThisQInterval >= 0)
4532 {
4533 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4534 mDNS_StopQuery(&mDNSStorage, &old->q);
4535 }
4536 else
4537 {
4538 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4539 AutoTunnelSetKeys(old, mDNSfalse);
4540 }
4541 *p = old->next;
4542 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
4543 freeL("ClientTunnel", old);
4544 }
4545 }
4546 }
4547
4548 mDNSlocal void TunnelClientFinish(DNSQuestion *question, const ResourceRecord *const answer)
4549 {
4550 mDNS *const m = &mDNSStorage;
4551 mDNSBool needSetKeys = mDNStrue;
4552 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4553 mDNSBool v6Tunnel = mDNSfalse;
4554 DomainAuthInfo *info;
4555
4556 // If the port is zero, then we have a relay address of the peer
4557 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4558 v6Tunnel = mDNStrue;
4559
4560 if (v6Tunnel)
4561 {
4562 LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
4563 tun->rmt_outer6 = answer->rdata->u.ipv6;
4564 tun->loc_outer6 = m->AutoTunnelRelayAddr;
4565 }
4566 else
4567 {
4568 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
4569 tun->rmt_outer = answer->rdata->u.ipv4;
4570 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
4571 tmpDst.ip.v4 = tun->rmt_outer;
4572 mDNSAddr tmpSrc = zeroAddr;
4573 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
4574 if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
4575 else tun->loc_outer = m->AdvertisedV4.ip.v4;
4576 }
4577
4578 question->ThisQInterval = -1; // So we know this tunnel setup has completed
4579
4580 info = GetAuthInfoForName(m, &tun->dstname);
4581 if (!info)
4582 {
4583 LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
4584 ReissueBlockedQuestions(&tun->dstname, mDNSfalse);
4585 return;
4586 }
4587
4588 tun->loc_inner = info->AutoTunnelInnerAddress;
4589
4590 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
4591 // look for existing tunnels to see whether they have the same information for our peer.
4592 // If not, delete them and need to create a new tunnel. If they are same, just use the
4593 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
4594 TunnelClientDeleteAny(tun, !v6Tunnel);
4595 needSetKeys = TunnelClientDeleteMatching(tun, v6Tunnel);
4596
4597 if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
4598 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
4599
4600 mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
4601 LogInfo("TunnelClientFinish: Tunnel setup result %d", result);
4602 // Kick off any questions that were held pending this tunnel setup
4603 ReissueBlockedQuestions(&tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
4604 }
4605
4606 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
4607 {
4608 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4609 DomainAuthInfo *info;
4610
4611 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
4612
4613 if (!AddRecord) return;
4614 mDNS_StopQuery(m, question);
4615
4616 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
4617 // The code below will look for _autotunnel._udp SRV record followed by A record
4618 if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
4619 {
4620 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
4621 UnlinkAndReissueBlockedQuestions(tun, mDNSfalse);
4622 return;
4623 }
4624
4625 switch (tun->tc_state)
4626 {
4627 case TC_STATE_AAAA_PEER:
4628 if (question->qtype != kDNSType_AAAA)
4629 {
4630 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
4631 }
4632 info = GetAuthInfoForName(m, &tun->dstname);
4633 if (!info)
4634 {
4635 LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
4636 UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4637 return;
4638 }
4639 if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
4640 {
4641 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
4642 UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4643 return;
4644 }
4645 if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
4646 {
4647 LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6);
4648 UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4649 return;
4650 }
4651 tun->rmt_inner = answer->rdata->u.ipv6;
4652 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
4653 if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
4654 {
4655 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
4656 tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
4657 question->qtype = kDNSType_AAAA;
4658 AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
4659 }
4660 else
4661 {
4662 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
4663 tun->tc_state = TC_STATE_SRV_PEER;
4664 question->qtype = kDNSType_SRV;
4665 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4666 }
4667 AppendDomainName(&question->qname, &tun->dstname);
4668 mDNS_StartQuery(m, &tun->q);
4669 return;
4670 case TC_STATE_AAAA_PEER_RELAY:
4671 if (question->qtype != kDNSType_AAAA)
4672 {
4673 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
4674 }
4675 // If it failed, look for the SRV record.
4676 if (!answer->rdlength)
4677 {
4678 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
4679 tun->tc_state = TC_STATE_SRV_PEER;
4680 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4681 AppendDomainName(&question->qname, &tun->dstname);
4682 question->qtype = kDNSType_SRV;
4683 mDNS_StartQuery(m, &tun->q);
4684 return;
4685 }
4686 TunnelClientFinish(question, answer);
4687 return;
4688 case TC_STATE_SRV_PEER:
4689 if (question->qtype != kDNSType_SRV)
4690 {
4691 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
4692 }
4693 LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
4694 tun->tc_state = TC_STATE_ADDR_PEER;
4695 AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
4696 tun->rmt_outer_port = answer->rdata->u.srv.port;
4697 question->qtype = kDNSType_A;
4698 mDNS_StartQuery(m, &tun->q);
4699 return;
4700 case TC_STATE_ADDR_PEER:
4701 if (question->qtype != kDNSType_A)
4702 {
4703 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
4704 }
4705 TunnelClientFinish(question, answer);
4706 return;
4707 default:
4708 LogMsg("AutoTunnelCallback: Unknown question %p", question);
4709 }
4710 }
4711
4712 // Must be called with the lock held
4713 mDNSexport void AddNewClientTunnel(DNSQuestion *const q)
4714 {
4715 mDNS *const m = &mDNSStorage;
4716 ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
4717 if (!p) return;
4718 AssignDomainName(&p->dstname, &q->qname);
4719 p->MarkedForDeletion = mDNSfalse;
4720 p->loc_inner = zerov6Addr;
4721 p->loc_outer = zerov4Addr;
4722 p->loc_outer6 = zerov6Addr;
4723 p->rmt_inner = zerov6Addr;
4724 p->rmt_outer = zerov4Addr;
4725 p->rmt_outer6 = zerov6Addr;
4726 p->rmt_outer_port = zeroIPPort;
4727 p->tc_state = TC_STATE_AAAA_PEER;
4728 p->next = m->TunnelClients;
4729 m->TunnelClients = p; // We intentionally build list in reverse order
4730
4731 p->q.InterfaceID = mDNSInterface_Any;
4732 p->q.flags = 0;
4733 p->q.Target = zeroAddr;
4734 AssignDomainName(&p->q.qname, &q->qname);
4735 p->q.qtype = kDNSType_AAAA;
4736 p->q.qclass = kDNSClass_IN;
4737 p->q.LongLived = mDNSfalse;
4738 p->q.ExpectUnique = mDNStrue;
4739 p->q.ForceMCast = mDNSfalse;
4740 p->q.ReturnIntermed = mDNStrue;
4741 p->q.SuppressUnusable = mDNSfalse;
4742 p->q.SearchListIndex = 0;
4743 p->q.AppendSearchDomains = 0;
4744 p->q.RetryWithSearchDomains = mDNSfalse;
4745 p->q.TimeoutQuestion = 0;
4746 p->q.WakeOnResolve = 0;
4747 p->q.UseBackgroundTrafficClass = mDNSfalse;
4748 p->q.ValidationRequired = 0;
4749 p->q.ValidatingResponse = 0;
4750 p->q.ProxyQuestion = 0;
4751 p->q.qnameOrig = mDNSNULL;
4752 p->q.AnonInfo = mDNSNULL;
4753 p->q.pid = mDNSPlatformGetPID();
4754 p->q.euid = 0;
4755 p->q.QuestionCallback = AutoTunnelCallback;
4756 p->q.QuestionContext = p;
4757
4758 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
4759 mDNS_StartQuery_internal(m, &p->q);
4760 }
4761
4762 #endif // APPLE_OSX_mDNSResponder
4763
4764 #if COMPILER_LIKES_PRAGMA_MARK
4765 #pragma mark -
4766 #pragma mark - Power State & Configuration Change Management
4767 #endif
4768
4769 mDNSlocal mStatus ReorderInterfaceList()
4770 {
4771 // Disable Reorder lists till <rdar://problem/30071012> is fixed to prevent spurious name conflicts
4772 return (mStatus_NoError);
4773
4774 mDNS *const m = &mDNSStorage;
4775 nwi_state_t state = nwi_state_copy();
4776
4777 if (state == mDNSNULL)
4778 {
4779 LogMsg("NWI State is NULL!");
4780 return (mStatus_Invalid);
4781 }
4782
4783 // Get the count of interfaces
4784 mDNSu32 count = nwi_state_get_interface_names(state, mDNSNULL, 0);
4785 if (count == 0)
4786 {
4787 LogMsg("Unable to get the ordered list of interface names");
4788 nwi_state_release(state);
4789 return (mStatus_Invalid);
4790 }
4791
4792 // Get the ordered interface list
4793 int i;
4794 const char *names[count];
4795 count = nwi_state_get_interface_names(state, names, count);
4796
4797 NetworkInterfaceInfo *newList = mDNSNULL;
4798 for (i = count-1; i >= 0; i--)
4799 { // Build a new ordered interface list
4800 NetworkInterfaceInfo **ptr = &m->HostInterfaces;
4801 while (*ptr != mDNSNULL )
4802 {
4803 if (strcmp((*ptr)->ifname, names[i]) == 0)
4804 {
4805 NetworkInterfaceInfo *node = *ptr;
4806 *ptr = (*ptr)->next;
4807 node->next = newList;
4808 newList = node;
4809 }
4810 else
4811 ptr = &((*ptr)->next);
4812 }
4813 }
4814
4815 // Get to the end of the list
4816 NetworkInterfaceInfo *newListEnd = newList;
4817 while (newListEnd != mDNSNULL && newListEnd->next != mDNSNULL)
4818 newListEnd = newListEnd->next;
4819
4820 // Add any remaing interfaces to the end of the sorted list
4821 if (newListEnd != mDNSNULL)
4822 newListEnd->next = m->HostInterfaces;
4823
4824 // If we have a valid new list, point to that now
4825 if (newList != mDNSNULL)
4826 m->HostInterfaces = newList;
4827
4828 nwi_state_release(state);
4829 return (mStatus_NoError);
4830 }
4831
4832 mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
4833 {
4834 mDNS *const m = &mDNSStorage;
4835 mDNSBool foundav4 = mDNSfalse;
4836 mDNSBool foundav6 = mDNSfalse;
4837 struct ifaddrs *ifa = myGetIfAddrs(0);
4838 struct ifaddrs *v4Loopback = NULL;
4839 struct ifaddrs *v6Loopback = NULL;
4840 char defaultname[64];
4841 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
4842 if (InfoSocket < 3 && errno != EAFNOSUPPORT)
4843 LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
4844
4845 if (m->SleepState == SleepState_Sleeping) ifa = NULL;
4846
4847 while (ifa)
4848 {
4849 #if LIST_ALL_INTERFACES
4850 if (ifa->ifa_addr)
4851 {
4852 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
4853 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
4854 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4855 else if (ifa->ifa_addr->sa_family == AF_LINK)
4856 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
4857 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4858 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
4859 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
4860 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4861 }
4862 else
4863 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X ifa_addr is NOT set",
4864 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags);
4865
4866 if (!(ifa->ifa_flags & IFF_UP))
4867 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
4868 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4869 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4870 if (!(ifa->ifa_flags & IFF_MULTICAST))
4871 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
4872 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4873 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4874 if (ifa->ifa_flags & IFF_POINTOPOINT)
4875 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
4876 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4877 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4878 if (ifa->ifa_flags & IFF_LOOPBACK)
4879 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
4880 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4881 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4882 #endif
4883
4884 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
4885 {
4886 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
4887 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
4888 mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
4889 }
4890
4891 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr && !isCoprocessorInterface(InfoSocket, ifa->ifa_name))
4892 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
4893 {
4894 if (!ifa->ifa_netmask)
4895 {
4896 mDNSAddr ip;
4897 SetupAddr(&ip, ifa->ifa_addr);
4898 LogMsg("UpdateInterfaceList: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
4899 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
4900 }
4901 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
4902 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4903 else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0)
4904 {
4905 mDNSAddr ip;
4906 SetupAddr(&ip, ifa->ifa_addr);
4907 LogMsg("UpdateInterfaceList: ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
4908 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
4909 }
4910 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
4911 else if ((int)if_nametoindex(ifa->ifa_name) <= 0)
4912 {
4913 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
4914 }
4915 else
4916 {
4917 // Make sure ifa_netmask->sa_family is set correctly
4918 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4919 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
4920 int ifru_flags6 = 0;
4921
4922 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
4923 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
4924 {
4925 struct in6_ifreq ifr6;
4926 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
4927 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
4928 ifr6.ifr_addr = *sin6;
4929 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
4930 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
4931 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
4932 }
4933
4934 if (!(ifru_flags6 & (IN6_IFF_TENTATIVE | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
4935 {
4936 if (ifa->ifa_flags & IFF_LOOPBACK)
4937 {
4938 if (ifa->ifa_addr->sa_family == AF_INET)
4939 v4Loopback = ifa;
4940 else if (sin6->sin6_addr.s6_addr[0] != 0xFD)
4941 v6Loopback = ifa;
4942 }
4943 else
4944 {
4945 NetworkInterfaceInfoOSX *i = AddInterfaceToList(ifa, utc);
4946 if (i && MulticastInterface(i) && i->ifinfo.Advertise)
4947 {
4948 if (ifa->ifa_addr->sa_family == AF_INET)
4949 foundav4 = mDNStrue;
4950 else
4951 foundav6 = mDNStrue;
4952 }
4953 }
4954 }
4955 }
4956 }
4957 ifa = ifa->ifa_next;
4958 }
4959
4960 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
4961 if (!foundav4 && v4Loopback) AddInterfaceToList(v4Loopback, utc);
4962 if (!foundav6 && v6Loopback) AddInterfaceToList(v6Loopback, utc);
4963
4964 if (InfoSocket >= 0)
4965 close(InfoSocket);
4966
4967 mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
4968 m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
4969
4970 // Set up the nice label
4971 domainlabel nicelabel;
4972 nicelabel.c[0] = 0;
4973 GetUserSpecifiedFriendlyComputerName(&nicelabel);
4974 if (nicelabel.c[0] == 0)
4975 {
4976 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
4977 MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
4978 }
4979
4980 // Set up the RFC 1034-compliant label
4981 domainlabel hostlabel;
4982 hostlabel.c[0] = 0;
4983 GetUserSpecifiedLocalHostName(&hostlabel);
4984 if (hostlabel.c[0] == 0)
4985 {
4986 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
4987 MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
4988 }
4989
4990 mDNSBool namechange = mDNSfalse;
4991
4992 // We use a case-sensitive comparison here because even though changing the capitalization
4993 // of the name alone is not significant to DNS, it's still a change from the user's point of view
4994 if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
4995 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
4996 else
4997 {
4998 if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
4999 LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
5000 m->p->usernicelabel = m->nicelabel = nicelabel;
5001 namechange = mDNStrue;
5002 }
5003
5004 if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
5005 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
5006 else
5007 {
5008 if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
5009 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
5010 m->p->userhostlabel = m->hostlabel = hostlabel;
5011 mDNS_SetFQDN(m);
5012 namechange = mDNStrue;
5013 }
5014
5015 if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
5016 {
5017 #if APPLE_OSX_mDNSResponder
5018 DomainAuthInfo *info;
5019 for (info = m->AuthInfoList; info; info = info->next)
5020 if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
5021 #endif // APPLE_OSX_mDNSResponder
5022 }
5023
5024 return(mStatus_NoError);
5025 }
5026
5027 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
5028 // Returns -1 if all the one-bits are not contiguous
5029 mDNSlocal int CountMaskBits(mDNSAddr *mask)
5030 {
5031 int i = 0, bits = 0;
5032 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
5033 while (i < bytes)
5034 {
5035 mDNSu8 b = mask->ip.v6.b[i++];
5036 while (b & 0x80) { bits++; b <<= 1; }
5037 if (b) return(-1);
5038 }
5039 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
5040 return(bits);
5041 }
5042
5043 // Returns count of non-link local V4 addresses registered (why? -- SC)
5044 mDNSlocal int SetupActiveInterfaces(mDNSs32 utc)
5045 {
5046 mDNS *const m = &mDNSStorage;
5047 NetworkInterfaceInfoOSX *i;
5048 int count = 0;
5049
5050 // Recalculate SuppressProbes time based on the current set of active interfaces.
5051 m->SuppressProbes = 0;
5052 for (i = m->p->InterfaceList; i; i = i->next)
5053 if (i->Exists)
5054 {
5055 NetworkInterfaceInfo *const n = &i->ifinfo;
5056 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
5057 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
5058
5059 if (i->Registered && i->Registered != primary) // Sanity check
5060 {
5061 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
5062 i->Registered = mDNSNULL;
5063 }
5064
5065 if (!i->Registered)
5066 {
5067 InterfaceActivationSpeed activationSpeed;
5068
5069 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5070 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5071 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it.
5072 i->Registered = primary;
5073
5074 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
5075 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
5076 // 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.
5077 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
5078
5079 // The "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
5080 // every time a new interface is created. We think it is a duplicate and hence consider it
5081 // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
5082 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
5083 // logs a warning message to system.log noting frequent interface transitions.
5084 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
5085 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
5086 {
5087 activationSpeed = FastActivation;
5088 LogInfo("SetupActiveInterfaces: %s DirectLink interface registering", i->ifinfo.ifname);
5089 }
5090 else if (i->Flashing && i->Occulting)
5091 {
5092 activationSpeed = SlowActivation;
5093 }
5094 else
5095 {
5096 activationSpeed = NormalActivation;
5097 }
5098
5099 mDNS_RegisterInterface(m, n, activationSpeed);
5100
5101 if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
5102 LogInfo("SetupActiveInterfaces: Registered %7s(%u) BSSID %.6a Struct addr %p, primary %p, %#a/%d%s%s%s",
5103 i->ifinfo.ifname, i->scope_id, &i->BSSID, i, primary, &n->ip, CountMaskBits(&n->mask),
5104 i->Flashing ? " (Flashing)" : "",
5105 i->Occulting ? " (Occulting)" : "",
5106 n->InterfaceActive ? " (Primary)" : "");
5107
5108 if (!n->McastTxRx)
5109 {
5110 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);
5111 #if TARGET_OS_EMBEDDED
5112 // We join the Bonjour multicast group on Apple embedded platforms ONLY when a client request is active,
5113 // so we leave the multicast group here to clear any residual group membership.
5114 if (i->sa_family == AF_INET)
5115 {
5116 struct ip_mreq imr;
5117 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
5118 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
5119 imr.imr_interface = primary->ifa_v4addr;
5120
5121 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET) == i)
5122 {
5123 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
5124 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
5125 if (err < 0 && (errno != EADDRNOTAVAIL))
5126 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
5127 }
5128 }
5129 if (i->sa_family == AF_INET6)
5130 {
5131 struct ipv6_mreq i6mr;
5132 i6mr.ipv6mr_interface = primary->scope_id;
5133 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
5134
5135 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET6) == i)
5136 {
5137 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IPV6_LEAVE_GROUP for %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5138 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
5139 if (err < 0 && (errno != EADDRNOTAVAIL))
5140 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5141 }
5142 }
5143 #endif // TARGET_OS_EMBEDDED
5144 }
5145 else
5146 {
5147 if (i->sa_family == AF_INET)
5148 {
5149 struct ip_mreq imr;
5150 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
5151 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
5152 imr.imr_interface = primary->ifa_v4addr;
5153
5154 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
5155 // before trying to join the group, to clear out stale kernel state which may be lingering.
5156 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
5157 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
5158 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
5159 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
5160 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
5161 // because by the time we get the configuration change notification, the interface is already gone,
5162 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
5163 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
5164 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET) == i)
5165 {
5166 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);
5167 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
5168 if (err < 0 && (errno != EADDRNOTAVAIL))
5169 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
5170 }
5171
5172 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
5173 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
5174 // Joining same group twice can give "Address already in use" error -- no need to report that
5175 if (err < 0 && (errno != EADDRINUSE))
5176 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
5177 }
5178 if (i->sa_family == AF_INET6)
5179 {
5180 struct ipv6_mreq i6mr;
5181 i6mr.ipv6mr_interface = primary->scope_id;
5182 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
5183
5184 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET6) == i)
5185 {
5186 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);
5187 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
5188 if (err < 0 && (errno != EADDRNOTAVAIL))
5189 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5190 }
5191
5192 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5193 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
5194 // Joining same group twice can give "Address already in use" error -- no need to report that
5195 if (err < 0 && (errno != EADDRINUSE))
5196 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5197 }
5198 }
5199 }
5200 }
5201
5202 return count;
5203 }
5204
5205 mDNSlocal void MarkAllInterfacesInactive(mDNSs32 utc)
5206 {
5207 NetworkInterfaceInfoOSX *i;
5208 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
5209 {
5210 if (i->Exists) i->LastSeen = utc;
5211 i->Exists = mDNSfalse;
5212 }
5213 }
5214
5215 // Returns count of non-link local V4 addresses deregistered (why? -- SC)
5216 mDNSlocal int ClearInactiveInterfaces(mDNSs32 utc)
5217 {
5218 mDNS *const m = &mDNSStorage;
5219 // First pass:
5220 // If an interface is going away, then deregister this from the mDNSCore.
5221 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
5222 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
5223 // it refers to has gone away we'll crash.
5224 NetworkInterfaceInfoOSX *i;
5225 int count = 0;
5226 for (i = m->p->InterfaceList; i; i = i->next)
5227 {
5228 // If this interface is no longer active, or its InterfaceID is changing, deregister it
5229 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
5230 if (i->Registered)
5231 if (i->Exists == 0 || i->Exists == MulticastStateChanged || i->Registered != primary)
5232 {
5233 InterfaceActivationSpeed activationSpeed;
5234
5235 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
5236 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5237 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary,
5238 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
5239 i->Flashing ? " (Flashing)" : "",
5240 i->Occulting ? " (Occulting)" : "",
5241 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5242
5243 // "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
5244 // every time it creates a new interface. We think it is a duplicate and hence consider it
5245 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
5246 // stale data returned to the application even after the interface is removed. The application
5247 // then starts to send data but the new interface is not yet created.
5248 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
5249 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
5250 {
5251 activationSpeed = FastActivation;
5252 LogInfo("ClearInactiveInterfaces: %s DirectLink interface deregistering", i->ifinfo.ifname);
5253 }
5254 else if (i->Flashing && i->Occulting)
5255 {
5256 activationSpeed = SlowActivation;
5257 }
5258 else
5259 {
5260 activationSpeed = NormalActivation;
5261 }
5262 mDNS_DeregisterInterface(m, &i->ifinfo, activationSpeed);
5263
5264 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
5265 i->Registered = mDNSNULL;
5266 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5267 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5268 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
5269
5270 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
5271 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
5272 }
5273 }
5274
5275 // Second pass:
5276 // Now that everything that's going to deregister has done so, we can clean up and free the memory
5277 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
5278 while (*p)
5279 {
5280 i = *p;
5281 // If no longer active, delete interface from list and free memory
5282 if (!i->Exists)
5283 {
5284 if (i->LastSeen == utc) i->LastSeen = utc - 1;
5285 const mDNSBool delete = (i->isAWDL || (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0)) && (utc - i->LastSeen >= 60);
5286 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
5287 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
5288 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
5289 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5290 #if APPLE_OSX_mDNSResponder
5291 if (i->BPF_fd >= 0) CloseBPF(i);
5292 #endif // APPLE_OSX_mDNSResponder
5293 if (delete)
5294 {
5295 *p = i->next;
5296 freeL("NetworkInterfaceInfoOSX", i);
5297 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
5298 }
5299 }
5300 p = &i->next;
5301 }
5302 return count;
5303 }
5304
5305 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
5306 {
5307 DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
5308 if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
5309 else
5310 {
5311 dnle->next = mDNSNULL;
5312 dnle->uid = uid;
5313 AssignDomainName(&dnle->name, name);
5314 **List = dnle;
5315 *List = &dnle->next;
5316 }
5317 }
5318
5319 mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
5320 {
5321 dns_resolver_t *a = *(dns_resolver_t**)aa;
5322 dns_resolver_t *b = *(dns_resolver_t**)bb;
5323
5324 return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
5325 }
5326
5327 mDNSlocal void UpdateSearchDomainHash(MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID)
5328 {
5329 mDNS *const m = &mDNSStorage;
5330 char *buf = ".";
5331 mDNSu32 scopeid = 0;
5332 char ifid_buf[16];
5333
5334 if (domain)
5335 buf = domain;
5336 //
5337 // Hash the search domain name followed by the InterfaceID.
5338 // As we have scoped search domains, we also included InterfaceID. If either of them change,
5339 // we will detect it. Even if the order of them change, we will detect it.
5340 //
5341 // Note: We have to handle a few of these tricky cases.
5342 //
5343 // 1) Current: com, apple.com Changing to: comapple.com
5344 // 2) Current: a.com,b.com Changing to a.comb.com
5345 // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
5346 // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
5347 //
5348 // There are more variants of the above. The key thing is if we include the null in each case
5349 // at the end of name and the InterfaceID, it will prevent a new name (which can't include
5350 // NULL as part of the name) to be mistakenly thought of as a old name.
5351
5352 scopeid = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
5353 // mDNS_snprintf always null terminates
5354 if (mDNS_snprintf(ifid_buf, sizeof(ifid_buf), "%u", scopeid) >= sizeof(ifid_buf))
5355 LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid);
5356
5357 LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf, ifid_buf);
5358 MD5_Update(sdc, buf, strlen(buf) + 1);
5359 MD5_Update(sdc, ifid_buf, strlen(ifid_buf) + 1);
5360 }
5361
5362 mDNSlocal void FinalizeSearchDomainHash(MD5_CTX *sdc)
5363 {
5364 mDNS *const m = &mDNSStorage;
5365 mDNSu8 md5_hash[MD5_LEN];
5366
5367 MD5_Final(md5_hash, sdc);
5368
5369 if (memcmp(md5_hash, m->SearchDomainsHash, MD5_LEN))
5370 {
5371 // If the hash is different, either the search domains have changed or
5372 // the ordering between them has changed. Restart the questions that
5373 // would be affected by this.
5374 LogInfo("FinalizeSearchDomains: The hash is different");
5375 memcpy(m->SearchDomainsHash, md5_hash, MD5_LEN);
5376 RetrySearchDomainQuestions(m);
5377 }
5378 else { LogInfo("FinalizeSearchDomains: The hash is same"); }
5379 }
5380
5381 mDNSexport const char *DNSScopeToString(mDNSu32 scope)
5382 {
5383 switch (scope)
5384 {
5385 case kScopeNone:
5386 return "Unscoped";
5387 case kScopeInterfaceID:
5388 return "InterfaceScoped";
5389 case kScopeServiceID:
5390 return "ServiceScoped";
5391 default:
5392 return "Unknown";
5393 }
5394 }
5395
5396 mDNSlocal void ConfigSearchDomains(dns_resolver_t *resolver, mDNSInterfaceID interfaceId, mDNSu32 scope, MD5_CTX *sdc, uint64_t generation)
5397 {
5398 const char *scopeString = DNSScopeToString(scope);
5399 int j;
5400 domainname d;
5401
5402 if (scope == kScopeNone)
5403 interfaceId = mDNSInterface_Any;
5404
5405 if (scope == kScopeNone || scope == kScopeInterfaceID)
5406 {
5407 for (j = 0; j < resolver->n_search; j++)
5408 {
5409 if (MakeDomainNameFromDNSNameString(&d, resolver->search[j]) != NULL)
5410 {
5411 char interface_buf[32];
5412 mDNS_snprintf(interface_buf, sizeof(interface_buf), "for interface %s", InterfaceNameForID(&mDNSStorage, interfaceId));
5413 LogInfo("ConfigSearchDomains: (%s) configuring search domain %s %s (generation= %llu)", scopeString,
5414 resolver->search[j], (interfaceId == mDNSInterface_Any) ? "" : interface_buf, generation);
5415 UpdateSearchDomainHash(sdc, resolver->search[j], interfaceId);
5416 mDNS_AddSearchDomain_CString(resolver->search[j], interfaceId);
5417 }
5418 else
5419 {
5420 LogInfo("ConfigSearchDomains: An invalid search domain was detected for %s domain %s n_nameserver %d, (generation= %llu)",
5421 DNSScopeToString(scope), resolver->domain, resolver->n_nameserver, generation);
5422 }
5423 }
5424 }
5425 else
5426 {
5427 LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString, InterfaceNameForID(&mDNSStorage, interfaceId));
5428 }
5429 }
5430
5431 mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNSu32 ifindex)
5432 {
5433 NetworkInterfaceInfoOSX *ni;
5434 mDNSInterfaceID interface;
5435
5436 for (ni = mDNSStorage.p->InterfaceList; ni; ni = ni->next)
5437 {
5438 if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex)
5439 break;
5440 }
5441 if (ni != NULL)
5442 {
5443 interface = ni->ifinfo.InterfaceID;
5444 }
5445 else
5446 {
5447 // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
5448 // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
5449 // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
5450 // As the caller is going to ack the configuration always, we have to add all the DNS servers
5451 // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
5452
5453 LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex);
5454
5455 // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
5456 interface = (mDNSInterfaceID)(unsigned long)ifindex;
5457 }
5458 return interface;
5459 }
5460
5461 mDNSlocal void ConfigNonUnicastResolver(dns_resolver_t *r)
5462 {
5463 char *opt = r->options;
5464 domainname d;
5465
5466 if (opt && !strncmp(opt, "mdns", strlen(opt)))
5467 {
5468 if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5469 {
5470 LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain);
5471 return;
5472 }
5473 mDNS_AddMcastResolver(&mDNSStorage, &d, mDNSInterface_Any, r->timeout);
5474 }
5475 }
5476
5477 #if !defined(NWI_IFSTATE_FLAGS_HAS_CLAT46)
5478 #define NWI_IFSTATE_FLAGS_HAS_CLAT46 0x0040
5479 #endif
5480
5481 mDNSlocal mDNSBool NWIInterfaceHasCLAT46(nwi_state_t state, uint32_t ifIndex)
5482 {
5483 char ifNameBuf[IFNAMSIZ + 1];
5484 const char *ifNamePtr = if_indextoname(ifIndex, ifNameBuf);
5485 if (!ifNamePtr) return(mDNSfalse);
5486
5487 const nwi_ifstate_t ifState = nwi_state_get_ifstate(state, ifNamePtr);
5488 if (!ifState) return(mDNSfalse);
5489
5490 const nwi_ifstate_flags flags = nwi_ifstate_get_flags(ifState);
5491 return((flags & NWI_IFSTATE_FLAGS_HAS_CLAT46) ? mDNStrue : mDNSfalse);
5492 }
5493
5494 mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu32 resGroupID)
5495 {
5496 int n;
5497 domainname d;
5498 int serviceID = 0;
5499 mDNSBool cellIntf = mDNSfalse;
5500 mDNSBool reqA, reqAAAA;
5501 NetworkInterfaceInfoOSX *info;
5502 mDNSBool isExpensive;
5503 mDNSBool isCLAT46;
5504
5505 if (!r->domain || !*r->domain)
5506 {
5507 d.c[0] = 0;
5508 }
5509 else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5510 {
5511 LogMsg("ConfigDNSServers: bad domain %s", r->domain);
5512 return;
5513 }
5514 // Parse the resolver specific attributes that affects all the DNS servers.
5515 if (scope == kScopeServiceID)
5516 {
5517 serviceID = r->service_identifier;
5518 }
5519
5520 #if TARGET_OS_IPHONE
5521 cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
5522 #endif
5523 reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse);
5524 reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
5525 info = IfindexToInterfaceInfoOSX(interface);
5526 isExpensive = (info && info->isExpensive) ? mDNStrue : mDNSfalse;
5527 if (mDNSStorage.p->NWIState && interface)
5528 {
5529 const uint32_t ifIndex = (uint32_t)((uintptr_t)interface);
5530 isCLAT46 = NWIInterfaceHasCLAT46(mDNSStorage.p->NWIState, ifIndex);
5531 }
5532 else
5533 {
5534 isCLAT46 = mDNSfalse;
5535 }
5536
5537 for (n = 0; n < r->n_nameserver; n++)
5538 {
5539 mDNSAddr saddr;
5540 DNSServer *s;
5541
5542 if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6)
5543 continue;
5544
5545 if (SetupAddr(&saddr, r->nameserver[n]))
5546 {
5547 LogMsg("ConfigDNSServers: Bad address");
5548 continue;
5549 }
5550
5551 // The timeout value is for all the DNS servers in a given resolver, hence we pass
5552 // the timeout value only for the first DNSServer. If we don't have a value in the
5553 // resolver, then use the core's default value
5554 //
5555 // Note: this assumes that when the core picks a list of DNSServers for a question,
5556 // it takes the sum of all the timeout values for all DNS servers. By doing this, it
5557 // tries all the DNS servers in a specified timeout
5558 s = mDNS_AddDNSServer(&mDNSStorage, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope,
5559 (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, isExpensive, isCLAT46,
5560 resGroupID, reqA, reqAAAA, mDNStrue);
5561 if (s)
5562 {
5563 LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c);
5564 }
5565 }
5566 }
5567
5568 // ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
5569 // Service scope resolvers. This is indicated by the scope argument.
5570 //
5571 // "resolver" has entries that should only be used for unscoped questions.
5572 //
5573 // "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
5574 // interface index (q->InterfaceID)
5575 //
5576 // "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
5577 // a service identifier (q->ServiceID)
5578 //
5579 mDNSlocal void ConfigResolvers(dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc)
5580 {
5581 int i;
5582 dns_resolver_t **resolver;
5583 int nresolvers;
5584 const char *scopeString = DNSScopeToString(scope);
5585 mDNSInterfaceID interface;
5586
5587 switch (scope)
5588 {
5589 case kScopeNone:
5590 resolver = config->resolver;
5591 nresolvers = config->n_resolver;
5592 break;
5593 case kScopeInterfaceID:
5594 resolver = config->scoped_resolver;
5595 nresolvers = config->n_scoped_resolver;
5596 break;
5597 case kScopeServiceID:
5598 resolver = config->service_specific_resolver;
5599 nresolvers = config->n_service_specific_resolver;
5600 break;
5601 default:
5602 return;
5603 }
5604 qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
5605
5606 for (i = 0; i < nresolvers; i++)
5607 {
5608 dns_resolver_t *r = resolver[i];
5609
5610 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString, i, r->domain, r->n_nameserver);
5611
5612 interface = mDNSInterface_Any;
5613
5614 // Parse the interface index
5615 if (r->if_index != 0)
5616 {
5617 interface = ConfigParseInterfaceID(r->if_index);
5618 }
5619
5620 if (setsearch)
5621 {
5622 ConfigSearchDomains(resolver[i], interface, scope, sdc, config->generation);
5623
5624 // Parse other scoped resolvers for search lists
5625 if (!setservers)
5626 continue;
5627 }
5628
5629 if (r->port == 5353 || r->n_nameserver == 0)
5630 {
5631 ConfigNonUnicastResolver(r);
5632 }
5633 else
5634 {
5635 ConfigDNSServers(r, interface, scope, mDNS_GetNextResolverGroupID());
5636 }
5637 }
5638 }
5639
5640 #if APPLE_OSX_mDNSResponder
5641 mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
5642 {
5643 if (QuerySuppressed(q))
5644 {
5645 debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5646 return mDNSfalse;
5647 }
5648 if (mDNSOpaque16IsZero(q->TargetQID))
5649 {
5650 debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5651 return mDNSfalse;
5652 }
5653 // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
5654 // for trigger.
5655 if (q->LOAddressAnswers)
5656 {
5657 debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5658 return mDNSfalse;
5659 }
5660 return mDNStrue;
5661 }
5662 #endif
5663
5664 // This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
5665 // We set our state appropriately so that if we start receiving answers, trigger the
5666 // upper layer to retry DNS questions.
5667 #if APPLE_OSX_mDNSResponder
5668 mDNSexport void mDNSPlatformUpdateDNSStatus(DNSQuestion *q)
5669 {
5670 mDNS *const m = &mDNSStorage;
5671 if (!QuestionValidForDNSTrigger(q))
5672 return;
5673
5674 // Ignore applications that start and stop queries for no reason before we ever talk
5675 // to any DNS server.
5676 if (!q->triedAllServersOnce)
5677 {
5678 LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q->qname.c, DNSTypeName(q->qtype));
5679 return;
5680 }
5681 if (q->qtype == kDNSType_A)
5682 m->p->v4answers = 0;
5683 if (q->qtype == kDNSType_AAAA)
5684 m->p->v6answers = 0;
5685 if (!m->p->v4answers || !m->p->v6answers)
5686 {
5687 LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, question %##s (%s)", m->p->v4answers, m->p->v6answers, q->qname.c,
5688 DNSTypeName(q->qtype));
5689 }
5690 }
5691 #endif
5692
5693 mDNSlocal void AckConfigd(dns_config_t *config)
5694 {
5695 mDNS_CheckLock(&mDNSStorage);
5696
5697 // Acking the configuration triggers configd to reissue the reachability queries
5698 mDNSStorage.p->DNSTrigger = NonZeroTime(mDNSStorage.timenow);
5699 _dns_configuration_ack(config, "com.apple.mDNSResponder");
5700 }
5701
5702 // If v4q is non-NULL, it means we have received some answers for "A" type questions
5703 // If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
5704 #if APPLE_OSX_mDNSResponder
5705 mDNSexport void mDNSPlatformTriggerDNSRetry(DNSQuestion *v4q, DNSQuestion *v6q)
5706 {
5707 mDNS *const m = &mDNSStorage;
5708 mDNSBool trigger = mDNSfalse;
5709 mDNSs32 timenow;
5710
5711 // Don't send triggers too often.
5712 // If we have started delivering answers to questions, we should send a trigger
5713 // if the time permits. If we are delivering answers, we should set the state
5714 // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know
5715 // whether the answers that are being delivered currently is for configd or some
5716 // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
5717 // then we won't deliver the trigger later when it is okay to send one as the
5718 // "answers" are already set to 1. Hence, don't affect the state of v4answers and
5719 // v6answers if we are not delivering triggers.
5720 mDNS_Lock(m);
5721 timenow = m->timenow;
5722 if (m->p->DNSTrigger && (timenow - m->p->DNSTrigger) < DNS_TRIGGER_INTERVAL)
5723 {
5724 if (!m->p->v4answers || !m->p->v6answers)
5725 {
5726 debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
5727 (timenow - m->p->DNSTrigger), m->p->v4answers, m->p->v6answers);
5728 }
5729 mDNS_Unlock(m);
5730 return;
5731 }
5732 mDNS_Unlock(m);
5733 if (v4q != NULL && QuestionValidForDNSTrigger(v4q))
5734 {
5735 int old = m->p->v4answers;
5736
5737 m->p->v4answers = 1;
5738
5739 // If there are IPv4 answers now and previously we did not have
5740 // any answers, trigger a DNS change so that reachability
5741 // can retry the queries again.
5742 if (!old)
5743 {
5744 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
5745 v4q->qname.c, DNSTypeName(v4q->qtype));
5746 trigger = mDNStrue;
5747 }
5748 }
5749 if (v6q != NULL && QuestionValidForDNSTrigger(v6q))
5750 {
5751 int old = m->p->v6answers;
5752
5753 m->p->v6answers = 1;
5754 // If there are IPv6 answers now and previously we did not have
5755 // any answers, trigger a DNS change so that reachability
5756 // can retry the queries again.
5757 if (!old)
5758 {
5759 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
5760 v6q->qname.c, DNSTypeName(v6q->qtype));
5761 trigger = mDNStrue;
5762 }
5763 }
5764 if (trigger)
5765 {
5766 dns_config_t *config = dns_configuration_copy();
5767 if (config)
5768 {
5769 mDNS_Lock(m);
5770 AckConfigd(config);
5771 mDNS_Unlock(m);
5772 dns_configuration_free(config);
5773 }
5774 else
5775 {
5776 LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
5777 }
5778 }
5779 }
5780
5781 mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
5782 {
5783 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
5784 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
5785 if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver &&
5786 config->resolver[0]->nameserver[0])
5787 {
5788 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
5789 }
5790 else
5791 {
5792 ActiveDirectoryPrimaryDomain.c[0] = 0;
5793 }
5794
5795 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
5796 ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
5797 if (config->n_resolver && config->resolver[0]->n_nameserver &&
5798 SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
5799 {
5800 SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
5801 }
5802 else
5803 {
5804 AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
5805 ActiveDirectoryPrimaryDomainLabelCount = 0;
5806 ActiveDirectoryPrimaryDomainServer = zeroAddr;
5807 }
5808 }
5809 #endif
5810
5811 mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
5812 {
5813 int i;
5814 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NULL
5815 domainname d;
5816
5817 CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_DynamicDNS);
5818 if (ddnsdict)
5819 {
5820 if (fqdn)
5821 {
5822 CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
5823 if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
5824 {
5825 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
5826 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
5827 if (fqdnDict && DictionaryIsEnabled(fqdnDict))
5828 {
5829 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
5830 if (name)
5831 {
5832 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5833 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
5834 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
5835 else
5836 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
5837 }
5838 }
5839 }
5840 }
5841 if (RegDomains)
5842 {
5843 CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
5844 if (regArray && CFArrayGetCount(regArray) > 0)
5845 {
5846 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
5847 if (regDict && DictionaryIsEnabled(regDict))
5848 {
5849 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
5850 if (name)
5851 {
5852 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5853 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
5854 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
5855 else
5856 {
5857 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
5858 AppendDNameListElem(&RegDomains, 0, &d);
5859 }
5860 }
5861 }
5862 }
5863 }
5864 if (BrowseDomains)
5865 {
5866 CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
5867 if (browseArray)
5868 {
5869 for (i = 0; i < CFArrayGetCount(browseArray); i++)
5870 {
5871 CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
5872 if (browseDict && DictionaryIsEnabled(browseDict))
5873 {
5874 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
5875 if (name)
5876 {
5877 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5878 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
5879 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
5880 else
5881 {
5882 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
5883 AppendDNameListElem(&BrowseDomains, 0, &d);
5884 }
5885 }
5886 }
5887 }
5888 }
5889 }
5890 CFRelease(ddnsdict);
5891 }
5892 #if MDNSRESPONDER_BTMM_SUPPORT
5893 if (RegDomains)
5894 {
5895 CFDictionaryRef btmm = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BackToMyMac);
5896 if (btmm)
5897 {
5898 CFIndex size = CFDictionaryGetCount(btmm);
5899 const void *key[size];
5900 const void *val[size];
5901 CFDictionaryGetKeysAndValues(btmm, key, val);
5902 for (i = 0; i < size; i++)
5903 {
5904 LogInfo("BackToMyMac %d", i);
5905 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
5906 LogMsg("Can't read BackToMyMac %d key %s", i, buf);
5907 else
5908 {
5909 mDNSu32 uid = atoi(buf);
5910 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
5911 LogMsg("Can't read BackToMyMac %d val %s", i, buf);
5912 else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
5913 {
5914 LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
5915 AppendDNameListElem(&RegDomains, uid, &d);
5916 }
5917 }
5918 }
5919 CFRelease(btmm);
5920 }
5921 }
5922 #endif
5923 }
5924
5925 // Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
5926 mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
5927 DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
5928 {
5929 mDNS *const m = &mDNSStorage;
5930 MD5_CTX sdc; // search domain context
5931
5932 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
5933 if (fqdn ) fqdn->c[0] = 0;
5934 if (RegDomains ) *RegDomains = NULL;
5935 if (BrowseDomains) *BrowseDomains = NULL;
5936
5937 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
5938 setservers ? " setservers" : "",
5939 setsearch ? " setsearch" : "",
5940 fqdn ? " fqdn" : "",
5941 RegDomains ? " RegDomains" : "",
5942 BrowseDomains ? " BrowseDomains" : "");
5943
5944 if (setsearch) MD5_Init(&sdc);
5945
5946 // Add the inferred address-based configuration discovery domains
5947 // (should really be in core code I think, not platform-specific)
5948 if (setsearch)
5949 {
5950 struct ifaddrs *ifa = mDNSNULL;
5951 struct sockaddr_in saddr;
5952 mDNSPlatformMemZero(&saddr, sizeof(saddr));
5953 saddr.sin_len = sizeof(saddr);
5954 saddr.sin_family = AF_INET;
5955 saddr.sin_port = 0;
5956 saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
5957
5958 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
5959 if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1);
5960
5961 while (ifa)
5962 {
5963 mDNSAddr a, n;
5964 char buf[64];
5965
5966 if (ifa->ifa_addr->sa_family == AF_INET &&
5967 ifa->ifa_netmask &&
5968 !(ifa->ifa_flags & IFF_LOOPBACK) &&
5969 !SetupAddr(&a, ifa->ifa_addr) &&
5970 !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
5971 {
5972 // 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
5973 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5974 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; // Make sure ifa_netmask->sa_family is set correctly
5975 SetupAddr(&n, ifa->ifa_netmask);
5976 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
5977 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
5978 a.ip.v4.b[2] & n.ip.v4.b[2],
5979 a.ip.v4.b[1] & n.ip.v4.b[1],
5980 a.ip.v4.b[0] & n.ip.v4.b[0]);
5981 UpdateSearchDomainHash(&sdc, buf, NULL);
5982 mDNS_AddSearchDomain_CString(buf, mDNSNULL);
5983 }
5984 ifa = ifa->ifa_next;
5985 }
5986 }
5987
5988 #ifndef MDNS_NO_DNSINFO
5989 if (setservers || setsearch)
5990 {
5991 dns_config_t *config = dns_configuration_copy();
5992 if (!config)
5993 {
5994 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
5995 // Apparently this is expected behaviour -- "not a bug".
5996 // Accordingly, we suppress syslog messages for the first three minutes after boot.
5997 // If we are still getting failures after three minutes, then we log them.
5998 if ((mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
5999 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
6000 }
6001 else
6002 {
6003 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config->n_resolver, config->generation, m->p->LastConfigGeneration);
6004
6005 // For every network change, mDNSPlatformSetDNSConfig is called twice. First,
6006 // to update the search domain list (in which case, the setsearch bool is set);
6007 // and second, to update the DNS server list (in which case, the setservers bool
6008 // is set). The code assumes only one of these flags, setsearch or setserver,
6009 // will be set when mDNSPlatformSetDNSConfig is called to handle a network change.
6010 // The mDNSPlatformSetDNSConfig function also assumes that ackCfg will be set
6011 // when setservers is set.
6012
6013 // The search domains update occurs on every network change to avoid sync issues
6014 // that may occur if a network change happens during the processing
6015 // of a network change. The dns servers update occurs when the DNS config
6016 // changes. The dns servers stay in sync by saving the config's generation number
6017 // on every update; and only updating when the generation number changes.
6018
6019 // If this is a DNS server update and the configuration hasn't changed, then skip update
6020 if (setservers && m->p->LastConfigGeneration == config->generation)
6021 {
6022 LogInfo("mDNSPlatformSetDNSConfig(setservers): generation number %llu same, not processing", config->generation);
6023 dns_configuration_free(config);
6024 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6025 return mDNSfalse;
6026 }
6027 #if APPLE_OSX_mDNSResponder
6028 SetupActiveDirectoryDomain(config);
6029 #endif
6030
6031 ConfigResolvers(config, kScopeNone, setsearch, setservers, &sdc);
6032 ConfigResolvers(config, kScopeInterfaceID, setsearch, setservers, &sdc);
6033 ConfigResolvers(config, kScopeServiceID, setsearch, setservers, &sdc);
6034
6035 // Acking provides a hint to other processes that the current DNS configuration has completed
6036 // its update. When configd receives the ack, it publishes a notification.
6037 // Applications monitoring the notification then know when to re-issue their DNS queries
6038 // after a network change occurs.
6039 if (ackConfig)
6040 {
6041 // Note: We have to set the generation number here when we are acking.
6042 // For every DNS configuration change, we do the following:
6043 //
6044 // 1) Copy dns configuration, handle search domains change
6045 // 2) Copy dns configuration, handle dns server change
6046 //
6047 // If we update the generation number at step (1), we won't process the
6048 // DNS servers the second time because generation number would be the same.
6049 // As we ack only when we process dns servers, we set the generation number
6050 // during acking.
6051 m->p->LastConfigGeneration = config->generation;
6052 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers, setsearch);
6053 AckConfigd(config);
6054 }
6055 dns_configuration_free(config);
6056 if (setsearch) FinalizeSearchDomainHash(&sdc);
6057 }
6058 }
6059 #endif // MDNS_NO_DNSINFO
6060 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6061 return mDNStrue;
6062 }
6063
6064
6065 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
6066 {
6067 char buf[256];
6068
6069 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_IPv4);
6070 if (dict)
6071 {
6072 r->type = mDNSAddrType_IPv4;
6073 r->ip.v4 = zerov4Addr;
6074 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
6075 if (string)
6076 {
6077 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
6078 LogMsg("Could not convert router to CString");
6079 else
6080 {
6081 struct sockaddr_in saddr;
6082 saddr.sin_len = sizeof(saddr);
6083 saddr.sin_family = AF_INET;
6084 saddr.sin_port = 0;
6085 inet_aton(buf, &saddr.sin_addr);
6086 *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
6087 }
6088 }
6089 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
6090 if (string)
6091 {
6092 mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
6093 struct ifaddrs *ifa = myGetIfAddrs(1);
6094 *v4 = *v6 = zeroAddr;
6095
6096 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
6097 {
6098 LogMsg("Could not convert router to CString");
6099 goto exit;
6100 }
6101 // find primary interface in list
6102 while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
6103 {
6104 if (!ifa->ifa_addr)
6105 {
6106 LogMsg("Skip interface, %s, since ifa_addr is not set.", (ifa->ifa_name) ? ifa->ifa_name: "name not found");
6107 ifa = ifa->ifa_next;
6108 continue;
6109 }
6110 mDNSAddr tmp6 = zeroAddr;
6111 if (!strcmp(buf, ifa->ifa_name))
6112 {
6113 if (ifa->ifa_addr->sa_family == AF_INET)
6114 {
6115 if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4))
6116 SetupAddr(v4, ifa->ifa_addr);
6117 }
6118 else if (ifa->ifa_addr->sa_family == AF_INET6)
6119 {
6120 SetupAddr(&tmp6, ifa->ifa_addr);
6121 if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
6122 {
6123 HavePrimaryGlobalv6 = mDNStrue;
6124 *v6 = tmp6;
6125 }
6126 }
6127 }
6128 else
6129 {
6130 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
6131 if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
6132 {
6133 SetupAddr(&tmp6, ifa->ifa_addr);
6134 if (tmp6.ip.v6.b[0] >> 5 == 1)
6135 *v6 = tmp6;
6136 }
6137 }
6138 ifa = ifa->ifa_next;
6139 }
6140 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
6141 // V4 to communicate w/ our DNS server
6142 }
6143
6144 exit:
6145 CFRelease(dict);
6146 }
6147 return mStatus_NoError;
6148 }
6149
6150 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
6151 {
6152 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
6153 char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6154 ConvertDomainNameToCString(dname, uname);
6155
6156 char *p = uname;
6157 while (*p)
6158 {
6159 *p = tolower(*p);
6160 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
6161 p++;
6162 }
6163
6164 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
6165 // That single entity is a CFDictionary with name "HostNames".
6166 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
6167 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
6168 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
6169 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
6170 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
6171
6172 const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
6173 const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
6174 const CFStringRef StatusKeys[1] = { CFSTR("Status") };
6175 if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
6176 else
6177 {
6178 const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
6179 if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
6180 else
6181 {
6182 const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6183 if (HostVals[0])
6184 {
6185 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6186 if (StateVals[0])
6187 {
6188 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6189 if (StateDict)
6190 {
6191 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
6192 CFRelease(StateDict);
6193 }
6194 CFRelease(StateVals[0]);
6195 }
6196 CFRelease(HostVals[0]);
6197 }
6198 CFRelease(StatusVals[0]);
6199 }
6200 CFRelease(HostKeys[0]);
6201 }
6202 }
6203
6204 #if MDNSRESPONDER_BTMM_SUPPORT
6205 #if !NO_AWACS
6206
6207 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
6208 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
6209 // help catch it
6210 mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
6211 {
6212 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
6213 if (!store)
6214 {
6215 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6216 return mDNSfalse;
6217 }
6218 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
6219 if (btmm)
6220 {
6221 CFIndex size = CFDictionaryGetCount(btmm);
6222 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6223 const void *key[size];
6224 const void *val[size];
6225 domainname dom;
6226 int i;
6227 CFDictionaryGetKeysAndValues(btmm, key, val);
6228 for (i = 0; i < size; i++)
6229 {
6230 LogInfo("BackToMyMac %d", i);
6231 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6232 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
6233 else
6234 {
6235 mDNSu32 uid = atoi(buf);
6236 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6237 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
6238 else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
6239 {
6240 if (SameDomainName(&dom, d))
6241 {
6242 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
6243 CFRelease(btmm);
6244 CFRelease(store);
6245 return mDNStrue;
6246 }
6247 }
6248 }
6249 }
6250 CFRelease(btmm);
6251 }
6252 CFRelease(store);
6253 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
6254 return mDNSfalse;
6255 }
6256
6257 // Appends data to the buffer
6258 mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
6259 {
6260 int len;
6261
6262 len = strlcpy(buf + *currlen, data, bufsz - *currlen);
6263 if (len >= (bufsz - *currlen))
6264 {
6265 // if we have exceeded the space in buf, it has already been NULL terminated
6266 // and we have nothing more to do. Set currlen to the last byte so that the caller
6267 // knows to do the right thing
6268 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
6269 *currlen = bufsz - 1;
6270 return -1;
6271 }
6272 else { (*currlen) += len; }
6273
6274 buf[*currlen] = ',';
6275 if (*currlen >= bufsz)
6276 {
6277 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
6278 *currlen = bufsz - 1;
6279 buf[*currlen] = 0;
6280 return -1;
6281 }
6282 // if we have filled up the buffer exactly, then there is no more work to do
6283 if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
6284 (*currlen)++;
6285 return *currlen;
6286 }
6287
6288 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
6289 // BTMM domains, then bring down the connection to the relay.
6290 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6291 {
6292 DomainAuthInfo *BTMMDomain = mDNSNULL;
6293 DomainAuthInfo *FoundInList;
6294 static mDNSBool AWACSDConnected = mDNSfalse;
6295 char AllUsers[1024]; // maximum size of mach message
6296 char AllPass[1024]; // maximum size of mach message
6297 char username[MAX_DOMAIN_LABEL + 1];
6298 int currulen = 0;
6299 int currplen = 0;
6300
6301 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
6302 // we may not be able to send the dns queries over the relay connection which may be needed
6303 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
6304 // need to make sure that we send the disconnect before attempting the next connect as the
6305 // awacs connections are redirected based on usernames.
6306 //
6307 // For now we send a disconnect immediately. When we start sending dns queries over the relay
6308 // connection, we will need to fix this.
6309
6310 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6311 if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
6312 {
6313 // We need the passwd from the first domain.
6314 BTMMDomain = FoundInList;
6315 ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
6316 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
6317 if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
6318 if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
6319 }
6320
6321 if (BTMMDomain)
6322 {
6323 // In the normal case (where we neither exceed the buffer size nor write bytes that
6324 // fit exactly into the buffer), currulen/currplen should be a different size than
6325 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
6326
6327 if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
6328 if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
6329
6330 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
6331 AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
6332 AWACSDConnected = mDNStrue;
6333 }
6334 else
6335 {
6336 // Disconnect only if we connected previously
6337 if (AWACSDConnected)
6338 {
6339 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
6340 AWACS_Disconnect();
6341 AWACSDConnected = mDNSfalse;
6342 }
6343 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
6344 }
6345 }
6346 #else
6347 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6348 {
6349 (void) m; // Unused
6350 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
6351 }
6352 #endif // ! NO_AWACS
6353
6354 mDNSlocal void ProcessConndConfigChanges(void);
6355
6356 #endif // MDNSRESPONDER_BTMM_SUPPORT
6357
6358 // MUST be called holding the lock
6359 mDNSlocal void SetDomainSecrets_internal(mDNS *m)
6360 {
6361 #ifdef NO_SECURITYFRAMEWORK
6362 (void) m;
6363 LogMsg("Note: SetDomainSecrets: no keychain support");
6364 #else
6365 mDNSBool haveAutoTunnels = mDNSfalse;
6366
6367 LogInfo("SetDomainSecrets");
6368
6369 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
6370 // In the case where the user simultaneously removes their DDNS host name and the key
6371 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
6372 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
6373 // address records behind that we no longer have permission to delete.
6374 DomainAuthInfo *ptr;
6375 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
6376 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
6377
6378 #if APPLE_OSX_mDNSResponder
6379 {
6380 // Mark all TunnelClients for deletion
6381 ClientTunnel *client;
6382 for (client = m->TunnelClients; client; client = client->next)
6383 {
6384 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
6385 client->MarkedForDeletion = mDNStrue;
6386 }
6387 }
6388 #endif // APPLE_OSX_mDNSResponder
6389
6390 // String Array used to write list of private domains to Dynamic Store
6391 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6392 if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
6393 CFIndex i;
6394 CFDataRef data = NULL;
6395 const int itemsPerEntry = 4; // domain name, key name, key value, Name value
6396 CFArrayRef secrets = NULL;
6397 int err = mDNSKeychainGetSecrets(&secrets);
6398 if (err || !secrets)
6399 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
6400 else
6401 {
6402 CFIndex ArrayCount = CFArrayGetCount(secrets);
6403 // Iterate through the secrets
6404 for (i = 0; i < ArrayCount; ++i)
6405 {
6406 mDNSBool AutoTunnel;
6407 int j, offset;
6408 CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
6409 if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
6410 { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i, itemsPerEntry); continue; }
6411 for (j = 0; j < CFArrayGetCount(entry); ++j)
6412 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
6413 { LogMsg("SetDomainSecrets: malformed entry item %d", j); continue; }
6414
6415 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
6416
6417 // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
6418 // Get DNS domain this key is for (kmDNSKcWhere)
6419 char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(btmmprefix)];
6420 data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere);
6421 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6422 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
6423 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6424 stringbuf[CFDataGetLength(data)] = '\0';
6425
6426 AutoTunnel = mDNSfalse;
6427 offset = 0;
6428 if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
6429 offset = strlen(dnsprefix);
6430 #if MDNSRESPONDER_BTMM_SUPPORT
6431 else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix)))
6432 {
6433 AutoTunnel = mDNStrue;
6434 offset = strlen(btmmprefix);
6435 }
6436 #endif
6437 domainname domain;
6438 if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
6439
6440 // Get key name (kmDNSKcAccount)
6441 data = CFArrayGetValueAtIndex(entry, kmDNSKcAccount);
6442 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6443 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
6444 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
6445 stringbuf[CFDataGetLength(data)] = '\0';
6446
6447 domainname keyname;
6448 if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
6449
6450 // Get key data (kmDNSKcKey)
6451 data = CFArrayGetValueAtIndex(entry, kmDNSKcKey);
6452 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6453 {
6454 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data));
6455 continue;
6456 }
6457 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6458 stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
6459
6460 // Get the Name of the keychain entry (kmDNSKcName) host or host:port
6461 // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
6462 char hostbuf[MAX_ESCAPED_DOMAIN_NAME + 6]; // Max legal domainname as C-string, including terminating NUL
6463 data = CFArrayGetValueAtIndex(entry, kmDNSKcName);
6464 if (CFDataGetLength(data) >= (int)sizeof(hostbuf))
6465 {
6466 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data));
6467 continue;
6468 }
6469 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)hostbuf);
6470 hostbuf[CFDataGetLength(data)] = '\0';
6471
6472 domainname hostname;
6473 mDNSIPPort port;
6474 char *hptr;
6475 hptr = strchr(hostbuf, ':');
6476
6477 port.NotAnInteger = 0;
6478 if (hptr)
6479 {
6480 mDNSu8 *p;
6481 mDNSu16 val = 0;
6482
6483 *hptr++ = '\0';
6484 while(hptr && *hptr != 0)
6485 {
6486 if (*hptr < '0' || *hptr > '9')
6487 { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr, val); val = 0; break;}
6488 val = val * 10 + *hptr - '0';
6489 hptr++;
6490 }
6491 if (!val) continue;
6492 p = (mDNSu8 *)&val;
6493 port.NotAnInteger = p[0] << 8 | p[1];
6494 }
6495 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
6496 hptr = strchr(hostbuf, '@');
6497 if (hptr)
6498 hptr++;
6499 else
6500 hptr = hostbuf;
6501 if (!MakeDomainNameFromDNSNameString(&hostname, hptr)) { LogMsg("SetDomainSecrets: bad host name %s", hptr); continue; }
6502
6503 DomainAuthInfo *FoundInList;
6504 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6505 if (SameDomainName(&FoundInList->domain, &domain)) break;
6506
6507 #if APPLE_OSX_mDNSResponder
6508 if (FoundInList)
6509 {
6510 // If any client tunnel destination is in this domain, set deletion flag to false
6511 ClientTunnel *client;
6512 for (client = m->TunnelClients; client; client = client->next)
6513 if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
6514 {
6515 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
6516 client->MarkedForDeletion = mDNSfalse;
6517 }
6518 }
6519
6520 #endif // APPLE_OSX_mDNSResponder
6521
6522 // Uncomment the line below to view the keys as they're read out of the system keychain
6523 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
6524 //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]));
6525 LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain.c, &keyname.c, hostname.c, (port.b[0] << 8 | port.b[1]));
6526
6527 // If didn't find desired domain in the list, make a new entry
6528 ptr = FoundInList;
6529 if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
6530 if (!FoundInList)
6531 {
6532 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
6533 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
6534 }
6535
6536 //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
6537
6538 // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
6539 if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port, AutoTunnel) == mStatus_BadParamErr)
6540 {
6541 if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
6542 continue;
6543 }
6544
6545 ConvertDomainNameToCString(&domain, stringbuf);
6546 CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
6547 if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
6548 }
6549 CFRelease(secrets);
6550 }
6551
6552 if (!privateDnsArray || !CFEqual(privateDnsArray, sa))
6553 {
6554 if (privateDnsArray)
6555 CFRelease(privateDnsArray);
6556
6557 privateDnsArray = sa;
6558 CFRetain(privateDnsArray);
6559 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
6560 }
6561 CFRelease(sa);
6562
6563 #if APPLE_OSX_mDNSResponder
6564 {
6565 // clean up ClientTunnels
6566 ClientTunnel **pp = &m->TunnelClients;
6567 while (*pp)
6568 {
6569 if ((*pp)->MarkedForDeletion)
6570 {
6571 ClientTunnel *cur = *pp;
6572 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
6573 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
6574 AutoTunnelSetKeys(cur, mDNSfalse);
6575 *pp = cur->next;
6576 freeL("ClientTunnel", cur);
6577 }
6578 else
6579 pp = &(*pp)->next;
6580 }
6581
6582 mDNSBool needAutoTunnelNAT = mDNSfalse;
6583 DomainAuthInfo *info;
6584 for (info = m->AuthInfoList; info; info = info->next)
6585 {
6586 if (info->AutoTunnel)
6587 {
6588 UpdateAutoTunnelDeviceInfoRecord(m, info);
6589 UpdateAutoTunnelHostRecord(m, info);
6590 UpdateAutoTunnelServiceRecords(m, info);
6591 UpdateAutoTunnel6Record(m, info);
6592 if (info->deltime)
6593 {
6594 if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse;
6595 }
6596 else if (info->AutoTunnelServiceStarted)
6597 needAutoTunnelNAT = true;
6598
6599 UpdateAutoTunnelDomainStatus(info);
6600 }
6601 }
6602
6603 // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
6604 if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext)
6605 {
6606 // stop the NAT operation, reset port, cleanup state
6607 mDNS_StopNATOperation_internal(m, &m->AutoTunnelNAT);
6608 m->AutoTunnelNAT.ExternalAddress = zerov4Addr;
6609 m->AutoTunnelNAT.NewAddress = zerov4Addr;
6610 m->AutoTunnelNAT.ExternalPort = zeroIPPort;
6611 m->AutoTunnelNAT.RequestedPort = zeroIPPort;
6612 m->AutoTunnelNAT.Lifetime = 0;
6613 m->AutoTunnelNAT.Result = mStatus_NoError;
6614 m->AutoTunnelNAT.clientContext = mDNSNULL;
6615 }
6616
6617 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
6618 #if MDNSRESPONDER_BTMM_SUPPORT
6619 ProcessConndConfigChanges(); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
6620 #endif
6621 }
6622 #endif // APPLE_OSX_mDNSResponder
6623
6624 CheckSuppressUnusableQuestions(m);
6625
6626 #endif /* NO_SECURITYFRAMEWORK */
6627 }
6628
6629 mDNSexport void SetDomainSecrets(mDNS *m)
6630 {
6631 #if DEBUG
6632 // Don't get secrets for BTMM if running in debug mode
6633 if (!IsDebugSocketInUse())
6634 #endif
6635 SetDomainSecrets_internal(m);
6636 }
6637
6638 mDNSlocal void SetLocalDomains(void)
6639 {
6640 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6641 if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
6642
6643 CFArrayAppendValue(sa, CFSTR("local"));
6644 CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
6645 CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
6646 CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
6647 CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
6648 CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
6649
6650 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
6651 CFRelease(sa);
6652 }
6653
6654 mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
6655 {
6656
6657 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_PowerSettings);
6658 if (!dict)
6659 {
6660 LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
6661 }
6662 else
6663 {
6664 CFNumberRef number = CFDictionaryGetValue(dict, name);
6665 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
6666 *val = 0;
6667 CFRelease(dict);
6668 }
6669
6670 }
6671
6672 #if APPLE_OSX_mDNSResponder
6673
6674 static CFMutableDictionaryRef spsStatusDict = NULL;
6675 static const CFStringRef kMetricRef = CFSTR("Metric");
6676
6677 mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
6678 {
6679 mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
6680 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
6681 if (!num)
6682 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
6683 else
6684 {
6685 CFDictionarySetValue(dict, key, num);
6686 CFRelease(num);
6687 }
6688 }
6689
6690 mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
6691 {
6692 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6693 if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
6694
6695 char buffer[1024];
6696 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
6697 CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
6698 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
6699 CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
6700 CFRelease(spsname);
6701
6702 if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
6703 if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
6704 if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
6705 if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
6706
6707 mDNSu32 tmp = SPSMetric(ptr);
6708 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
6709 if (!num)
6710 LogMsg("SPSCreateDict: Could not create CFNumber");
6711 else
6712 {
6713 CFDictionarySetValue(dict, kMetricRef, num);
6714 CFRelease(num);
6715 }
6716
6717 if (ptr[0] >= 12)
6718 {
6719 memcpy(buffer, ptr + 13, ptr[0] - 12);
6720 buffer[ptr[0] - 12] = 0;
6721 spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
6722 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
6723 else
6724 {
6725 CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
6726 CFRelease(spsname);
6727 }
6728 }
6729
6730 return dict;
6731 }
6732
6733 mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
6734 {
6735 (void)context;
6736 return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
6737 (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
6738 NULL);
6739 }
6740
6741 mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
6742 {
6743 NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
6744 debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
6745
6746 mDNS_Lock(m);
6747 mDNS_UpdateAllowSleep(m);
6748 mDNS_Unlock(m);
6749
6750 if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names
6751
6752 if (!spsStatusDict)
6753 {
6754 spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6755 if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
6756 }
6757
6758 CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
6759 if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
6760
6761 CFMutableArrayRef array = NULL;
6762
6763 if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
6764 {
6765 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6766 if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
6767 CFDictionarySetValue(spsStatusDict, ifname, array);
6768 CFRelease(array); // let go of our reference, now that the dict has one
6769 }
6770 else
6771 if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
6772
6773 if (!answer) // special call that means the question has been stopped (because the interface is going away)
6774 CFArrayRemoveAllValues(array);
6775 else
6776 {
6777 CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
6778 if (!dict) { CFRelease(ifname); return; }
6779
6780 if (AddRecord)
6781 {
6782 if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
6783 {
6784 int i=0;
6785 for (i=0; i<CFArrayGetCount(array); i++)
6786 if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
6787 break;
6788 CFArrayInsertValueAtIndex(array, i, dict);
6789 }
6790 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
6791 }
6792 else
6793 {
6794 CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
6795 if (i != -1) CFArrayRemoveValueAtIndex(array, i);
6796 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
6797 }
6798
6799 CFRelease(dict);
6800 }
6801
6802 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
6803
6804 CFRelease(ifname);
6805 }
6806
6807 mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
6808 {
6809 mDNSs32 val = -1;
6810 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
6811 if (!store)
6812 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6813 else
6814 {
6815 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
6816 if (dict)
6817 {
6818 CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
6819 if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
6820 CFRelease(dict);
6821 }
6822 CFRelease(store);
6823 }
6824 return val;
6825 }
6826
6827 mDNSlocal void SetSPS(mDNS *const m)
6828 {
6829
6830 // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
6831 mDNSu8 sps = (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware : 0;
6832
6833 // For devices that are not running NAT, but are set to never sleep, we may choose to act
6834 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
6835 //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
6836
6837 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
6838
6839 // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
6840 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
6841 // We rate such a device as metric 70 ("Incidentally Available Hardware")
6842 if (SPMetricMarginalPower <= 60 && !sps) sps = mDNSSleepProxyMetric_IncidentalHardware;
6843
6844 // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
6845 // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
6846 if (sps && OfferSleepProxyService && OfferSleepProxyService < 100) sps = OfferSleepProxyService;
6847
6848 #ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI
6849 // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active.
6850 if (IsAppleTV())
6851 {
6852 NetworkInterfaceInfo *intf = mDNSNULL;
6853 mDNSEthAddr bssid = zeroEthAddr;
6854 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
6855 {
6856 if (intf->InterfaceID == AWDLInterfaceID) continue;
6857 bssid = GetBSSID(intf->ifname);
6858 if (!mDNSSameEthAddress(&bssid, &zeroEthAddr))
6859 {
6860 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
6861 sps = 0;
6862 break;
6863 }
6864 }
6865 }
6866 #endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI
6867
6868 mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
6869 }
6870
6871 // The definitions below should eventually come from some externally-supplied header file.
6872 // However, since these definitions can't really be changed without breaking binary compatibility,
6873 // they should never change, so in practice it should not be a big problem to have them defined here.
6874
6875 enum
6876 { // commands from the daemon to the driver
6877 cmd_mDNSOffloadRR = 21, // give the mdns update buffer to the driver
6878 };
6879
6880 typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr;
6881
6882 typedef struct
6883 { // cmd_mDNSOffloadRR structure
6884 uint32_t command; // set to OffloadRR
6885 uint32_t rrBufferSize; // number of bytes of RR records
6886 uint32_t numUDPPorts; // number of SRV UDP ports
6887 uint32_t numTCPPorts; // number of SRV TCP ports
6888 uint32_t numRRRecords; // number of RR records
6889 uint32_t compression; // rrRecords - compression is base for compressed strings
6890 FatPtr rrRecords; // address of array of pointers to the rr records
6891 FatPtr udpPorts; // address of udp port list (SRV)
6892 FatPtr tcpPorts; // address of tcp port list (SRV)
6893 } mDNSOffloadCmd;
6894
6895 #include <IOKit/IOKitLib.h>
6896 #include <dns_util.h>
6897
6898 mDNSlocal mDNSu32 GetPortArray(int trans, mDNSIPPort *portarray)
6899 {
6900 mDNS *const m = &mDNSStorage;
6901 const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
6902 mDNSu32 count = 0;
6903
6904 AuthRecord *rr;
6905 for (rr = m->ResourceRecords; rr; rr=rr->next)
6906 {
6907 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c))
6908 {
6909 if (!portarray)
6910 count++;
6911 else
6912 {
6913 mDNSu32 i;
6914 for (i = 0; i < count; i++)
6915 if (mDNSSameIPPort(portarray[i], rr->resrec.rdata->u.srv.port))
6916 break;
6917
6918 // Add it into the port list only if it not already present in the list
6919 if (i >= count)
6920 portarray[count++] = rr->resrec.rdata->u.srv.port;
6921 }
6922 }
6923 }
6924
6925 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
6926 if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext)
6927 {
6928 LogSPS("GetPortArray Back to My Mac at %u", count);
6929 if (portarray) portarray[count] = IPSECPort;
6930 count++;
6931 }
6932 return(count);
6933 }
6934
6935 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6936 mDNSlocal mDNSBool SupportsTCPKeepAlive()
6937 {
6938 IOReturn ret = kIOReturnSuccess;
6939 CFTypeRef obj = NULL;
6940 mDNSBool supports = mDNSfalse;
6941
6942 ret = IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj);
6943 if ((kIOReturnSuccess == ret) && (obj != NULL))
6944 {
6945 supports = (obj == kCFBooleanTrue)? mDNStrue : mDNSfalse;
6946 CFRelease(obj);
6947 }
6948 LogSPS("%s: The hardware %s TCP Keep Alive", __func__, (supports ? "supports" : "does not support"));
6949 return supports;
6950 }
6951
6952 mDNSlocal mDNSBool OnBattery(void)
6953 {
6954 CFTypeRef powerInfo = IOPSCopyPowerSourcesInfo();
6955 CFTypeRef powerSrc = IOPSGetProvidingPowerSourceType(powerInfo);
6956 mDNSBool result = mDNSfalse;
6957
6958 if (powerInfo != NULL)
6959 {
6960 result = CFEqual(CFSTR(kIOPSBatteryPowerValue), powerSrc);
6961 CFRelease(powerInfo);
6962 }
6963 LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
6964 return result;
6965 }
6966
6967 #endif // !TARGET_OS_EMBEDDED
6968
6969 #define TfrRecordToNIC(RR) \
6970 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
6971
6972 mDNSlocal mDNSu32 CountProxyRecords(uint32_t *const numbytes, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
6973 {
6974 mDNS *const m = &mDNSStorage;
6975 *numbytes = 0;
6976 uint32_t count = 0;
6977 mDNSBool isKeepAliveRecord = mDNSfalse;
6978
6979 AuthRecord *rr;
6980
6981 for (rr = m->ResourceRecords; rr; rr=rr->next)
6982 {
6983 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
6984 {
6985 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6986 isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
6987 // Skip over all other records if we are registering TCP KeepAlive records only
6988 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
6989 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
6990 continue;
6991 #else
6992 (void) TCPKAOnly; // unused
6993 (void) supportsTCPKA; // unused
6994 #endif
6995 if (TfrRecordToNIC(rr))
6996 {
6997 // For KeepAlive records, use an estimated length of 256, which is the maximum size.
6998 const uint32_t rdataLen = isKeepAliveRecord ? ((uint32_t)sizeof(UTF8str255)) : rr->resrec.rdestimate;
6999 const uint32_t recordSize = DomainNameLength(rr->resrec.name) + 10 + rdataLen;
7000 *numbytes += recordSize;
7001 LogSPS("CountProxyRecords: %3u size %5u total %5u %s", count, recordSize, *numbytes, ARDisplayString(m,rr));
7002 count++;
7003 }
7004 }
7005 }
7006 return(count);
7007 }
7008
7009 mDNSlocal void GetProxyRecords(DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records,
7010 uint32_t *outRecordCount, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
7011 {
7012 mDNS *const m = &mDNSStorage;
7013 mDNSu8 *p = msg->data;
7014 const mDNSu8 *const limit = p + *numbytes;
7015 InitializeDNSMessage(&msg->h, zeroID, zeroID);
7016
7017 uint32_t count = 0;
7018 AuthRecord *rr;
7019
7020 for (rr = m->ResourceRecords; rr; rr=rr->next)
7021 {
7022 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
7023 {
7024 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7025 const mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
7026
7027 // Skip over all other records if we are registering TCP KeepAlive records only
7028 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
7029 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
7030 continue;
7031
7032 // Update the record before calculating the number of bytes required
7033 // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
7034 // attempt to update the record again.
7035 if (isKeepAliveRecord)
7036 {
7037 if (UpdateKeepaliveRData(m, rr, intf, mDNSfalse, mDNSNULL) != mStatus_NoError)
7038 {
7039 LogSPS("GetProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m, rr));
7040 continue;
7041 }
7042 // Offload only Valid Keepalive records
7043 if (!mDNSValidKeepAliveRecord(rr))
7044 {
7045 continue;
7046 }
7047 }
7048 #else
7049 (void) intf; // unused
7050 (void) TCPKAOnly; // unused
7051 (void) supportsTCPKA; // unused
7052 #endif // APPLE_OSX_mDNSResponder
7053
7054 if (TfrRecordToNIC(rr))
7055 {
7056 records[count].sixtyfourbits = zeroOpaque64;
7057 records[count].ptr = p;
7058 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
7059 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it
7060 p = PutResourceRecordTTLWithLimit(msg, p, &msg->h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
7061 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state
7062 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
7063 count, records[count].ptr, p, p - (mDNSu8 *)records[count].ptr, p - msg->data, ARDisplayString(m,rr));
7064 count++;
7065 }
7066 }
7067 }
7068 *numbytes = p - msg->data;
7069 if (outRecordCount) *outRecordCount = count;
7070 }
7071
7072 mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf)
7073 {
7074 if(!UseInternalSleepProxy)
7075 {
7076 LogMsg("SupportsInNICProxy: Internal Sleep Proxy is disabled");
7077 return mDNSfalse;
7078 }
7079 return CheckInterfaceSupport(intf, mDNS_IOREG_KEY);
7080 }
7081
7082 // Called with the lock held
7083 mDNSexport mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool offloadKeepAlivesOnly, mDNSBool *keepaliveOnly)
7084 {
7085 mStatus result = mStatus_UnknownErr;
7086 mDNSBool TCPKAOnly = mDNSfalse;
7087 mDNSBool supportsTCPKA = mDNSfalse;
7088 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
7089
7090 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7091 // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
7092 supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive()) ? mDNStrue : mDNSfalse;
7093 if (!offloadKeepAlivesOnly)
7094 {
7095 // Only TCP Keepalive records are to be offloaded if
7096 // - The system is on battery
7097 // - OR wake for network access is not set but powernap is enabled
7098 TCPKAOnly = supportsTCPKA && ((mDNSStorage.SystemWakeOnLANEnabled == mDNS_WakeOnBattery) || OnBattery());
7099 }
7100 else
7101 {
7102 TCPKAOnly = mDNStrue;
7103 }
7104 #else
7105 (void)offloadKeepAlivesOnly; // Unused.
7106 #endif
7107 if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", intf->ifname); return(mStatus_UnknownErr); }
7108
7109 io_name_t n1, n2;
7110 IOObjectGetClass(service, n1);
7111
7112 CFTypeRef ref;
7113 io_object_t parent;
7114 kern_return_t kr = RegistryEntrySearchCFPropertyAndIOObject(service, kIOServicePlane, CFSTR(mDNS_IOREG_KEY), &ref, &parent);
7115 IOObjectRelease(service);
7116 if (kr != KERN_SUCCESS) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s kr %d", intf->ifname, n1, kr);
7117 else
7118 {
7119 IOObjectGetClass(parent, n2);
7120 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf->ifname, n1, n2);
7121
7122 if (CFGetTypeID(ref) != CFStringGetTypeID() || !CFEqual(ref, CFSTR(mDNS_IOREG_VALUE)))
7123 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
7124 intf->ifname, n1, n2, CFStringGetCStringPtr(ref, mDNSNULL), mDNS_IOREG_VALUE);
7125 else if (!UseInternalSleepProxy)
7126 LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf->ifname);
7127 else
7128 {
7129 io_connect_t conObj;
7130 kr = IOServiceOpen(parent, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE, &conObj);
7131 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf->ifname, n1, n2, kr);
7132 else
7133 {
7134 mDNSOffloadCmd cmd;
7135 mDNSPlatformMemZero(&cmd, sizeof(cmd)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
7136 cmd.command = cmd_mDNSOffloadRR;
7137 cmd.numUDPPorts = TCPKAOnly ? 0 : GetPortArray(mDNSTransport_UDP, mDNSNULL);
7138 cmd.numTCPPorts = TCPKAOnly ? 0 : GetPortArray(mDNSTransport_TCP, mDNSNULL);
7139 cmd.numRRRecords = CountProxyRecords(&cmd.rrBufferSize, TCPKAOnly, supportsTCPKA);
7140 cmd.compression = sizeof(DNSMessageHeader);
7141
7142 DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
7143 cmd.rrRecords.ptr = cmd.numRRRecords ? mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr)) : NULL;
7144 cmd.udpPorts.ptr = cmd.numUDPPorts ? mallocL("mDNSOffloadCmd udpPorts" , cmd.numUDPPorts * sizeof(mDNSIPPort)) : NULL;
7145 cmd.tcpPorts.ptr = cmd.numTCPPorts ? mallocL("mDNSOffloadCmd tcpPorts" , cmd.numTCPPorts * sizeof(mDNSIPPort)) : NULL;
7146
7147 LogSPS("ActivateLocalProxy: msg %p %u RR %p %u, UDP %p %u, TCP %p %u",
7148 msg, cmd.rrBufferSize,
7149 cmd.rrRecords.ptr, cmd.numRRRecords,
7150 cmd.udpPorts.ptr, cmd.numUDPPorts,
7151 cmd.tcpPorts.ptr, cmd.numTCPPorts);
7152
7153 if (msg && cmd.rrRecords.ptr)
7154 {
7155 GetProxyRecords(msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, &cmd.numRRRecords, intf, TCPKAOnly, supportsTCPKA);
7156 }
7157 if (cmd.udpPorts.ptr) cmd.numUDPPorts = TCPKAOnly ? 0 : GetPortArray(mDNSTransport_UDP, cmd.udpPorts.ptr);
7158 if (cmd.tcpPorts.ptr) cmd.numTCPPorts = TCPKAOnly ? 0 : GetPortArray(mDNSTransport_TCP, cmd.tcpPorts.ptr);
7159
7160 char outputData[2];
7161 size_t outputDataSize = sizeof(outputData);
7162 kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize);
7163 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr);
7164 if (kr == KERN_SUCCESS) result = mStatus_NoError;
7165
7166 if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts.ptr);
7167 if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts.ptr);
7168 if (cmd.rrRecords.ptr) freeL("mDNSOffloadCmd rrRecords", cmd.rrRecords.ptr);
7169 if (msg) freeL("mDNSOffloadCmd msg", msg);
7170 IOServiceClose(conObj);
7171 }
7172 }
7173 CFRelease(ref);
7174 IOObjectRelease(parent);
7175 }
7176 *keepaliveOnly = (TCPKAOnly && supportsTCPKA) ? mDNStrue : mDNSfalse;
7177 return result;
7178 }
7179
7180 #endif // APPLE_OSX_mDNSResponder
7181
7182 mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
7183 {
7184 mDNSs32 val = 0;
7185 mDNSu8 ret = (mDNSu8)mDNS_NoWake;
7186
7187 #if TARGET_OS_IOS
7188 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7189 return ret;
7190 #endif
7191
7192 if (DisableSleepProxyClient)
7193 {
7194 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7195 return ret;
7196 }
7197
7198 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
7199
7200 ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
7201
7202 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7203 // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
7204 // Further policy decisions on whether to offload the records is handled during sleep processing.
7205 if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive())
7206 ret = (mDNSu8)mDNS_WakeOnBattery;
7207 #endif // APPLE_OSX_mDNSResponder
7208
7209 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret);
7210 return ret;
7211 }
7212
7213 mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
7214 {
7215 mDNSs32 val = 0;
7216 // PrioritizeNetworkReachabilityOverSleep has been deprecated.
7217 // GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
7218 // Statically set the PrioritizeNetworkReachabilityOverSleep value to 1 for AppleTV
7219 if (IsAppleTV())
7220 val = 1;
7221 return val != 0 ? mDNStrue : mDNSfalse;
7222 }
7223
7224
7225 #if APPLE_OSX_mDNSResponder
7226 // When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
7227 // gets deregistered, so that older peers are forced to connect over direct UDP instead of
7228 // the RR relay.
7229 //
7230 // When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
7231 // service records are deregistered, so they do not appear in peers' Finder sidebars.
7232 // We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
7233 // depend on their associated SRV record and therefore will be deregistered together in a
7234 // single update with the SRV record.
7235 //
7236 // Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
7237 // its presence shouldn't delay sleep.
7238 //
7239 // Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
7240 // relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
7241 //
7242 // Also note that returning false here will not delay sleep past the maximum of 10 seconds.
7243 mDNSexport mDNSBool RecordReadyForSleep(AuthRecord *rr)
7244 {
7245 mDNS *const m = &mDNSStorage;
7246 if (!AuthRecord_uDNS(rr)) return mDNStrue;
7247
7248 if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
7249 {
7250 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7251 return mDNSfalse;
7252 }
7253
7254 if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result))
7255 {
7256 if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone
7257 && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel"))
7258 {
7259 DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
7260 if (info && info->AutoTunnel)
7261 {
7262 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7263 return mDNSfalse;
7264 }
7265 }
7266 }
7267
7268 return mDNStrue;
7269 }
7270
7271 // Caller must hold the lock
7272 mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
7273 {
7274 DomainAuthInfo *info;
7275 // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
7276 // deregister the record, and the MemFree callback won't re-register.
7277 m->AutoTunnelRelayAddr = zerov6Addr;
7278 for (info = m->AuthInfoList; info; info = info->next)
7279 if (info->AutoTunnel)
7280 UpdateAutoTunnel6Record(m, info);
7281 }
7282 #endif /* APPLE_OSX_mDNSResponder */
7283
7284 #if MDNSRESPONDER_BTMM_SUPPORT
7285 mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname)
7286 {
7287 struct ifaddrs *ifa;
7288 struct ifaddrs *ifaddrs;
7289 mDNSAddr addr;
7290
7291 if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;}
7292
7293 if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;}
7294
7295 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
7296 {
7297 if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
7298 continue;
7299 if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
7300 continue;
7301 if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
7302 {
7303 LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
7304 continue;
7305 }
7306 if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6))
7307 {
7308 LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr);
7309 break;
7310 }
7311 }
7312 freeifaddrs(ifaddrs);
7313 return ifa != NULL;
7314 }
7315
7316 mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf)
7317 {
7318 mDNSv6Addr retVal;
7319 struct addrinfo hints;
7320 struct addrinfo *res0;
7321
7322 memset(&hints, 0, sizeof(hints));
7323 hints.ai_family = AF_INET6;
7324 hints.ai_flags = AI_NUMERICHOST;
7325
7326 int err = getaddrinfo(buf, NULL, &hints, &res0);
7327 if (err)
7328 return zerov6Addr;
7329
7330 retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr;
7331
7332 freeaddrinfo(res0);
7333
7334 return retVal;
7335 }
7336
7337 mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict()
7338 {
7339 CFDictionaryRef connd = NULL;
7340 CFDictionaryRef BTMMDict = NULL;
7341
7342 connd = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BTMMConnectivity);
7343 if (!connd)
7344 {
7345 LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
7346 goto end;
7347 }
7348
7349 BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
7350 if (!BTMMDict)
7351 {
7352 LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
7353 goto end;
7354 }
7355
7356 // Non-dictionary is treated as non-existent dictionary
7357 if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
7358 {
7359 BTMMDict = NULL;
7360 LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
7361 goto end;
7362 }
7363
7364 CFRetain(BTMMDict);
7365
7366 end:
7367 if (connd) CFRelease(connd);
7368
7369 return BTMMDict;
7370 }
7371
7372 #define MAX_IPV6_TEXTUAL 40
7373
7374 mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey)
7375 {
7376 mDNSv6Addr retVal = zerov6Addr;
7377 CFTypeRef string = NULL;
7378 char ifname[IFNAMSIZ];
7379 char address[MAX_IPV6_TEXTUAL];
7380
7381 if (!BTMMDict)
7382 return zerov6Addr;
7383
7384 if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string))
7385 {
7386 LogInfo("ParseBackToMyMacAddr: interface key does not exist");
7387 return zerov6Addr;
7388 }
7389
7390 if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8))
7391 {
7392 LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
7393 return zerov6Addr;
7394 }
7395
7396 if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string))
7397 {
7398 LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
7399 return zerov6Addr;
7400 }
7401
7402 if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8))
7403 {
7404 LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
7405 return zerov6Addr;
7406 }
7407
7408 retVal = IPv6AddressFromString(address);
7409 LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal);
7410
7411 if (mDNSIPv6AddressIsZero(retVal))
7412 return zerov6Addr;
7413
7414 if (!IPv6AddressIsOnInterface(retVal, ifname))
7415 {
7416 LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname);
7417 return zerov6Addr;
7418 }
7419
7420 return retVal;
7421 }
7422
7423 mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict)
7424 {
7425 CFTypeRef zones = NULL;
7426
7427 if (!BTMMDict)
7428 return NULL;
7429
7430 if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones))
7431 {
7432 LogInfo("CopyBTMMZones: Zones key does not exist");
7433 return NULL;
7434 }
7435
7436 return zones;
7437 }
7438
7439 mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info)
7440 {
7441 mDNSv6Addr addr = zerov6Addr;
7442 char buffer[MAX_ESCAPED_DOMAIN_NAME];
7443 CFStringRef domain = NULL;
7444 CFTypeRef theZone = NULL;
7445
7446 if (!zones)
7447 return addr;
7448
7449 ConvertDomainNameToCString(&info->domain, buffer);
7450 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
7451 if (!domain)
7452 return addr;
7453
7454 if (CFDictionaryGetValueIfPresent(zones, domain, &theZone))
7455 addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address"));
7456
7457 CFRelease(domain);
7458
7459 return addr;
7460 }
7461
7462 mDNSlocal void SetupBackToMyMacInnerAddresses(CFDictionaryRef BTMMDict)
7463 {
7464 mDNS *const m = &mDNSStorage;
7465 DomainAuthInfo* info;
7466 CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
7467 mDNSv6Addr newAddr;
7468
7469 for (info = m->AuthInfoList; info; info = info->next)
7470 {
7471 if (!info->AutoTunnel)
7472 continue;
7473
7474 newAddr = ParseBackToMyMacZone(zones, info);
7475
7476 if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress))
7477 continue;
7478
7479 info->AutoTunnelInnerAddress = newAddr;
7480 DeregisterAutoTunnelHostRecord(m, info);
7481 UpdateAutoTunnelHostRecord(m, info);
7482 UpdateAutoTunnelDomainStatus(info);
7483 }
7484 }
7485
7486 // MUST be called holding the lock
7487 mDNSlocal void ProcessConndConfigChanges(void)
7488 {
7489 mDNS *const m = &mDNSStorage;
7490 CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
7491 if (!dict)
7492 LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
7493 mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
7494
7495 LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
7496
7497 SetupBackToMyMacInnerAddresses(dict);
7498
7499 if (dict) CFRelease(dict);
7500
7501 if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr))
7502 {
7503 m->AutoTunnelRelayAddr = relayAddr;
7504
7505 DomainAuthInfo* info;
7506 for (info = m->AuthInfoList; info; info = info->next)
7507 if (info->AutoTunnel)
7508 {
7509 DeregisterAutoTunnel6Record(m, info);
7510 UpdateAutoTunnel6Record(m, info);
7511 UpdateAutoTunnelDomainStatus(info);
7512 }
7513
7514 // Determine whether we need racoon to accept incoming connections
7515 UpdateAnonymousRacoonConfig(m);
7516 }
7517
7518 // If awacsd crashes or exits for some reason, restart it
7519 UpdateBTMMRelayConnection(m);
7520 }
7521 #endif // MDNSRESPONDER_BTMM_SUPPORT
7522
7523 mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
7524 {
7525 DNSServer *s;
7526 // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
7527 for (s = m->DNSServers; s; s = s->next)
7528 {
7529 if (s->addr.ip.v4.b[0] == 17)
7530 {
7531 LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s->domain.c, &s->addr);
7532 return mDNStrue;
7533 }
7534 }
7535 return mDNSfalse;
7536 }
7537
7538 // Called with KQueueLock & mDNS lock
7539 // SetNetworkChanged is allowed to shorten (but not extend) the pause while we wait for configuration changes to settle
7540 mDNSlocal void SetNetworkChanged(mDNSs32 delay)
7541 {
7542 mDNS *const m = &mDNSStorage;
7543 mDNS_CheckLock(m);
7544 if (!m->NetworkChanged || m->NetworkChanged - NonZeroTime(m->timenow + delay) > 0)
7545 {
7546 m->NetworkChanged = NonZeroTime(m->timenow + delay);
7547 LogInfo("SetNetworkChanged: Scheduling in %d ticks", delay);
7548 }
7549 else
7550 LogInfo("SetNetworkChanged: *NOT* increasing delay from %d to %d", m->NetworkChanged - m->timenow, delay);
7551 }
7552
7553 // Called with KQueueLock & mDNS lock
7554 mDNSlocal void SetKeyChainTimer(mDNSs32 delay)
7555 {
7556 mDNS *const m = &mDNSStorage;
7557 // If it's not set or it needs to happen sooner than when it's currently set
7558 if (!m->p->KeyChainTimer || m->p->KeyChainTimer - NonZeroTime(m->timenow + delay) > 0)
7559 {
7560 m->p->KeyChainTimer = NonZeroTime(m->timenow + delay);
7561 LogInfo("SetKeyChainTimer: %d", delay);
7562 }
7563 }
7564
7565 mDNSexport void mDNSMacOSXNetworkChanged(void)
7566 {
7567 mDNS *const m = &mDNSStorage;
7568 LogInfo("*** Network Configuration Change *** %d ticks late%s",
7569 m->NetworkChanged ? mDNS_TimeNow(m) - m->NetworkChanged : 0,
7570 m->NetworkChanged ? "" : " (no scheduled configuration change)");
7571 m->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
7572
7573 // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring
7574 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
7575 if (InfoSocket > 0)
7576 {
7577 mDNSBool tentative = mDNSfalse;
7578 struct ifaddrs *ifa = myGetIfAddrs(1);
7579 while (ifa)
7580 {
7581 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6)
7582 {
7583 struct in6_ifreq ifr6;
7584 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
7585 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
7586 ifr6.ifr_addr = *(struct sockaddr_in6 *)ifa->ifa_addr;
7587 // We need to check for IN6_IFF_TENTATIVE here, not IN6_IFF_NOTREADY, because
7588 // IN6_IFF_NOTREADY includes both IN6_IFF_TENTATIVE and IN6_IFF_DUPLICATED addresses.
7589 // We can expect that an IN6_IFF_TENTATIVE address will shortly become ready,
7590 // but an IN6_IFF_DUPLICATED address may not.
7591 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
7592 {
7593 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
7594 {
7595 LogInfo("*** Network Configuration Change *** IPv6 address %.16a TENTATIVE, will retry", &ifr6.ifr_addr.sin6_addr);
7596 tentative = mDNStrue;
7597 // no need to check other interfaces if we already found out that one interface is TENTATIVE
7598 break;
7599 }
7600 }
7601 }
7602 ifa = ifa->ifa_next;
7603 }
7604 close(InfoSocket);
7605 if (tentative)
7606 {
7607 mDNS_Lock(m);
7608 SetNetworkChanged(mDNSPlatformOneSecond / 2);
7609 mDNS_Unlock(m);
7610 return;
7611 }
7612 LogInfo("*** Network Configuration Change *** No IPv6 address TENTATIVE, will continue");
7613 }
7614
7615 mDNSs32 utc = mDNSPlatformUTC();
7616 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
7617 m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
7618 MarkAllInterfacesInactive(utc);
7619 UpdateInterfaceList(utc);
7620 ClearInactiveInterfaces(utc);
7621 SetupActiveInterfaces(utc);
7622 ReorderInterfaceList();
7623
7624 #if APPLE_OSX_mDNSResponder
7625 #if !TARGET_OS_EMBEDDED
7626 #if MDNSRESPONDER_BTMM_SUPPORT
7627 mDNS_Lock(m);
7628 ProcessConndConfigChanges();
7629 mDNS_Unlock(m);
7630 #endif
7631
7632 // Scan to find client tunnels whose questions have completed,
7633 // but whose local inner/outer addresses have changed since the tunnel was set up
7634 ClientTunnel *p;
7635 for (p = m->TunnelClients; p; p = p->next)
7636 if (p->q.ThisQInterval < 0)
7637 {
7638 DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname);
7639 if (!info)
7640 {
7641 LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c);
7642 AutoTunnelSetKeys(p, mDNSfalse);
7643 }
7644 else
7645 {
7646 mDNSv6Addr inner = info->AutoTunnelInnerAddress;
7647
7648 if (!mDNSIPPortIsZero(p->rmt_outer_port))
7649 {
7650 mDNSAddr tmpSrc = zeroAddr;
7651 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
7652 tmpDst.ip.v4 = p->rmt_outer;
7653 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
7654 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7655 !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
7656 {
7657 AutoTunnelSetKeys(p, mDNSfalse);
7658 p->loc_inner = inner;
7659 p->loc_outer = tmpSrc.ip.v4;
7660 AutoTunnelSetKeys(p, mDNStrue);
7661 }
7662 }
7663 else
7664 {
7665 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7666 !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
7667 {
7668 AutoTunnelSetKeys(p, mDNSfalse);
7669 p->loc_inner = inner;
7670 p->loc_outer6 = m->AutoTunnelRelayAddr;
7671 AutoTunnelSetKeys(p, mDNStrue);
7672 }
7673 }
7674 }
7675 }
7676 #endif //!TARGET_OS_EMBEDDED
7677
7678 SetSPS(m);
7679
7680 NetworkInterfaceInfoOSX *i;
7681 for (i = m->p->InterfaceList; i; i = i->next)
7682 {
7683 if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
7684 {
7685 if (i->BPF_fd >= 0 && CountProxyTargets(i, mDNSNULL, mDNSNULL) == 0)
7686 CloseBPF(i);
7687 }
7688 else // else, we're Sleep Proxy Server; open BPF fds
7689 {
7690 if (i->Exists && (i->Registered == i) && SPSInterface(i) && i->BPF_fd == -1)
7691 {
7692 LogMsg("%s mDNSMacOSXNetworkChanged: requesting BPF", i->ifinfo.ifname);
7693 i->BPF_fd = -2;
7694 mDNSRequestBPF();
7695 }
7696 }
7697 }
7698
7699 #endif // APPLE_OSX_mDNSResponder
7700
7701 uDNS_SetupDNSConfig(m);
7702 mDNS_ConfigChanged(m);
7703
7704 if (IsAppleNetwork(m) != mDNS_McastTracingEnabled)
7705 {
7706 mDNS_McastTracingEnabled = mDNS_McastTracingEnabled ? mDNSfalse : mDNStrue;
7707 LogInfo("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
7708 UpdateDebugState();
7709 }
7710
7711 }
7712
7713 // Copy the fourth slash-delimited element from either:
7714 // State:/Network/Interface/<bsdname>/IPv4
7715 // or
7716 // Setup:/Network/Service/<servicename>/Interface
7717 mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
7718 {
7719 CFArrayRef a;
7720 CFStringRef name = NULL;
7721
7722 a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
7723 if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
7724 if (a != NULL) CFRelease(a);
7725
7726 return name;
7727 }
7728
7729 // Whether a key from a network change notification corresponds to
7730 // an IP service that is explicitly configured for IPv4 Link Local
7731 mDNSlocal int ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
7732 {
7733 CFDictionaryRef dict = NULL;
7734 CFMutableArrayRef a;
7735 const void **keys = NULL, **vals = NULL;
7736 CFStringRef pattern = NULL;
7737 int i, ic, j, jc;
7738 int found = 0;
7739
7740 jc = CFArrayGetCount(inkeys);
7741 if (!jc) goto done;
7742
7743 a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7744 if (a == NULL) goto done;
7745
7746 // Setup:/Network/Service/[^/]+/Interface
7747 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
7748 if (pattern == NULL) goto done;
7749 CFArrayAppendValue(a, pattern);
7750 CFRelease(pattern);
7751
7752 // Setup:/Network/Service/[^/]+/IPv4
7753 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
7754 if (pattern == NULL) goto done;
7755 CFArrayAppendValue(a, pattern);
7756 CFRelease(pattern);
7757
7758 dict = SCDynamicStoreCopyMultiple(NULL, NULL, a);
7759 CFRelease(a);
7760
7761 if (!dict)
7762 {
7763 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
7764 goto done;
7765 }
7766
7767 ic = CFDictionaryGetCount(dict);
7768 vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7769 keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7770 CFDictionaryGetKeysAndValues(dict, keys, vals);
7771
7772 // For each key we were given...
7773 for (j = 0; j < jc; j++)
7774 {
7775 CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
7776 CFStringRef ifname = NULL;
7777
7778 char buf[256];
7779
7780 // It would be nice to use a regex here
7781 if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
7782
7783 if ((ifname = CopyNameFromKey(key)) == NULL) continue;
7784 if (mDNS_LoggingEnabled)
7785 {
7786 if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7787 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
7788 }
7789
7790 // Loop over the interfaces to find matching the ifname, and see if that one has kSCValNetIPv4ConfigMethodLinkLocal
7791 for (i = 0; i < ic; i++)
7792 {
7793 CFDictionaryRef ipv4dict;
7794 CFStringRef name;
7795 CFStringRef serviceid;
7796 CFStringRef configmethod;
7797
7798 if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
7799
7800 if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
7801
7802 if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
7803
7804 if (!CFEqual(ifname, name)) continue;
7805
7806 if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
7807 if (mDNS_LoggingEnabled)
7808 {
7809 if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7810 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
7811 }
7812
7813 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
7814 CFRelease(serviceid);
7815 if (pattern == NULL) continue;
7816
7817 ipv4dict = CFDictionaryGetValue(dict, pattern);
7818 CFRelease(pattern);
7819 if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
7820
7821 configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
7822 if (!configmethod) continue;
7823
7824 if (mDNS_LoggingEnabled)
7825 {
7826 if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7827 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
7828 }
7829
7830 if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found++; break; }
7831 }
7832
7833 CFRelease(ifname);
7834 }
7835
7836 done:
7837 if (vals != NULL) mDNSPlatformMemFree(vals);
7838 if (keys != NULL) mDNSPlatformMemFree(keys);
7839 if (dict != NULL) CFRelease(dict);
7840
7841 return found;
7842 }
7843
7844 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
7845 {
7846 (void)store; // Parameter not used
7847 mDNS *const m = (mDNS *const)context;
7848 KQueueLock();
7849 mDNS_Lock(m);
7850
7851 //mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
7852 const mDNSs32 delay = (mDNSPlatformOneSecond + 39) / 40; // 25 ms delay
7853
7854 const int c = CFArrayGetCount(changedKeys); // Count changes
7855 CFRange range = { 0, c };
7856 const int c_host = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
7857 const int c_comp = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
7858 const int c_udns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0);
7859 const int c_ddns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
7860 #if MDNSRESPONDER_BTMM_SUPPORT
7861 const int c_btmm = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac ) != 0);
7862 #else
7863 const int c_btmm = 0;
7864 #endif
7865 const int c_v4ll = ChangedKeysHaveIPv4LL(changedKeys);
7866 int c_fast = 0;
7867
7868 // Do immediate network changed processing for "p2p*" interfaces and
7869 // for interfaces with the IFEF_DIRECTLINK or IFEF_AWDL flag set or association with a CarPlay
7870 // hosted SSID.
7871 {
7872 CFArrayRef labels;
7873 CFIndex n;
7874 for (int i = 0; i < c; i++)
7875 {
7876 CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i);
7877
7878 // Only look at keys with prefix "State:/Network/Interface/"
7879 if (!CFStringHasPrefix(key, NetworkChangedKey_StateInterfacePrefix))
7880 continue;
7881
7882 // And suffix "IPv6" or "IPv4".
7883 if (!CFStringHasSuffix(key, kSCEntNetIPv6) && !CFStringHasSuffix(key, kSCEntNetIPv4))
7884 continue;
7885
7886 labels = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
7887 if (labels == NULL)
7888 break;
7889 n = CFArrayGetCount(labels);
7890
7891 // Interface changes will have keys of the form:
7892 // State:/Network/Interface/<interfaceName>/IPv6
7893 // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
7894 if (n == 5)
7895 {
7896 char buf[256];
7897
7898 // The 4th label (index = 3) should be the interface name.
7899 if (CFStringGetCString(CFArrayGetValueAtIndex(labels, 3), buf, sizeof(buf), kCFStringEncodingUTF8)
7900 && (strstr(buf, "p2p") || (getExtendedFlags(buf) & (IFEF_DIRECTLINK | IFEF_AWDL)) || IsCarPlaySSID(buf)))
7901 {
7902 LogInfo("NetworkChanged: interface %s qualifies for reduced change handling delay", buf);
7903 c_fast++;
7904 CFRelease(labels);
7905 break;
7906 }
7907 }
7908 CFRelease(labels);
7909 }
7910 }
7911
7912 //if (c && c - c_host - c_comp - c_udns - c_ddns - c_btmm - c_v4ll - c_fast == 0)
7913 // delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
7914
7915 if (mDNS_LoggingEnabled)
7916 {
7917 int i;
7918 for (i=0; i<c; i++)
7919 {
7920 char buf[256];
7921 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7922 LogInfo("*** Network Configuration Change *** SC key: %s", buf);
7923 }
7924 LogInfo("*** Network Configuration Change *** %d change%s %s%s%s%s%s%s%sdelay %d%s",
7925 c, c>1 ? "s" : "",
7926 c_host ? "(Local Hostname) " : "",
7927 c_comp ? "(Computer Name) " : "",
7928 c_udns ? "(DNS) " : "",
7929 c_ddns ? "(DynamicDNS) " : "",
7930 c_btmm ? "(BTMM) " : "",
7931 c_v4ll ? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
7932 c_fast ? "(P2P/IFEF_DIRECTLINK/IFEF_AWDL/IsCarPlaySSID) " : "",
7933 delay,
7934 (c_ddns || c_btmm) ? " + SetKeyChainTimer" : "");
7935 }
7936
7937 SetNetworkChanged(delay);
7938
7939 // Other software might pick up these changes to register or browse in WAB or BTMM domains,
7940 // so in order for secure updates to be made to the server, make sure to read the keychain and
7941 // setup the DomainAuthInfo before handing the network change.
7942 // If we don't, then we will first try to register services in the clear, then later setup the
7943 // DomainAuthInfo, which is incorrect.
7944 if (c_ddns || c_btmm)
7945 SetKeyChainTimer(delay);
7946
7947 // Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
7948
7949 mDNS_Unlock(m);
7950 KQueueUnlock("NetworkChanged");
7951 }
7952
7953 #if APPLE_OSX_mDNSResponder
7954 mDNSlocal void RefreshSPSStatus(const void *key, const void *value, void *context)
7955 {
7956 (void)context;
7957 char buf[IFNAMSIZ];
7958
7959 CFStringRef ifnameStr = (CFStringRef)key;
7960 CFArrayRef array = (CFArrayRef)value;
7961 if (!CFStringGetCString(ifnameStr, buf, sizeof(buf), kCFStringEncodingUTF8))
7962 buf[0] = 0;
7963
7964 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf, CFArrayGetCount(array));
7965 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, buf, value);
7966 }
7967 #endif
7968
7969 mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
7970 {
7971 mDNS *const m = (mDNS *const)info;
7972 (void)store;
7973
7974 KQueueLock(); // serialize with KQueueLoop()
7975
7976 LogInfo("DynamicStoreReconnected: Reconnected");
7977
7978 // State:/Network/MulticastDNS
7979 SetLocalDomains();
7980
7981 // State:/Network/DynamicDNS
7982 if (m->FQDN.c[0])
7983 mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
7984
7985 // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
7986 // as we receive network change notifications and thus not necessary. But we leave it here
7987 // so that if things are done differently in the future, this code still works.
7988
7989 // State:/Network/PrivateDNS
7990 if (privateDnsArray)
7991 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
7992
7993 #if APPLE_OSX_mDNSResponder
7994 // State:/Network/BackToMyMac
7995 UpdateAutoTunnelDomainStatuses(m);
7996
7997 // State:/Network/Interface/en0/SleepProxyServers
7998 if (spsStatusDict)
7999 CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
8000 #endif
8001 KQueueUnlock("DynamicStoreReconnected");
8002 }
8003
8004 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
8005 {
8006 mStatus err = -1;
8007 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
8008 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
8009 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8010 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
8011 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
8012 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8013
8014 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
8015 if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
8016
8017 CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
8018 CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
8019 CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
8020 CFArrayAppendValue(keys, NetworkChangedKey_Computername);
8021 CFArrayAppendValue(keys, NetworkChangedKey_DNS);
8022 CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
8023 CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings);
8024 #if MDNSRESPONDER_BTMM_SUPPORT
8025 CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
8026 CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
8027 #endif
8028 CFArrayAppendValue(patterns, pattern1);
8029 CFArrayAppendValue(patterns, pattern2);
8030 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
8031 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
8032 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
8033
8034 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8035 if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()))
8036 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8037 #else
8038 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
8039 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8040 CFRunLoopAddSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode);
8041 #endif
8042 SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected);
8043 m->p->Store = store;
8044 err = 0;
8045 goto exit;
8046
8047 error:
8048 if (store) CFRelease(store);
8049
8050 exit:
8051 if (patterns) CFRelease(patterns);
8052 if (pattern2) CFRelease(pattern2);
8053 if (pattern1) CFRelease(pattern1);
8054 if (keys) CFRelease(keys);
8055
8056 return(err);
8057 }
8058
8059 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8060
8061 mDNSlocal void mDNSSetPacketFilterRules(char * ifname, const ResourceRecord *const excludeRecord)
8062 {
8063 mDNS *const m = &mDNSStorage;
8064 AuthRecord *rr;
8065 pfArray_t portArray;
8066 pfArray_t protocolArray;
8067 uint32_t count = 0;
8068
8069 for (rr = m->ResourceRecords; rr; rr=rr->next)
8070 {
8071 if ((rr->resrec.rrtype == kDNSServiceType_SRV)
8072 && ((rr->ARType == AuthRecordAnyIncludeP2P) || (rr->ARType == AuthRecordAnyIncludeAWDLandP2P)))
8073 {
8074 const mDNSu8 *p;
8075
8076 if (count >= PFPortArraySize)
8077 {
8078 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize, ARDisplayString(m, rr));
8079 continue;
8080 }
8081
8082 if (excludeRecord && IdenticalResourceRecord(&rr->resrec, excludeRecord))
8083 {
8084 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m, rr));
8085 continue;
8086 }
8087
8088 LogMsg("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr));
8089
8090 portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger;
8091
8092 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
8093 p = rr->resrec.name->c;
8094
8095 // Skip to App Protocol
8096 if (p[0])
8097 p += 1 + p[0];
8098
8099 // Skip to Transport Protocol
8100 if (p[0])
8101 p += 1 + p[0];
8102
8103 if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp"))
8104 {
8105 protocolArray[count] = IPPROTO_TCP;
8106 }
8107 else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp"))
8108 {
8109 protocolArray[count] = IPPROTO_UDP;
8110 }
8111 else
8112 {
8113 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
8114 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m, rr));
8115 return;
8116 }
8117 count++;
8118 }
8119 }
8120 mDNSPacketFilterControl(PF_SET_RULES, ifname, count, portArray, protocolArray);
8121 }
8122
8123 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
8124 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8125 {
8126 mDNS *const m = &mDNSStorage;
8127
8128 NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
8129 while (intf)
8130 {
8131 if (strncmp(intf->ifname, "p2p", 3) == 0)
8132 {
8133 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname);
8134 mDNSSetPacketFilterRules(intf->ifname, excludeRecord);
8135 break;
8136 }
8137 intf = GetFirstActiveInterface(intf->next);
8138 }
8139 }
8140
8141 #else // !TARGET_OS_EMBEDDED
8142
8143 // Currently no packet filter setup required on embedded platforms.
8144 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8145 {
8146 (void) excludeRecord; // unused
8147 }
8148
8149 #endif // !TARGET_OS_EMBEDDED
8150
8151 // AWDL should no longer generate KEV_DL_MASTER_ELECTED events, so just log a message if we receive one.
8152 mDNSlocal void newMasterElected(struct net_event_data * ptr)
8153 {
8154 char ifname[IFNAMSIZ];
8155 mDNSu32 interfaceIndex;
8156
8157 snprintf(ifname, IFNAMSIZ, "%s%d", ptr->if_name, ptr->if_unit);
8158 interfaceIndex = if_nametoindex(ifname);
8159
8160 if (!interfaceIndex)
8161 {
8162 LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname);
8163 return;
8164 }
8165
8166 LogInfo("newMasterElected: KEV_DL_MASTER_ELECTED received on ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
8167 }
8168
8169 // An ssth array of all zeroes indicates the peer has no services registered.
8170 mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op)
8171 {
8172 int i;
8173 int *intp = (int *) op->ssth;
8174
8175 // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
8176 // it's not, print an error message and return false so that
8177 // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
8178 // is received.
8179 if (MAX_SSTH_SIZE % sizeof(int))
8180 {
8181 LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE);
8182 return mDNSfalse;
8183 }
8184
8185 for (i = 0; i < (int)(MAX_SSTH_SIZE / sizeof(int)); i++, intp++)
8186 {
8187 if (*intp)
8188 return mDNSfalse;
8189 }
8190 return mDNStrue;
8191 }
8192
8193 // Mark records from this peer for deletion from the cache.
8194 mDNSlocal void removeCachedPeerRecords(mDNSu32 ifindex, mDNSAddr *ap, bool purgeNow)
8195 {
8196 mDNS *const m = &mDNSStorage;
8197 mDNSu32 slot;
8198 CacheGroup *cg;
8199 CacheRecord *cr;
8200 NetworkInterfaceInfoOSX *infoOSX;
8201 mDNSInterfaceID InterfaceID;
8202
8203 // Using mDNSPlatformInterfaceIDfromInterfaceIndex() would lead to recursive
8204 // locking issues, see: <rdar://problem/21332983>
8205 infoOSX = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
8206 if (!infoOSX)
8207 {
8208 LogInfo("removeCachedPeerRecords: interface %d not yet active", ifindex);
8209 return;
8210 }
8211 InterfaceID = infoOSX->ifinfo.InterfaceID;
8212
8213 FORALL_CACHERECORDS(slot, cg, cr)
8214 {
8215 if ((InterfaceID == cr->resrec.InterfaceID) && mDNSSameAddress(ap, & cr->sourceAddress))
8216 {
8217 LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
8218 DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c);
8219
8220 if (purgeNow)
8221 mDNS_PurgeCacheResourceRecord(m, cr);
8222 else
8223 mDNS_Reconfirm_internal(m, cr, 0); // use default minimum reconfirm time
8224 }
8225 }
8226 }
8227
8228 // Handle KEV_DL_NODE_PRESENCE event.
8229 mDNSlocal void nodePresence(struct kev_dl_node_presence * p)
8230 {
8231 struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info;
8232
8233 LogInfo("nodePresence: IPv6 address: %.16a, SUI %d", p->sin6_node_address.sin6_addr.s6_addr, op->SUI);
8234
8235 // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
8236 // all zeroes when a node is present and has no services registered.
8237 if (allZeroSSTH(op))
8238 {
8239 mDNSAddr peerAddr;
8240
8241 peerAddr.type = mDNSAddrType_IPv6;
8242 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8243
8244 LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer");
8245 removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, false);
8246 }
8247 }
8248
8249 // Handle KEV_DL_NODE_ABSENCE event.
8250 mDNSlocal void nodeAbsence(struct kev_dl_node_absence * p)
8251 {
8252 mDNSAddr peerAddr;
8253
8254 peerAddr.type = mDNSAddrType_IPv6;
8255 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8256
8257 LogInfo("nodeAbsence: immediately purge cached records from %.16a", p->sin6_node_address.sin6_addr.s6_addr);
8258 removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, true);
8259 }
8260
8261 mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context, __unused mDNSBool encounteredEOF)
8262 {
8263 mDNS *const m = (mDNS *const)context;
8264
8265 mDNS_Lock(m);
8266
8267 struct { struct kern_event_msg k; char extra[256]; } msg;
8268 int bytes = recv(s1, &msg, sizeof(msg), 0);
8269 if (bytes < 0)
8270 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
8271 else
8272 {
8273 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
8274 bytes, msg.k.total_size,
8275 msg.k.vendor_code, msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?",
8276 msg.k.kev_class, msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
8277 msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?",
8278 msg.k.id, msg.k.event_code,
8279 msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" :
8280 msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" :
8281 msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" :
8282 msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" :
8283 msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" :
8284 msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" :
8285 msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" :
8286 msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" :
8287 msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" :
8288 msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" :
8289 msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" :
8290 msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" :
8291 msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" :
8292 msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" :
8293 msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" :
8294 msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
8295 msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" :
8296 msg.k.event_code == KEV_DL_IF_IDLE_ROUTE_REFCNT ? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
8297 msg.k.event_code == KEV_DL_IFCAP_CHANGED ? "KEV_DL_IFCAP_CHANGED" :
8298 msg.k.event_code == KEV_DL_LINK_QUALITY_METRIC_CHANGED ? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" :
8299 msg.k.event_code == KEV_DL_NODE_PRESENCE ? "KEV_DL_NODE_PRESENCE" :
8300 msg.k.event_code == KEV_DL_NODE_ABSENCE ? "KEV_DL_NODE_ABSENCE" :
8301 msg.k.event_code == KEV_DL_MASTER_ELECTED ? "KEV_DL_MASTER_ELECTED" :
8302 "?");
8303
8304 if (msg.k.event_code == KEV_DL_NODE_PRESENCE)
8305 nodePresence((struct kev_dl_node_presence *) &msg.k.event_data);
8306
8307 if (msg.k.event_code == KEV_DL_NODE_ABSENCE)
8308 nodeAbsence((struct kev_dl_node_absence *) &msg.k.event_data);
8309
8310 if (msg.k.event_code == KEV_DL_MASTER_ELECTED)
8311 newMasterElected((struct net_event_data *) &msg.k.event_data);
8312
8313 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
8314 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
8315 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
8316 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
8317 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
8318
8319 if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
8320 SetNetworkChanged(mDNSPlatformOneSecond * 2);
8321
8322 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8323
8324 // For p2p interfaces, need to open the advertised service port in the firewall.
8325 if (msg.k.event_code == KEV_DL_IF_ATTACHED)
8326 {
8327 struct net_event_data * p;
8328 p = (struct net_event_data *) &msg.k.event_data;
8329
8330 if (strncmp(p->if_name, "p2p", 3) == 0)
8331 {
8332 char ifname[IFNAMSIZ];
8333 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8334
8335 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8336
8337 mDNSSetPacketFilterRules(ifname, NULL);
8338 }
8339 }
8340
8341 // For p2p interfaces, need to clear the firewall rules on interface detach
8342 if (msg.k.event_code == KEV_DL_IF_DETACHED)
8343 {
8344 struct net_event_data * p;
8345 p = (struct net_event_data *) &msg.k.event_data;
8346
8347 if (strncmp(p->if_name, "p2p", 3) == 0)
8348 {
8349 pfArray_t portArray, protocolArray; // not initialized since count is 0 for PF_CLEAR_RULES
8350 char ifname[IFNAMSIZ];
8351 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8352
8353 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8354
8355 mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
8356 }
8357 }
8358 #endif // !TARGET_OS_EMBEDDED
8359
8360 }
8361
8362 mDNS_Unlock(m);
8363 }
8364
8365 mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
8366 {
8367 m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
8368 if (m->p->SysEventNotifier < 0)
8369 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); }
8370
8371 struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
8372 int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
8373 if (err < 0)
8374 {
8375 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno));
8376 close(m->p->SysEventNotifier);
8377 m->p->SysEventNotifier = -1;
8378 return(mStatus_UnknownErr);
8379 }
8380
8381 m->p->SysEventKQueue.KQcallback = SysEventCallBack;
8382 m->p->SysEventKQueue.KQcontext = m;
8383 m->p->SysEventKQueue.KQtask = "System Event Notifier";
8384 KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
8385
8386 return(mStatus_NoError);
8387 }
8388
8389 #ifndef NO_SECURITYFRAMEWORK
8390 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
8391 {
8392 LogInfo("*** Keychain Changed ***");
8393 mDNS *const m = (mDNS *const)context;
8394 SecKeychainRef skc;
8395 OSStatus err = SecKeychainCopyDefault(&skc);
8396 if (!err)
8397 {
8398 if (info->keychain == skc)
8399 {
8400 // 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
8401 mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
8402 if (!relevant)
8403 {
8404 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
8405 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
8406 SecKeychainAttributeList *a = NULL;
8407 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
8408 if (!err)
8409 {
8410 relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
8411 (a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))));
8412 #if MDNSRESPONDER_BTMM_SUPPORT
8413 if (!relevant && (a->attr[1].length >= mDNSPlatformStrLen(btmmprefix)) && !strncasecmp(a->attr[1].data, btmmprefix, mDNSPlatformStrLen(btmmprefix)))
8414 {
8415 relevant = mDNStrue;
8416 }
8417 #endif
8418 SecKeychainItemFreeAttributesAndData(a, NULL);
8419 }
8420 }
8421 if (relevant)
8422 {
8423 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
8424 keychainEvent,
8425 keychainEvent == kSecAddEvent ? "kSecAddEvent" :
8426 keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
8427 keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
8428 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
8429 KQueueLock();
8430 mDNS_Lock(m);
8431
8432 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
8433 // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
8434 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
8435 //
8436 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
8437 // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
8438 // a one second delay is ok, as we'll still converge to correctness, and there's no race
8439 // condition between the RegistrationDomain and the DomainAuthInfo.
8440 //
8441 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
8442 // the timer here, as it will not get set by NetworkChanged().
8443 SetKeyChainTimer(mDNSPlatformOneSecond);
8444
8445 mDNS_Unlock(m);
8446 KQueueUnlock("KeychainChanged");
8447 }
8448 }
8449 CFRelease(skc);
8450 }
8451
8452 return 0;
8453 }
8454 #endif
8455
8456 mDNSlocal void PowerOn(mDNS *const m)
8457 {
8458 mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
8459
8460 if (m->p->WakeAtUTC)
8461 {
8462 long utc = mDNSPlatformUTC();
8463 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
8464 if (m->p->WakeAtUTC - utc > 30)
8465 {
8466 LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
8467 }
8468 else if (utc - m->p->WakeAtUTC > 30)
8469 {
8470 LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
8471 }
8472 else if (IsAppleTV())
8473 {
8474 LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC);
8475 }
8476 else
8477 {
8478 LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m->p->WakeAtUTC - utc);
8479 m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond;
8480 }
8481 }
8482
8483 // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
8484 // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
8485 // We will clear this assertion as soon as we think the mainenance activities are done.
8486 mDNSPlatformPreventSleep(DARK_WAKE_TIME, "mDNSResponder:maintenance");
8487
8488 }
8489
8490 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
8491 {
8492 mDNS *const m = (mDNS *const)refcon;
8493 KQueueLock();
8494 (void)service; // Parameter not used
8495 debugf("PowerChanged %X %lX", messageType, messageArgument);
8496
8497 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8498 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8499
8500 switch(messageType)
8501 {
8502 case kIOMessageCanSystemPowerOff: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
8503 case kIOMessageSystemWillPowerOff: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
8504 mDNSCoreMachineSleep(m, true);
8505 if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged();
8506 break;
8507 case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
8508 case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep"); break; // E0000270
8509 case kIOMessageSystemWillSleep: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
8510 mDNSCoreMachineSleep(m, true);
8511 break;
8512 case kIOMessageSystemWillNotSleep: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
8513 case kIOMessageSystemHasPoweredOn: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
8514 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
8515 if (m->SleepState)
8516 {
8517 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
8518 PowerOn(m);
8519 }
8520 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
8521 // the System Configuration Framework "network changed" event that we expect
8522 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
8523 mDNS_Lock(m);
8524 SetNetworkChanged(mDNSPlatformOneSecond * 2);
8525 mDNS_Unlock(m);
8526
8527 break;
8528 case kIOMessageSystemWillRestart: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
8529 case kIOMessageSystemWillPowerOn: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
8530
8531 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
8532 if (m->SleepState != SleepState_Sleeping)
8533 {
8534 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
8535 m->SleepState = SleepState_Sleeping;
8536 mDNSMacOSXNetworkChanged();
8537 }
8538 PowerOn(m);
8539 break;
8540 default: LogSPS("PowerChanged unknown message %X", messageType); break;
8541 }
8542
8543 if (messageType == kIOMessageSystemWillSleep)
8544 m->p->SleepCookie = (long)messageArgument;
8545 else if (messageType == kIOMessageCanSystemSleep)
8546 IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
8547
8548 KQueueUnlock("PowerChanged Sleep/Wake");
8549 }
8550
8551 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
8552 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
8553 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
8554 mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
8555 {
8556 mDNS *const m = (mDNS *const)refcon;
8557 KQueueLock();
8558 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
8559 connection, token, eventDescriptor,
8560 eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "",
8561 eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "",
8562 eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "",
8563 eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
8564 eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : "");
8565
8566 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8567 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8568
8569 if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
8570 {
8571 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
8572 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
8573 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
8574 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
8575 if (m->SleepLimit)
8576 {
8577 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8578 IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie);
8579 m->SleepLimit = 0;
8580 }
8581 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8582 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
8583 if (m->SleepState != SleepState_Awake)
8584 {
8585 PowerOn(m);
8586 // If the network notifications have already come before we got the wakeup, we ignored them and
8587 // in case we get no more, we need to trigger one.
8588 mDNS_Lock(m);
8589 SetNetworkChanged(mDNSPlatformOneSecond * 2);
8590 mDNS_Unlock(m);
8591 }
8592 IOPMConnectionAcknowledgeEvent(connection, token);
8593 }
8594 else
8595 {
8596 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
8597 // we should hear nothing more until we're told that the CPU has started executing again.
8598 if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
8599 //sleep(5);
8600 //mDNSMacOSXNetworkChanged(m);
8601 mDNSCoreMachineSleep(m, true);
8602 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
8603 m->p->SleepCookie = token;
8604 }
8605
8606 KQueueUnlock("SnowLeopardPowerChanged Sleep/Wake");
8607 }
8608 #endif
8609
8610 #if COMPILER_LIKES_PRAGMA_MARK
8611 #pragma mark -
8612 #pragma mark - /etc/hosts support
8613 #endif
8614
8615 // Implementation Notes
8616 //
8617 // As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
8618 // 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
8619 // them into a hash table. The implementation need to be able to do the following things efficiently
8620 //
8621 // 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
8622 // 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
8623 // 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
8624 // need to be able set the RRSet of a resource record to the first one in the list and also update when
8625 // one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
8626 // not a duplicate
8627 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
8628 //
8629 // CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
8630 // "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
8631 // of the core layer which does all of the above very efficiently
8632
8633 #define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
8634
8635 mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
8636 {
8637 (void)m; // unused
8638 (void)rr;
8639 (void)result;
8640 if (result == mStatus_MemFree)
8641 {
8642 LogInfo("FreeEtcHosts: %s", ARDisplayString(m, rr));
8643 freeL("etchosts", rr);
8644 }
8645 }
8646
8647 // Returns true on success and false on failure
8648 mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(const domainname *domain, const struct sockaddr *sa, const domainname *cname, char *ifname, AuthHash *auth)
8649 {
8650 AuthRecord *rr;
8651 mDNSu32 namehash;
8652 AuthGroup *ag;
8653 mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly;
8654 mDNSu16 rrtype;
8655
8656 if (!domain)
8657 {
8658 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
8659 return mDNSfalse;
8660 }
8661 if (!sa && !cname)
8662 {
8663 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
8664 return mDNSfalse;
8665 }
8666
8667 if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
8668 {
8669 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa->sa_family);
8670 return mDNSfalse;
8671 }
8672
8673
8674 if (ifname)
8675 {
8676 mDNSu32 ifindex = if_nametoindex(ifname);
8677 if (!ifindex)
8678 {
8679 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain->c, ifname);
8680 return mDNSfalse;
8681 }
8682 InterfaceID = (mDNSInterfaceID)(uintptr_t)ifindex;
8683 }
8684
8685 if (sa)
8686 rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA);
8687 else
8688 rrtype = kDNSType_CNAME;
8689
8690 // Check for duplicates. See whether we parsed an entry before like this ?
8691 namehash = DomainNameHashValue(domain);
8692 ag = AuthGroupForName(auth, namehash, domain);
8693 if (ag)
8694 {
8695 rr = ag->members;
8696 while (rr)
8697 {
8698 if (rr->resrec.rrtype == rrtype)
8699 {
8700 if (rrtype == kDNSType_A)
8701 {
8702 mDNSv4Addr ip;
8703 ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
8704 if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip))
8705 {
8706 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c);
8707 return mDNSfalse;
8708 }
8709 }
8710 else if (rrtype == kDNSType_AAAA)
8711 {
8712 mDNSv6Addr ip6;
8713 ip6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
8714 ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
8715 ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
8716 ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
8717 if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6))
8718 {
8719 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c);
8720 return mDNSfalse;
8721 }
8722 }
8723 else if (rrtype == kDNSType_CNAME)
8724 {
8725 if (SameDomainName(&rr->resrec.rdata->u.name, cname))
8726 {
8727 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname->c, domain->c);
8728 return mDNSfalse;
8729 }
8730 }
8731 }
8732 rr = rr->next;
8733 }
8734 }
8735 rr= mallocL("etchosts", sizeof(*rr));
8736 if (rr == NULL) return mDNSfalse;
8737 mDNSPlatformMemZero(rr, sizeof(*rr));
8738 mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
8739 AssignDomainName(&rr->namestorage, domain);
8740
8741 if (sa)
8742 {
8743 rr->resrec.rdlength = sa->sa_family == AF_INET ? sizeof(mDNSv4Addr) : sizeof(mDNSv6Addr);
8744 if (sa->sa_family == AF_INET)
8745 rr->resrec.rdata->u.ipv4.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
8746 else
8747 {
8748 rr->resrec.rdata->u.ipv6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
8749 rr->resrec.rdata->u.ipv6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
8750 rr->resrec.rdata->u.ipv6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
8751 rr->resrec.rdata->u.ipv6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
8752 }
8753 }
8754 else
8755 {
8756 rr->resrec.rdlength = DomainNameLength(cname);
8757 rr->resrec.rdata->u.name.c[0] = 0;
8758 AssignDomainName(&rr->resrec.rdata->u.name, cname);
8759 }
8760 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
8761 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
8762 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(&mDNSStorage, rr));
8763 InsertAuthRecord(&mDNSStorage, auth, rr);
8764 return mDNStrue;
8765 }
8766
8767 mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **name)
8768 {
8769 int i;
8770
8771 *name = NULL;
8772 for (i = start; i < length; i++)
8773 {
8774 if (buffer[i] == '#')
8775 return -1;
8776 if (buffer[i] != ' ' && buffer[i] != ',' && buffer[i] != '\t')
8777 {
8778 *name = &buffer[i];
8779
8780 // Found the start of a name, find the end and null terminate
8781 for (i++; i < length; i++)
8782 {
8783 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
8784 {
8785 buffer[i] = 0;
8786 break;
8787 }
8788 }
8789 return i;
8790 }
8791 }
8792 return -1;
8793 }
8794
8795 mDNSlocal void mDNSMacOSXParseEtcHostsLine(char *buffer, ssize_t length, AuthHash *auth)
8796 {
8797 int i;
8798 int ifStart = 0;
8799 char *ifname = NULL;
8800 domainname name1d;
8801 domainname name2d;
8802 char *name1;
8803 char *name2;
8804 int aliasIndex;
8805
8806 //Ignore leading whitespaces and tabs
8807 while (*buffer == ' ' || *buffer == '\t')
8808 {
8809 buffer++;
8810 length--;
8811 }
8812
8813 // Find the end of the address string
8814 for (i = 0; i < length; i++)
8815 {
8816 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t' || buffer[i] == '%')
8817 {
8818 if (buffer[i] == '%')
8819 ifStart = i + 1;
8820 buffer[i] = 0;
8821 break;
8822 }
8823 }
8824
8825 // Convert the address string to an address
8826 struct addrinfo hints;
8827 bzero(&hints, sizeof(hints));
8828 hints.ai_flags = AI_NUMERICHOST;
8829 struct addrinfo *gairesults = NULL;
8830 if (getaddrinfo(buffer, NULL, &hints, &gairesults) != 0)
8831 {
8832 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
8833 return;
8834 }
8835
8836 if (ifStart)
8837 {
8838 // Parse the interface
8839 ifname = &buffer[ifStart];
8840 for (i = ifStart + 1; i < length; i++)
8841 {
8842 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
8843 {
8844 buffer[i] = 0;
8845 break;
8846 }
8847 }
8848 }
8849
8850 i = EtcHostsParseOneName(i + 1, length, buffer, &name1);
8851 if (i == length)
8852 {
8853 // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
8854 if (!MakeDomainNameFromDNSNameString(&name1d, name1))
8855 {
8856 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
8857 freeaddrinfo(gairesults);
8858 return;
8859 }
8860 mDNSMacOSXCreateEtcHostsEntry(&name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
8861 }
8862 else if (i != -1)
8863 {
8864 domainname first;
8865 // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
8866 // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
8867 // doing the right thing.
8868
8869 if (!MakeDomainNameFromDNSNameString(&first, name1))
8870 {
8871 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
8872 freeaddrinfo(gairesults);
8873 return;
8874 }
8875 mDNSMacOSXCreateEtcHostsEntry(&first, gairesults->ai_addr, mDNSNULL, ifname, auth);
8876
8877 // /etc/hosts alias discussion:
8878 //
8879 // If the /etc/hosts has an entry like this
8880 //
8881 // ip_address cname [aliases...]
8882 // 1.2.3.4 sun star bright
8883 //
8884 // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
8885 // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
8886 //
8887 // To achieve this, we need to add the entry like this:
8888 //
8889 // sun A 1.2.3.4
8890 // star CNAME sun
8891 // bright CNAME sun
8892 //
8893 // We store the first name we parsed in "first" and add the address (A/AAAA) record.
8894 // Then we parse additional names adding CNAME records till we reach the end.
8895
8896 aliasIndex = 0;
8897 while (i < length)
8898 {
8899 // Continue to parse additional aliases until we reach end of the line and
8900 // for each "alias" parsed, add a CNAME record where "alias" points to the first "name".
8901 // See also /etc/hosts alias discussion above
8902
8903 i = EtcHostsParseOneName(i + 1, length, buffer, &name2);
8904
8905 if (name2)
8906 {
8907 if ((aliasIndex) && (*buffer == *name2))
8908 break; // break out of the loop if we wrap around
8909
8910 if (!MakeDomainNameFromDNSNameString(&name2d, name2))
8911 {
8912 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2);
8913 freeaddrinfo(gairesults);
8914 return;
8915 }
8916 // Ignore if it points to itself
8917 if (!SameDomainName(&first, &name2d))
8918 {
8919 if (!mDNSMacOSXCreateEtcHostsEntry(&name2d, mDNSNULL, &first, ifname, auth))
8920 {
8921 freeaddrinfo(gairesults);
8922 return;
8923 }
8924 }
8925 else
8926 {
8927 LogInfo("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names first %##s, name2 %##s", first.c, name2d.c);
8928 }
8929 aliasIndex++;
8930 }
8931 else if (!aliasIndex)
8932 {
8933 // We have never parsed any aliases. This case happens if there
8934 // is just one name and some extra white spaces at the end.
8935 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c);
8936 break;
8937 }
8938 }
8939 }
8940 freeaddrinfo(gairesults);
8941 }
8942
8943 mDNSlocal void mDNSMacOSXParseEtcHosts(int fd, AuthHash *auth)
8944 {
8945 mDNSBool good;
8946 char buf[ETCHOSTS_BUFSIZE];
8947 ssize_t len;
8948 FILE *fp;
8949
8950 if (fd == -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
8951
8952 fp = fopen("/etc/hosts", "r");
8953 if (!fp) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
8954
8955 while (1)
8956 {
8957 good = (fgets(buf, ETCHOSTS_BUFSIZE, fp) != NULL);
8958 if (!good) break;
8959
8960 // skip comment and empty lines
8961 if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n')
8962 continue;
8963
8964 len = strlen(buf);
8965 if (!len) break; // sanity check
8966 //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
8967 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
8968 {
8969 buf[len - 1] = '\0';
8970 len = len - 1;
8971 }
8972 // fgets always null terminates and hence even if we have no
8973 // newline at the end, it is null terminated. The callee
8974 // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
8975 // buf[length] is zero and hence we decrement len to reflect that.
8976 if (len)
8977 {
8978 //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
8979 //here we need to check for just \r but taking extra caution.
8980 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
8981 {
8982 buf[len - 1] = '\0';
8983 len = len - 1;
8984 }
8985 }
8986 if (!len) //Sanity Check: len should never be zero
8987 {
8988 LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
8989 continue;
8990 }
8991 mDNSMacOSXParseEtcHostsLine(buf, len, auth);
8992 }
8993 fclose(fp);
8994 }
8995
8996 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m);
8997
8998 mDNSlocal int mDNSMacOSXGetEtcHostsFD(void)
8999 {
9000 mDNS *const m = &mDNSStorage;
9001 #ifdef __DISPATCH_GROUP__
9002 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9003 static dispatch_queue_t etcq = 0;
9004 static dispatch_source_t etcsrc = 0;
9005 static dispatch_source_t hostssrc = 0;
9006
9007 // First time through? just schedule ourselves on the main queue and we'll do the work later
9008 if (!etcq)
9009 {
9010 etcq = dispatch_get_main_queue();
9011 if (etcq)
9012 {
9013 // Do this work on the queue, not here - solves potential synchronization issues
9014 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9015 }
9016 return -1;
9017 }
9018
9019 if (hostssrc) return dispatch_source_get_handle(hostssrc);
9020 #endif
9021
9022 int fd = open("/etc/hosts", O_RDONLY);
9023
9024 #ifdef __DISPATCH_GROUP__
9025 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9026 if (fd == -1)
9027 {
9028 // If the open failed and we're already watching /etc, we're done
9029 if (etcsrc) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd; }
9030
9031 // we aren't watching /etc, we should be
9032 fd = open("/etc", O_RDONLY);
9033 if (fd == -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
9034 etcsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME, etcq);
9035 if (etcsrc == NULL)
9036 {
9037 close(fd);
9038 return -1;
9039 }
9040 dispatch_source_set_event_handler(etcsrc,
9041 ^{
9042 u_int32_t flags = dispatch_source_get_data(etcsrc);
9043 LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags);
9044 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9045 {
9046 dispatch_source_cancel(etcsrc);
9047 dispatch_release(etcsrc);
9048 etcsrc = NULL;
9049 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9050 return;
9051 }
9052 if ((flags & DISPATCH_VNODE_WRITE) != 0 && hostssrc == NULL)
9053 {
9054 mDNSMacOSXUpdateEtcHosts(m);
9055 }
9056 });
9057 dispatch_source_set_cancel_handler(etcsrc, ^{close(fd);});
9058 dispatch_resume(etcsrc);
9059
9060 // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
9061 fd = open("/etc/hosts", O_RDONLY | O_EVTONLY);
9062 if (fd == -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
9063 }
9064
9065 // create a dispatch source to watch for changes to hosts file
9066 hostssrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd,
9067 (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME |
9068 DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_LINK | DISPATCH_VNODE_REVOKE), etcq);
9069 if (hostssrc == NULL)
9070 {
9071 close(fd);
9072 return -1;
9073 }
9074 dispatch_source_set_event_handler(hostssrc,
9075 ^{
9076 u_int32_t flags = dispatch_source_get_data(hostssrc);
9077 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags);
9078 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9079 {
9080 dispatch_source_cancel(hostssrc);
9081 dispatch_release(hostssrc);
9082 hostssrc = NULL;
9083 // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
9084 // the block immediately, we try to open the file and the file may not exist and may
9085 // fail to get a notification in the future. When the file does not exist and
9086 // we start to monitor the directory, on "dispatch_resume" of that source, there
9087 // is no guarantee that the file creation will be notified always because when
9088 // the dispatch_resume returns, the kevent manager may not have registered the
9089 // kevent yet but the file may have been created
9090 usleep(1000000);
9091 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9092 return;
9093 }
9094 if ((flags & DISPATCH_VNODE_WRITE) != 0)
9095 {
9096 mDNSMacOSXUpdateEtcHosts(m);
9097 }
9098 });
9099 dispatch_source_set_cancel_handler(hostssrc, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd); close(fd);});
9100 dispatch_resume(hostssrc);
9101
9102 // Cleanup /etc source, no need to watch it if we already have /etc/hosts
9103 if (etcsrc)
9104 {
9105 dispatch_source_cancel(etcsrc);
9106 dispatch_release(etcsrc);
9107 etcsrc = NULL;
9108 }
9109
9110 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
9111 return hostssrc ? (int)dispatch_source_get_handle(hostssrc) : -1;
9112 #else
9113 (void)m;
9114 return fd;
9115 #endif
9116 }
9117
9118 // When /etc/hosts is modified, flush all the cache records as there may be local
9119 // authoritative answers now
9120 mDNSlocal void FlushAllCacheRecords(mDNS *const m)
9121 {
9122 CacheRecord *cr;
9123 mDNSu32 slot;
9124 CacheGroup *cg;
9125
9126 FORALL_CACHERECORDS(slot, cg, cr)
9127 {
9128 // Skip multicast.
9129 if (cr->resrec.InterfaceID) continue;
9130
9131 // If a resource record can answer A or AAAA, they need to be flushed so that we will
9132 // never used to deliver an ADD or RMV
9133 if (RRTypeAnswersQuestionType(&cr->resrec, kDNSType_A) ||
9134 RRTypeAnswersQuestionType(&cr->resrec, kDNSType_AAAA))
9135 {
9136 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr));
9137 mDNS_PurgeCacheResourceRecord(m, cr);
9138 }
9139 }
9140 }
9141
9142 // Add new entries to the core. If justCheck is set, this function does not add, just returns true
9143 mDNSlocal mDNSBool EtcHostsAddNewEntries(AuthHash *newhosts, mDNSBool justCheck)
9144 {
9145 mDNS *const m = &mDNSStorage;
9146 AuthGroup *ag;
9147 mDNSu32 slot;
9148 AuthRecord *rr, *primary, *rrnext;
9149 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9150 for (ag = newhosts->rrauth_hash[slot]; ag; ag = ag->next)
9151 {
9152 primary = NULL;
9153 for (rr = ag->members; rr; rr = rrnext)
9154 {
9155 rrnext = rr->next;
9156 AuthGroup *ag1;
9157 AuthRecord *rr1;
9158 mDNSBool found = mDNSfalse;
9159 ag1 = AuthGroupForRecord(&m->rrauth, &rr->resrec);
9160 if (ag1 && ag1->members)
9161 {
9162 if (!primary) primary = ag1->members;
9163 rr1 = ag1->members;
9164 while (rr1)
9165 {
9166 // We are not using InterfaceID in checking for duplicates. This means,
9167 // if there are two addresses for a given name e.g., fe80::1%en0 and
9168 // fe80::1%en1, we only add the first one. It is not clear whether
9169 // this is a common case. To fix this, we also need to modify
9170 // mDNS_Register_internal in how it handles duplicates. If it becomes a
9171 // common case, we will fix it then.
9172 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9173 {
9174 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
9175 found = mDNStrue;
9176 break;
9177 }
9178 rr1 = rr1->next;
9179 }
9180 }
9181 if (!found)
9182 {
9183 if (justCheck)
9184 {
9185 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m, rr));
9186 return mDNStrue;
9187 }
9188 RemoveAuthRecord(m, newhosts, rr);
9189 // if there is no primary, point to self
9190 rr->RRSet = (primary ? primary : rr);
9191 rr->next = NULL;
9192 LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m, rr));
9193 if (mDNS_Register_internal(m, rr) != mStatus_NoError)
9194 LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr));
9195 }
9196 }
9197 }
9198 return mDNSfalse;
9199 }
9200
9201 // Delete entries from the core that are no longer needed. If justCheck is set, this function
9202 // does not delete, just returns true
9203 mDNSlocal mDNSBool EtcHostsDeleteOldEntries(AuthHash *newhosts, mDNSBool justCheck)
9204 {
9205 mDNS *const m = &mDNSStorage;
9206 AuthGroup *ag;
9207 mDNSu32 slot;
9208 AuthRecord *rr, *rrnext;
9209 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9210 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
9211 for (rr = ag->members; rr; rr = rrnext)
9212 {
9213 mDNSBool found = mDNSfalse;
9214 AuthGroup *ag1;
9215 AuthRecord *rr1;
9216 rrnext = rr->next;
9217 if (rr->RecordCallback != FreeEtcHosts) continue;
9218 ag1 = AuthGroupForRecord(newhosts, &rr->resrec);
9219 if (ag1)
9220 {
9221 rr1 = ag1->members;
9222 while (rr1)
9223 {
9224 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9225 {
9226 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m, rr));
9227 found = mDNStrue;
9228 break;
9229 }
9230 rr1 = rr1->next;
9231 }
9232 }
9233 // there is no corresponding record in newhosts for the same name. This means
9234 // we should delete this from the core.
9235 if (!found)
9236 {
9237 if (justCheck)
9238 {
9239 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m, rr));
9240 return mDNStrue;
9241 }
9242 // if primary is going away, make sure that the rest of the records
9243 // point to the new primary
9244 if (rr == ag->members)
9245 {
9246 AuthRecord *new_primary = rr->next;
9247 AuthRecord *r = new_primary;
9248 while (r)
9249 {
9250 if (r->RRSet == rr)
9251 {
9252 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m, r));
9253 r->RRSet = new_primary;
9254 }
9255 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m, r), r->resrec.name);
9256 r = r->next;
9257 }
9258 }
9259 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m, rr));
9260 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
9261 }
9262 }
9263 return mDNSfalse;
9264 }
9265
9266 mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context)
9267 {
9268 AuthHash *newhosts = (AuthHash *)context;
9269
9270 mDNS_CheckLock(m);
9271
9272 //Delete old entries from the core if they are not present in the newhosts
9273 EtcHostsDeleteOldEntries(newhosts, mDNSfalse);
9274 // Add the new entries to the core if not already present in the core
9275 EtcHostsAddNewEntries(newhosts, mDNSfalse);
9276 }
9277
9278 mDNSlocal void FreeNewHosts(AuthHash *newhosts)
9279 {
9280 mDNSu32 slot;
9281 AuthGroup *ag, *agnext;
9282 AuthRecord *rr, *rrnext;
9283
9284 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9285 for (ag = newhosts->rrauth_hash[slot]; ag; ag = agnext)
9286 {
9287 agnext = ag->next;
9288 for (rr = ag->members; rr; rr = rrnext)
9289 {
9290 rrnext = rr->next;
9291 freeL("etchosts", rr);
9292 }
9293 freeL("AuthGroups", ag);
9294 }
9295 }
9296
9297 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
9298 {
9299 AuthHash newhosts;
9300
9301 // As we will be modifying the core, we can only have one thread running at
9302 // any point in time.
9303 KQueueLock();
9304
9305 mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
9306
9307 // Get the file desecriptor (will trigger us to start watching for changes)
9308 int fd = mDNSMacOSXGetEtcHostsFD();
9309 if (fd != -1)
9310 {
9311 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd);
9312 mDNSMacOSXParseEtcHosts(fd, &newhosts);
9313 }
9314 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
9315
9316 // Optimization: Detect whether /etc/hosts changed or not.
9317 //
9318 // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
9319 // newhosts is already registered with core. If we find at least one entry that is not
9320 // registered with core, then it means we have work to do.
9321 //
9322 // 2. Next, we check to see if any of the entries that are registered with core is not present
9323 // in newhosts. If we find at least one entry that is not present, it means we have work to
9324 // do.
9325 //
9326 // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
9327 // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
9328 // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
9329 // in the future and this code does not have to change.
9330 mDNS_Lock(m);
9331 // Add the new entries to the core if not already present in the core
9332 if (!EtcHostsAddNewEntries(&newhosts, mDNStrue))
9333 {
9334 // No new entries to add, check to see if we need to delete any old entries from the
9335 // core if they are not present in the newhosts
9336 if (!EtcHostsDeleteOldEntries(&newhosts, mDNStrue))
9337 {
9338 LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
9339 FreeNewHosts(&newhosts);
9340 mDNS_Unlock(m);
9341 KQueueUnlock("/etc/hosts changed");
9342 return;
9343 }
9344 }
9345
9346 // This will flush the cache, stop and start the query so that the queries
9347 // can look at the /etc/hosts again
9348 //
9349 // Notes:
9350 //
9351 // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
9352 // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
9353 // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
9354 // delivers these events in the right order and then calls us back to delete them.
9355 //
9356 // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
9357 // is a common function that looks at all local auth records and delivers a RMV including
9358 // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
9359 // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
9360 // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
9361 // is called back where we do the Registration of the record. This results in RMV followed by ADD which
9362 // looks normal.
9363 mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts);
9364 FreeNewHosts(&newhosts);
9365 mDNS_Unlock(m);
9366 KQueueUnlock("/etc/hosts changed");
9367 }
9368
9369 #if COMPILER_LIKES_PRAGMA_MARK
9370 #pragma mark -
9371 #pragma mark - Initialization & Teardown
9372 #endif
9373
9374 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
9375 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
9376 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
9377 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
9378
9379 // Major version 13 is 10.9.x
9380 mDNSexport void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
9381 {
9382 int major = 0, minor = 0;
9383 char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
9384 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
9385 if (vers)
9386 {
9387 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
9388 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
9389 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
9390 if (cfprodname)
9391 CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
9392 if (cfprodvers)
9393 CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
9394 if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
9395 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
9396 CFRelease(vers);
9397 }
9398 if (!major)
9399 {
9400 major = 13;
9401 LogMsg("Note: No Major Build Version number found; assuming 13");
9402 }
9403 if (HINFO_SWstring)
9404 mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion));
9405 //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
9406
9407 // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
9408 if ((prodname[0] & 0xDF) == 'M')
9409 OSXVers = major;
9410 else
9411 iOSVers = major;
9412 }
9413
9414 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
9415 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
9416 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
9417 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
9418 {
9419 int err = -1;
9420 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
9421 if (s < 3)
9422 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
9423 else
9424 {
9425 struct sockaddr_in s5353;
9426 s5353.sin_family = AF_INET;
9427 s5353.sin_port = MulticastDNSPort.NotAnInteger;
9428 s5353.sin_addr.s_addr = 0;
9429 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
9430 close(s);
9431 }
9432
9433 if (err) LogMsg("No unicast UDP responses");
9434 else debugf("Unicast UDP responses okay");
9435 return(err == 0);
9436 }
9437
9438 mDNSlocal void CreatePTRRecord(const domainname *domain)
9439 {
9440 AuthRecord *rr;
9441 const domainname *pname = (domainname *)"\x9" "localhost";
9442
9443 rr= mallocL("localhosts", sizeof(*rr));
9444 if (rr == NULL) return;
9445 mDNSPlatformMemZero(rr, sizeof(*rr));
9446
9447 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
9448 AssignDomainName(&rr->namestorage, domain);
9449
9450 rr->resrec.rdlength = DomainNameLength(pname);
9451 rr->resrec.rdata->u.name.c[0] = 0;
9452 AssignDomainName(&rr->resrec.rdata->u.name, pname);
9453
9454 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
9455 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
9456 mDNS_Register(&mDNSStorage, rr);
9457 }
9458
9459 // Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
9460 // on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
9461 // fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
9462 // a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
9463 //
9464 // Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
9465 // intentionally to avoid adding to the complexity of code handling /etc/hosts.
9466 mDNSlocal void SetupLocalHostRecords(void)
9467 {
9468 domainname name;
9469
9470 MakeDomainNameFromDNSNameString(&name, "1.0.0.127.in-addr.arpa.");
9471 CreatePTRRecord(&name);
9472
9473 MakeDomainNameFromDNSNameString(&name, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.");
9474 CreatePTRRecord(&name);
9475 }
9476
9477 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
9478 mDNSlocal void setSameDomainLabelPointer(void);
9479 #endif
9480
9481 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
9482 // 1) query for b._dns-sd._udp.local on LocalOnly interface
9483 // (.local manually generated via explicit callback)
9484 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
9485 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
9486 // 4) result above should generate a callback from question in (1). result added to global list
9487 // 5) global list delivered to client via GetSearchDomainList()
9488 // 6) client calls to enumerate domains now go over LocalOnly interface
9489 // (!!!KRS may add outgoing interface in addition)
9490
9491 #if TARGET_OS_IPHONE
9492 mDNSlocal mDNSBool IsAppleInternalBuild(void)
9493 {
9494 return (os_variant_has_internal_diagnostics("com.apple.mDNSResponder") ? mDNStrue : mDNSfalse);
9495 }
9496
9497 mDNSlocal mStatus RegisterLocalOnlyAddressRecord(const domainname *const name, mDNSu16 type, const void *rdata, mDNSu16 rdlength)
9498 {
9499 switch(type)
9500 {
9501 case kDNSType_A:
9502 if (rdlength != 4) return (mStatus_BadParamErr);
9503 break;
9504
9505 case kDNSType_AAAA:
9506 if (rdlength != 16) return (mStatus_BadParamErr);
9507 break;
9508
9509 default:
9510 return (mStatus_BadParamErr);
9511 }
9512
9513 AuthRecord *rr = mallocL("etchosts", sizeof(*rr));
9514 if (!rr) return (mStatus_NoMemoryErr);
9515 mDNSPlatformMemZero(rr, sizeof(*rr));
9516
9517 mDNS_SetupResourceRecord(rr, NULL, mDNSInterface_LocalOnly, type, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
9518 AssignDomainName(&rr->namestorage, name);
9519 mDNSPlatformMemCopy(rr->resrec.rdata->u.data, rdata, rdlength);
9520
9521 const mStatus err = mDNS_Register_internal(&mDNSStorage, rr);
9522 if (err)
9523 {
9524 LogMsg("RegisterLocalOnlyAddressRecord: mDNS_Register error %d registering %s", err, ARDisplayString(&mDNSStorage, rr));
9525 freeL("etchosts", rr);
9526 }
9527 return (err);
9528 }
9529
9530 mDNSlocal void RegisterLocalOnlyARecord(const domainname *const name, const mDNSv4Addr *const addr)
9531 {
9532 RegisterLocalOnlyAddressRecord(name, kDNSType_A, addr->b, (mDNSu16)sizeof(mDNSv4Addr));
9533 }
9534
9535 mDNSlocal void RegisterLocalOnlyAAAARecord(const domainname *const name, const mDNSv6Addr *const addr)
9536 {
9537 RegisterLocalOnlyAddressRecord(name, kDNSType_AAAA, addr->b, (mDNSu16)sizeof(mDNSv6Addr));
9538 }
9539 #endif
9540
9541 mDNSlocal void NWIEventHandler(void)
9542 {
9543 mDNS * const m = &mDNSStorage;
9544 nwi_state_t newState = nwi_state_copy();
9545
9546 KQueueLock();
9547 const nwi_state_t oldState = m->p->NWIState;
9548 m->p->NWIState = newState;
9549 if (m->p->NWIState)
9550 {
9551 uint32_t lastIfIndex = 0;
9552 mDNSBool lastCLAT46 = mDNSfalse;
9553 for (DNSServer *server = m->DNSServers; server; server = server->next)
9554 {
9555 const uint32_t ifIndex = (uint32_t)((uintptr_t)server->interface);
9556 if (ifIndex == 0) continue;
9557 if (ifIndex == lastIfIndex)
9558 {
9559 server->isCLAT46 = lastCLAT46;
9560 continue;
9561 }
9562 server->isCLAT46 = NWIInterfaceHasCLAT46(m->p->NWIState, ifIndex);
9563 lastIfIndex = ifIndex;
9564 lastCLAT46 = server->isCLAT46;
9565 }
9566 }
9567 KQueueUnlock("NWIEventHandler");
9568 if (oldState) nwi_state_release(oldState);
9569 }
9570
9571 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
9572 {
9573 mStatus err;
9574
9575 char HINFO_SWstring[256] = "";
9576 mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
9577
9578 #if APPLE_OSX_mDNSResponder
9579 setSameDomainLabelPointer();
9580 #endif
9581
9582 err = mDNSHelperInit();
9583 if (err)
9584 return err;
9585
9586 // Store mDNSResponder Platform
9587 if (OSXVers)
9588 {
9589 m->mDNS_plat = platform_OSX;
9590 }
9591 else if (iOSVers)
9592 {
9593 if (IsAppleTV())
9594 m->mDNS_plat = platform_Atv;
9595 else
9596 m->mDNS_plat = platform_iOS;
9597 }
9598 else
9599 {
9600 m->mDNS_plat = platform_NonApple;
9601 }
9602
9603 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
9604 // 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.
9605 int i;
9606 for (i=0; i<100; i++)
9607 {
9608 domainlabel testlabel;
9609 testlabel.c[0] = 0;
9610 GetUserSpecifiedLocalHostName(&testlabel);
9611 if (testlabel.c[0]) break;
9612 usleep(50000);
9613 }
9614
9615 m->hostlabel.c[0] = 0;
9616
9617 int get_model[2] = { CTL_HW, HW_MODEL };
9618 size_t len_model = sizeof(HINFO_HWstring_buffer);
9619
9620 // Normal Apple model names are of the form "iPhone2,1", and
9621 // internal code names are strings containing no commas, e.g. "N88AP".
9622 // We used to ignore internal code names, but Apple now uses these internal code names
9623 // even in released shipping products, so we no longer ignore strings containing no commas.
9624 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
9625 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
9626 HINFO_HWstring = HINFO_HWstring_buffer;
9627
9628 // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
9629 // For names of the form "N88AP" containg no comma, we use the entire string.
9630 HINFO_HWstring_prefixlen = strchr(HINFO_HWstring_buffer, ',') ? strcspn(HINFO_HWstring, "0123456789") : strlen(HINFO_HWstring);
9631
9632 if (mDNSPlatformInit_CanReceiveUnicast())
9633 m->CanReceiveUnicastOn5353 = mDNStrue;
9634
9635 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
9636 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
9637 if (hlen + slen < 254)
9638 {
9639 m->HIHardware.c[0] = hlen;
9640 m->HISoftware.c[0] = slen;
9641 mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
9642 mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
9643 }
9644
9645 m->p->permanentsockets.port = MulticastDNSPort;
9646 m->p->permanentsockets.m = m;
9647 m->p->permanentsockets.sktv4 = -1;
9648 m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack;
9649 m->p->permanentsockets.kqsv4.KQcontext = &m->p->permanentsockets;
9650 m->p->permanentsockets.kqsv4.KQtask = "IPv4 UDP packet reception";
9651 m->p->permanentsockets.sktv6 = -1;
9652 m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
9653 m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
9654 m->p->permanentsockets.kqsv6.KQtask = "IPv6 UDP packet reception";
9655
9656 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
9657 if (err) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET) failed error %d errno %d (%s)", err, errno, strerror(errno));
9658 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
9659 if (err) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET6) failed error %d errno %d (%s)", err, errno, strerror(errno));
9660
9661 struct sockaddr_in s4;
9662 socklen_t n4 = sizeof(s4);
9663 if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0)
9664 LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
9665 else
9666 m->UnicastPort4.NotAnInteger = s4.sin_port;
9667
9668 if (m->p->permanentsockets.sktv6 >= 0)
9669 {
9670 struct sockaddr_in6 s6;
9671 socklen_t n6 = sizeof(s6);
9672 if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
9673 else m->UnicastPort6.NotAnInteger = s6.sin6_port;
9674 }
9675
9676 m->p->InterfaceList = mDNSNULL;
9677 m->p->userhostlabel.c[0] = 0;
9678 m->p->usernicelabel.c[0] = 0;
9679 m->p->prevoldnicelabel.c[0] = 0;
9680 m->p->prevnewnicelabel.c[0] = 0;
9681 m->p->prevoldhostlabel.c[0] = 0;
9682 m->p->prevnewhostlabel.c[0] = 0;
9683 m->p->NotifyUser = 0;
9684 m->p->KeyChainTimer = 0;
9685 m->p->WakeAtUTC = 0;
9686 m->p->RequestReSleep = 0;
9687 // Assume that everything is good to begin with. If something is not working,
9688 // we will detect that when we start sending questions.
9689 m->p->v4answers = 1;
9690 m->p->v6answers = 1;
9691 m->p->DNSTrigger = 0;
9692 m->p->LastConfigGeneration = 0;
9693
9694 m->AutoTunnelRelayAddr = zerov6Addr;
9695
9696 NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
9697 NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
9698 NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
9699 NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
9700 NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
9701 NetworkChangedKey_StateInterfacePrefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, CFSTR(""), NULL);
9702 if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS || !NetworkChangedKey_StateInterfacePrefix)
9703 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
9704
9705 err = WatchForNetworkChanges(m);
9706 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
9707
9708 err = WatchForSysEvents(m);
9709 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
9710
9711 m->p->NWIState = nwi_state_copy();
9712 uint32_t status = notify_register_dispatch(nwi_state_get_notify_key(), &m->p->NWINotifyToken, dispatch_get_main_queue(),
9713 ^(__unused int token) { NWIEventHandler(); });
9714 if (status == NOTIFY_STATUS_OK)
9715 {
9716 m->p->NWINotifyRegistered = mDNStrue;
9717 }
9718 else
9719 {
9720 LogMsg("mDNSPlatformInit_setup: notify_register_dispatch failed %u", status);
9721 }
9722
9723 mDNSs32 utc = mDNSPlatformUTC();
9724 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
9725 myGetIfAddrs(1);
9726 UpdateInterfaceList(utc);
9727 SetupActiveInterfaces(utc);
9728 ReorderInterfaceList();
9729
9730 // Explicitly ensure that our Keychain operations utilize the system domain.
9731 #ifndef NO_SECURITYFRAMEWORK
9732 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
9733 #endif
9734
9735 mDNS_Lock(m);
9736 SetDomainSecrets(m);
9737 SetLocalDomains();
9738 mDNS_Unlock(m);
9739
9740 #ifndef NO_SECURITYFRAMEWORK
9741 err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
9742 if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
9743 #endif
9744
9745 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
9746 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
9747 #else
9748 IOPMConnection c;
9749 IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
9750 if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
9751 else
9752 {
9753 iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
9754 if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
9755 else
9756 {
9757 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9758 IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue());
9759 LogInfo("IOPMConnectionSetDispatchQueue is now running");
9760 #else
9761 iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
9762 if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
9763 LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
9764 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9765 }
9766 }
9767 m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
9768 if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
9769 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
9770 {
9771 m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
9772 if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
9773 else
9774 {
9775 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9776 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
9777 #else
9778 CFRunLoopAddSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
9779 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9780 }
9781 }
9782
9783 #if APPLE_OSX_mDNSResponder
9784 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
9785 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
9786 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
9787 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
9788 if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9789 else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9790 else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9791 else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
9792 else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; }
9793 else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; }
9794 else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /* 4kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 13W */; }
9795 else if (!strncasecmp(HINFO_HWstring, "AirPort", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 12W */; }
9796 else if ( IsAppleTV() ) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 60 /* 1W */; SPMetricTotalPower = 63 /* 2W */; }
9797 else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
9798 else if (!strncasecmp(HINFO_HWstring, "PowerBook", 9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
9799 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
9800 HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
9801 #endif // APPLE_OSX_mDNSResponder
9802
9803 // Currently this is not defined. SSL code will eventually fix this. If it becomes
9804 // critical, we will define this to workaround the bug in SSL.
9805 #ifdef __SSL_NEEDS_SERIALIZATION__
9806 SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL);
9807 #else
9808 SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
9809 #endif
9810 if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
9811
9812 #if TARGET_OS_IPHONE
9813 // On device OSes (iOS, tvOS, watchOS, etc.), ignore /etc/hosts unless the OS is an internal build. When the /etc/hosts
9814 // file is ignored, LocalOnly auth records will be registered for localhost and broadcasthost addresses contained in the
9815 // standard /etc/hosts file:
9816 //
9817 // 127.0.0.1 localhost
9818 // 255.255.255.255 broadcasthost
9819 // ::1 localhost
9820
9821 if (!IsAppleInternalBuild())
9822 {
9823 const domainname *const localHostName = (const domainname *) "\x9" "localhost";
9824 const domainname *const broadcastHostName = (const domainname *) "\xd" "broadcasthost";
9825 const mDNSv4Addr localHostV4 = { { 127, 0, 0, 1 } };
9826 mDNSv6Addr localHostV6;
9827
9828 // Register localhost 127.0.0.1 A record.
9829
9830 RegisterLocalOnlyARecord(localHostName, &localHostV4);
9831
9832 // Register broadcasthost 255.255.255.255 A record.
9833
9834 RegisterLocalOnlyARecord(broadcastHostName, &onesIPv4Addr);
9835
9836 // Register localhost ::1 AAAA record.
9837
9838 mDNSPlatformMemZero(&localHostV6, sizeof(localHostV6));
9839 localHostV6.b[15] = 1;
9840 RegisterLocalOnlyAAAARecord(localHostName, &localHostV6);
9841 }
9842 else
9843 #endif
9844 {
9845 mDNSMacOSXUpdateEtcHosts(m);
9846 }
9847 SetupLocalHostRecords();
9848
9849 return(mStatus_NoError);
9850 }
9851
9852 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
9853 {
9854 #if MDNS_NO_DNSINFO
9855 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
9856 #endif
9857
9858 // Adding interfaces will use this flag, so set it now.
9859 m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
9860
9861 #if APPLE_OSX_mDNSResponder
9862 m->SPSBrowseCallback = UpdateSPSStatus;
9863 #endif // APPLE_OSX_mDNSResponder
9864
9865 mStatus result = mDNSPlatformInit_setup(m);
9866
9867 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
9868 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
9869 if (result == mStatus_NoError)
9870 {
9871 mDNSCoreInitComplete(m, mStatus_NoError);
9872 initializeD2DPlugins(m);
9873 }
9874 result = DNSSECCryptoInit(m);
9875 return(result);
9876 }
9877
9878 mDNSexport void mDNSPlatformClose(mDNS *const m)
9879 {
9880 if (m->p->PowerConnection)
9881 {
9882 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9883 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);
9884 #else
9885 CFRunLoopRemoveSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
9886 #endif
9887 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
9888 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
9889 IODeregisterForSystemPower(&m->p->PowerNotifier);
9890 IOServiceClose ( m->p->PowerConnection);
9891 IONotificationPortDestroy ( m->p->PowerPortRef);
9892 m->p->PowerConnection = 0;
9893 }
9894
9895 if (m->p->Store)
9896 {
9897 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9898 if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
9899 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
9900 #else
9901 CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode);
9902 CFRunLoopSourceInvalidate(m->p->StoreRLS);
9903 CFRelease(m->p->StoreRLS);
9904 m->p->StoreRLS = NULL;
9905 #endif
9906 CFRelease(m->p->Store);
9907 m->p->Store = NULL;
9908 }
9909
9910 if (m->p->PMRLS)
9911 {
9912 CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->PMRLS, kCFRunLoopDefaultMode);
9913 CFRunLoopSourceInvalidate(m->p->PMRLS);
9914 CFRelease(m->p->PMRLS);
9915 m->p->PMRLS = NULL;
9916 }
9917
9918 if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
9919 if (m->p->NWINotifyRegistered)
9920 {
9921 notify_cancel(m->p->NWINotifyToken);
9922 m->p->NWINotifyRegistered = mDNSfalse;
9923 }
9924 terminateD2DPlugins();
9925
9926 mDNSs32 utc = mDNSPlatformUTC();
9927 MarkAllInterfacesInactive(utc);
9928 ClearInactiveInterfaces(utc);
9929 CloseSocketSet(&m->p->permanentsockets);
9930
9931 #if APPLE_OSX_mDNSResponder
9932 // clean up tunnels
9933 while (m->TunnelClients)
9934 {
9935 ClientTunnel *cur = m->TunnelClients;
9936 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
9937 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
9938 AutoTunnelSetKeys(cur, mDNSfalse);
9939 m->TunnelClients = cur->next;
9940 freeL("ClientTunnel", cur);
9941 }
9942
9943 if (AnonymousRacoonConfig)
9944 {
9945 AnonymousRacoonConfig = mDNSNULL;
9946 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel need not be done in mDNSResponder");
9947 }
9948 #endif // APPLE_OSX_mDNSResponder
9949 }
9950
9951 #if COMPILER_LIKES_PRAGMA_MARK
9952 #pragma mark -
9953 #pragma mark - General Platform Support Layer functions
9954 #endif
9955
9956 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
9957 {
9958 return(arc4random());
9959 }
9960
9961 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
9962 mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
9963
9964 mDNSexport mStatus mDNSPlatformTimeInit(void)
9965 {
9966 // Notes: Typical values for mach_timebase_info:
9967 // tbi.numer = 1000 million
9968 // tbi.denom = 33 million
9969 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
9970 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
9971 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
9972 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
9973 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
9974 //
9975 // Arithmetic notes:
9976 // tbi.denom is at least 1, and not more than 2^32-1.
9977 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
9978 // tbi.denom is at least 1, and not more than 2^32-1.
9979 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
9980 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
9981 // which is unlikely on any current or future Macintosh.
9982 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
9983 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
9984 struct mach_timebase_info tbi;
9985 kern_return_t result = mach_timebase_info(&tbi);
9986 if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
9987 return(result);
9988 }
9989
9990 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
9991 {
9992 if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
9993
9994 static uint64_t last_mach_absolute_time = 0;
9995 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
9996 uint64_t this_mach_absolute_time = mach_absolute_time();
9997 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
9998 {
9999 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
10000 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
10001 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
10002 last_mach_absolute_time = this_mach_absolute_time;
10003 // Note: This bug happens all the time on 10.3
10004 NotifyOfElusiveBug("mach_absolute_time went backwards!",
10005 "This error occurs from time to time, often on newly released hardware, "
10006 "and usually the exact cause is different in each instance.\r\r"
10007 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
10008 "and assign it to Radar Component “Kernel” Version “X”.");
10009 }
10010 last_mach_absolute_time = this_mach_absolute_time;
10011
10012 return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
10013 }
10014
10015 mDNSexport mDNSs32 mDNSPlatformUTC(void)
10016 {
10017 return time(NULL);
10018 }
10019
10020 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
10021 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
10022 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
10023 mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (const char *)src); }
10024 mDNSexport mDNSu32 mDNSPlatformStrLCopy( void *dst, const void *src, mDNSu32 dstlen) { return (strlcpy((char *)dst, (const char *)src, dstlen)); }
10025 mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((const char*)src)); }
10026 mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
10027 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
10028 mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); }
10029 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); }
10030 mDNSexport void mDNSPlatformQsort ( void *base, int nel, int width, int (*compar)(const void *, const void *))
10031 {
10032 return (qsort(base, nel, width, compar));
10033 }
10034 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
10035 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
10036 mDNSexport void * mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL("mDNSPlatformMemAllocateClear", len)); }
10037 #endif
10038 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
10039
10040 mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason)
10041 {
10042 mDNS *const m = &mDNSStorage;
10043 if (allowSleep && m->p->IOPMAssertion)
10044 {
10045 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
10046 IOPMAssertionRelease(m->p->IOPMAssertion);
10047 m->p->IOPMAssertion = 0;
10048 }
10049 else if (!allowSleep)
10050 {
10051 #ifdef kIOPMAssertionTypeNoIdleSleep
10052 if (m->p->IOPMAssertion)
10053 {
10054 IOPMAssertionRelease(m->p->IOPMAssertion);
10055 m->p->IOPMAssertion = 0;
10056 }
10057
10058 CFStringRef assertionName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%d %s"), getprogname(), getpid(), reason ? reason : "");
10059 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, assertionName ? assertionName : CFSTR("mDNSResponder"), &m->p->IOPMAssertion);
10060 if (assertionName) CFRelease(assertionName);
10061 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__);
10062 #endif
10063 }
10064 }
10065
10066 mDNSexport void mDNSPlatformPreventSleep(mDNSu32 timeout, const char *reason)
10067 {
10068 mDNS *const m = &mDNSStorage;
10069 if (m->p->IOPMAssertion)
10070 {
10071 LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout, reason);
10072 return;
10073 }
10074 #ifdef kIOPMAssertionTypeNoIdleSleep
10075
10076 #if TARGET_OS_EMBEDDED
10077 if (!IsAppleTV())
10078 return; // No need for maintenance wakes on non-AppleTV embedded devices.
10079 #endif
10080
10081 double timeoutVal = (double)timeout;
10082 CFStringRef str = CFStringCreateWithCString(NULL, reason, kCFStringEncodingUTF8);
10083 CFNumberRef Timeout_num = CFNumberCreate(NULL, kCFNumberDoubleType, &timeoutVal);
10084 CFMutableDictionaryRef assertionProperties = CFDictionaryCreateMutable(NULL, 0,
10085 &kCFTypeDictionaryKeyCallBacks,
10086 &kCFTypeDictionaryValueCallBacks);
10087 if (IsAppleTV())
10088 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertPreventUserIdleSystemSleep);
10089 else
10090 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertMaintenanceActivity);
10091
10092 CFDictionarySetValue(assertionProperties, kIOPMAssertionTimeoutKey, Timeout_num);
10093 CFDictionarySetValue(assertionProperties, kIOPMAssertionNameKey, str);
10094
10095 IOPMAssertionCreateWithProperties(assertionProperties, (IOPMAssertionID *)&m->p->IOPMAssertion);
10096 CFRelease(str);
10097 CFRelease(Timeout_num);
10098 CFRelease(assertionProperties);
10099 LogSPS("Got an idle sleep assertion for %d seconds for %s", timeout, reason);
10100 #endif
10101 }
10102
10103 mDNSexport void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
10104 {
10105 mDNSu32 ifindex;
10106
10107 // Sanity check
10108 ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, InterfaceID, mDNStrue);
10109 if (ifindex <= 0)
10110 {
10111 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
10112 return;
10113 }
10114 mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration);
10115 }
10116
10117 mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
10118 {
10119 NetworkInterfaceInfoOSX *info;
10120
10121 if (InterfaceID == mDNSInterface_P2P)
10122 return mDNStrue;
10123
10124 // mDNSInterface_BLE not considered a D2D interface for the purpose of this
10125 // routine, since it's not implemented via a D2D plugin.
10126 if (InterfaceID == mDNSInterface_BLE)
10127 return mDNSfalse;
10128
10129 if ( (InterfaceID == mDNSInterface_Any)
10130 || (InterfaceID == mDNSInterfaceMark)
10131 || (InterfaceID == mDNSInterface_LocalOnly)
10132 || (InterfaceID == mDNSInterface_Unicast))
10133 return mDNSfalse;
10134
10135 // Compare to cached AWDL interface ID.
10136 if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
10137 return mDNStrue;
10138
10139 info = IfindexToInterfaceInfoOSX(InterfaceID);
10140 if (info == NULL)
10141 {
10142 // this log message can print when operations are stopped on an interface that has gone away
10143 LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID);
10144 return mDNSfalse;
10145 }
10146
10147 return (mDNSBool) info->D2DInterface;
10148 }
10149
10150 // Filter records send over P2P (D2D) type interfaces
10151 // Note that the terms P2P and D2D are used synonymously in the current code and comments.
10152 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
10153 {
10154 // For an explicit match to a valid interface ID, return true.
10155 if (rr->resrec.InterfaceID == InterfaceID)
10156 return mDNStrue;
10157
10158 // Only filtering records for D2D type interfaces, return true for all other interface types.
10159 if (!mDNSPlatformInterfaceIsD2D(InterfaceID))
10160 return mDNStrue;
10161
10162 // If it's an AWDL interface the record must be explicitly marked to include AWDL.
10163 if (InterfaceID == AWDLInterfaceID)
10164 {
10165 if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10166 return mDNStrue;
10167 else
10168 return mDNSfalse;
10169 }
10170
10171 // Send record if it is explicitly marked to include all other P2P type interfaces.
10172 if (rr->ARType == AuthRecordAnyIncludeP2P || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10173 return mDNStrue;
10174
10175 // Don't send the record over this interface.
10176 return mDNSfalse;
10177 }
10178
10179 // Filter questions send over P2P (D2D) type interfaces.
10180 mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
10181 {
10182 // For an explicit match to a valid interface ID, return true.
10183 if (q->InterfaceID == intf->InterfaceID)
10184 return mDNStrue;
10185
10186 // Only filtering questions for D2D type interfaces
10187 if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
10188 return mDNStrue;
10189
10190 // If it's an AWDL interface the question must be explicitly marked to include AWDL.
10191 if (intf->InterfaceID == AWDLInterfaceID)
10192 {
10193 if (q->flags & kDNSServiceFlagsIncludeAWDL)
10194 return mDNStrue;
10195 else
10196 return mDNSfalse;
10197 }
10198
10199 // Sent question if it is explicitly marked to include all other P2P type interfaces.
10200 if (q->flags & kDNSServiceFlagsIncludeP2P)
10201 return mDNStrue;
10202
10203 // Don't send the question over this interface.
10204 return mDNSfalse;
10205 }
10206
10207 // Returns true unless record was received over the AWDL interface and
10208 // the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
10209 // with the kDNSServiceFlagsIncludeAWDL flag set.
10210 mDNSexport mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
10211 {
10212 if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID))
10213 return mDNStrue;
10214
10215 if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL))
10216 return mDNSfalse;
10217
10218 return mDNStrue;
10219 }
10220
10221 // formating time to RFC 4034 format
10222 mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
10223 {
10224 struct tm tmTime;
10225 time_t t = (time_t)te;
10226 // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
10227 // gmtime_r first and then use strftime
10228 gmtime_r(&t, &tmTime);
10229 strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
10230 }
10231
10232 mDNSexport mDNSs32 mDNSPlatformGetPID()
10233 {
10234 return getpid();
10235 }
10236
10237 // Schedule a function asynchronously on the main queue
10238 mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func)
10239 {
10240 // KQueueLock/Unlock is used for two purposes
10241 //
10242 // 1. We can't be running along with the KQueue thread and hence acquiring the lock
10243 // serializes the access to the "core"
10244 //
10245 // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
10246 // up and calls udsserver_idle which schedules the messages across the uds socket.
10247 // If "func" delivers something to the uds socket from the dispatch thread, it will
10248 // not be delivered immediately if not for the Unlock.
10249 dispatch_async(dispatch_get_main_queue(), ^{
10250 KQueueLock();
10251 func(m, context);
10252 KQueueUnlock("mDNSPlatformDispatchAsync");
10253 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10254 // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
10255 // to handle any message that "func" might deliver.
10256 TriggerEventCompletion();
10257 #endif
10258 });
10259 }
10260
10261 // definitions for device-info record construction
10262 #define DEVINFO_MODEL "model="
10263 #define DEVINFO_MODEL_LEN sizeof_string(DEVINFO_MODEL)
10264
10265 #define OSX_VER "osxvers="
10266 #define OSX_VER_LEN sizeof_string(OSX_VER)
10267 #define VER_NUM_LEN 2 // 2 digits of version number added to base string
10268
10269 #define MODEL_COLOR "ecolor="
10270 #define MODEL_COLOR_LEN sizeof_string(MODEL_COLOR)
10271 #define MODEL_RGB_VALUE_LEN sizeof_string("255,255,255") // 'r,g,b'
10272
10273 // Bytes available in TXT record for model name after subtracting space for other
10274 // fixed size strings and their length bytes.
10275 #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))
10276
10277 mDNSlocal mDNSu8 getModelIconColors(char *color)
10278 {
10279 mDNSPlatformMemZero(color, MODEL_RGB_VALUE_LEN + 1);
10280
10281 #if !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10282 mDNSu8 red = 0;
10283 mDNSu8 green = 0;
10284 mDNSu8 blue = 0;
10285
10286 IOReturn rGetDeviceColor = IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey,
10287 &red, &green, &blue);
10288 if (kIOReturnSuccess == rGetDeviceColor)
10289 {
10290 // IOKit was able to get enclosure color for the current device.
10291 return snprintf(color, MODEL_RGB_VALUE_LEN + 1, "%d,%d,%d", red, green, blue);
10292 }
10293 #endif // !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10294
10295 return 0;
10296 }
10297
10298
10299 // Initialize device-info TXT record contents and return total length of record data.
10300 mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
10301 {
10302 mDNSu8 *bufferStart = ptr;
10303 mDNSu8 len = m->HIHardware.c[0] < MAX_MODEL_NAME_LEN ? m->HIHardware.c[0] : MAX_MODEL_NAME_LEN;
10304
10305 *ptr = DEVINFO_MODEL_LEN + len; // total length of DEVINFO_MODEL string plus the hardware name string
10306 ptr++;
10307 mDNSPlatformMemCopy(ptr, DEVINFO_MODEL, DEVINFO_MODEL_LEN);
10308 ptr += DEVINFO_MODEL_LEN;
10309 mDNSPlatformMemCopy(ptr, m->HIHardware.c + 1, len);
10310 ptr += len;
10311
10312 // only include this string for OSX
10313 if (OSXVers)
10314 {
10315 char ver_num[VER_NUM_LEN + 1]; // version digits + null written by snprintf
10316 *ptr = OSX_VER_LEN + VER_NUM_LEN; // length byte
10317 ptr++;
10318 mDNSPlatformMemCopy(ptr, OSX_VER, OSX_VER_LEN);
10319 ptr += OSX_VER_LEN;
10320 // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
10321 // WARNING: This code assumes that OSXVers is always exactly two digits
10322 snprintf(ver_num, VER_NUM_LEN + 1, "%d", OSXVers);
10323 mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN);
10324 ptr += VER_NUM_LEN;
10325
10326 char rgb[MODEL_RGB_VALUE_LEN + 1]; // RGB value + null written by snprintf
10327 len = getModelIconColors(rgb);
10328 if (len)
10329 {
10330 *ptr = MODEL_COLOR_LEN + len; // length byte
10331 ptr++;
10332
10333 mDNSPlatformMemCopy(ptr, MODEL_COLOR, MODEL_COLOR_LEN);
10334 ptr += MODEL_COLOR_LEN;
10335
10336 mDNSPlatformMemCopy(ptr, rgb, len);
10337 ptr += len;
10338 }
10339 }
10340
10341 return (ptr - bufferStart);
10342 }
10343
10344 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
10345
10346 // Use the scalar version of SameDomainLabel() by default
10347 mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
10348 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
10349 mDNSlocal mDNSBool (*SameDomainLabelPointer)(const mDNSu8 *a, const mDNSu8 *b) = scalarSameDomainLabel;
10350
10351 #include <System/machine/cpu_capabilities.h>
10352 #define _cpu_capabilities ((uint32_t*) _COMM_PAGE_CPU_CAPABILITIES)[0]
10353
10354 #if TARGET_OS_EMBEDDED
10355
10356 #include <arm_neon.h>
10357
10358 // Cache line aligned table that returns 32 for the upper case letters.
10359 // This will take up 4 cache lines.
10360 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table[256] = {
10361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10362 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10363 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10364 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10365 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
10366 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
10367 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10368 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10369 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10370 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10371 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10372 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10373 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10374 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10375 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10376 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
10377 };
10378
10379 // Neon version
10380 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10381 {
10382 const int len = *a++;
10383
10384 if (len > MAX_DOMAIN_LABEL)
10385 {
10386 fprintf(stderr, "v: Malformed label (too long)\n");
10387 return(mDNSfalse);
10388 }
10389
10390 if (len != *b++)
10391 {
10392 return(mDNSfalse);
10393 }
10394
10395 uint32_t len_count = len;
10396
10397 uint8x16_t vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
10398
10399 uint8x16_t v32 = vdupq_n_u8(32);
10400 uint8x16_t v37 = vdupq_n_u8(37);
10401 uint8x16_t v101 = vdupq_n_u8(101);
10402 #if !defined __arm64__
10403 uint32x4_t vtemp32;
10404 uint32x2_t vtemp32d;
10405 uint32_t sum;
10406 #endif
10407
10408 while(len_count > 15)
10409 {
10410 vA = vld1q_u8(a);
10411 vB = vld1q_u8(b);
10412 a += 16;
10413 b += 16;
10414
10415 //Make vA to lowercase if there is any uppercase.
10416 vARotated = vaddq_u8(vA, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10417 vMaskA = vcgtq_s8(vARotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10418 vMaskA = vandq_u8(vMaskA, v32); //Prepare 32 for the elements with uppercase letters.
10419 vA = vaddq_u8(vA, vMaskA); //Add 32 only to the uppercase letters to make them lowercase letters.
10420
10421 //Make vB to lowercase if there is any uppercase.
10422 vBRotated = vaddq_u8(vB, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10423 vMaskB = vcgtq_s8(vBRotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10424 vMaskB = vandq_u8(vMaskB, v32); //Prepare 32 for the elements with uppercase letters.
10425 vB = vaddq_u8(vB, vMaskB); //Add 32 only to the uppercase letters to make them lowercase letters.
10426
10427 //Compare vA & vB
10428 vA = vceqq_u8(vA, vB);
10429
10430 #if defined __arm64__
10431 //View 8-bit element as 32-bit => a3 a2 a1 a0
10432 //If min of 4 32-bit values in vA is 0xffffffff, then it means we have 0xff for all 16.
10433 if(vminvq_u32(vA) != 0xffffffffU)
10434 {
10435 return(mDNSfalse);
10436
10437 }
10438 #else
10439 //See if any element was not same.
10440 //View 8-bit element as 16-bit => a7 a6 a5 a4 a3 a2 a1 a0
10441 //(a7+a6) (a5+a4) (a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
10442 vtemp32 = vpaddlq_u16(vA);
10443 vtemp32d = vpadd_u32(vget_low_u32(vtemp32), vget_high_u32(vtemp32));
10444 vtemp32d = vpadd_u32(vtemp32d, vtemp32d);
10445 sum = vget_lane_u32(vtemp32d, 0);
10446
10447 //0x0001fffe + 0x0001fffe + 0x0001fffe + 0x0001fffe = 0x0007fff8U when all same.
10448 if(sum != 0x0007fff8U)
10449 {
10450 return(mDNSfalse);
10451 }
10452 #endif
10453
10454 len_count -= 16;
10455 }
10456
10457 uint8x8_t vAd, vBd, vARotatedd, vBRotatedd, vMaskAd, vMaskBd;
10458
10459 uint8x8_t v32d = vdup_n_u8(32);
10460 uint8x8_t v37d = vdup_n_u8(37);
10461 uint8x8_t v101d = vdup_n_u8(101);
10462
10463 while(len_count > 7)
10464 {
10465 vAd = vld1_u8(a);
10466 vBd = vld1_u8(b);
10467 a += 8;
10468 b += 8;
10469
10470 //Make vA to lowercase if there is any uppercase.
10471 vARotatedd = vadd_u8(vAd, v37d); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10472 vMaskAd = vcgt_s8(vARotatedd, v101d); //Check if anything is greater than '101' which means we have uppercase letters.
10473 vMaskAd = vand_u8(vMaskAd, v32d); //Prepare 32 for the elements with uppercase letters.
10474 vAd = vadd_u8(vAd, vMaskAd); //Add 32 only to the uppercase letters to make them lowercase letters.
10475
10476 //Make vB to lowercase if there is any uppercase.
10477 vBRotatedd = vadd_u8(vBd, v37d); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10478 vMaskBd = vcgt_s8(vBRotatedd, v101d); //Check if anything is greater than '101' which means we have uppercase letters.
10479 vMaskBd = vand_u8(vMaskBd, v32d); //Prepare 32 for the elements with uppercase letters.
10480 vBd = vadd_u8(vBd, vMaskBd); //Add 32 only to the uppercase letters to make them lowercase letters.
10481
10482 //Compare vA & vB
10483 vAd = vceq_u8(vAd, vBd);
10484
10485 #if defined __arm64__
10486 //View 8-bit element as 32-bit => a1 a0
10487 //If min of 2 32-bit values in vAd is 0xffffffff, then it means we have 0xff for all 16.
10488 if(vminv_u32(vAd) != 0xffffffffU)
10489 {
10490 return(mDNSfalse);
10491
10492 }
10493 #else
10494 //See if any element was not same.
10495 //View 8-bit element as 16-bit => a3 a2 a1 a0
10496 //(a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
10497 vtemp32d = vpaddl_u16(vAd);
10498 vtemp32d = vpadd_u32(vtemp32d, vtemp32d);
10499 sum = vget_lane_u32(vtemp32d, 0);
10500
10501 //0x0001fffe + 0x0001fffe = 0x0003fffc when all same.
10502 if(sum != 0x0003fffcU)
10503 {
10504 return(mDNSfalse);
10505 }
10506 #endif
10507
10508 len_count -= 8;
10509 }
10510
10511 while(len_count > 0)
10512 {
10513 mDNSu8 ac = *a++;
10514 mDNSu8 bc = *b++;
10515
10516 ac += upper_to_lower_case_table[ac];
10517 bc += upper_to_lower_case_table[bc];
10518
10519 if (ac != bc)
10520 {
10521 return(mDNSfalse);
10522 }
10523
10524 len_count -= 1;
10525 }
10526 return(mDNStrue);
10527 }
10528
10529 // Use vectorized implementation if it is supported on this platform.
10530 mDNSlocal void setSameDomainLabelPointer(void)
10531 {
10532 if(_cpu_capabilities & kHasNeon)
10533 {
10534 // Use Neon Code
10535 SameDomainLabelPointer = vectorSameDomainLabel;
10536 LogMsg("setSameDomainLabelPointer: using vector code");
10537 }
10538 else
10539 LogMsg("setSameDomainLabelPointer: using scalar code");
10540 }
10541
10542 #else // TARGET_OS_EMBEDDED
10543
10544 #include <smmintrin.h>
10545
10546 // Cache line aligned table that returns 32 for the upper case letters.
10547 // This will take up 4 cache lines.
10548 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table[256] = {
10549 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10550 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10551 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10552 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10553 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
10554 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
10555 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10557 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10561 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10563 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10564 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
10565 };
10566
10567 // SSE2 version
10568 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10569 {
10570 const int len = *a++;
10571
10572 if (len > MAX_DOMAIN_LABEL)
10573 {
10574 fprintf(stderr, "v: Malformed label (too long)\n");
10575 return(mDNSfalse);
10576 }
10577
10578 if (len != *b++)
10579 {
10580 return(mDNSfalse);
10581 }
10582
10583 uint32_t len_count = len;
10584
10585 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 };
10586 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 };
10587 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 };
10588 __m128i v37 = _mm_load_si128((__m128i*)c_37);
10589 __m128i v101 = _mm_load_si128((__m128i*)c_101);
10590 __m128i v32 = _mm_load_si128((__m128i*)c_32);
10591
10592 uint32_t is_equal;
10593 __m128i vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
10594
10595 //AVX code that uses higher bandwidth (more elements per vector) was removed
10596 //to speed up the processing on the small sizes.
10597 //When I had them, the performance of 1 ~ 8 characters were slower by about 10% ~ 30%.
10598 while(len_count > 15)
10599 {
10600 vA = _mm_loadu_si128((__m128i*)a);
10601 vB = _mm_loadu_si128((__m128i*)b);
10602 a += 16;
10603 b += 16;
10604
10605 //Make vA to lowercase if there is any uppercase.
10606 vARotated = _mm_add_epi8(vA, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10607 vMaskA = _mm_cmpgt_epi8(vARotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10608 vMaskA = _mm_and_si128(vMaskA, v32); //Prepare 32 for the elements with uppercase letters.
10609 vA = _mm_add_epi8(vA, vMaskA); //Add 32 only to the uppercase letters to make them lowercase letters.
10610
10611 //Make vB to lowercase if there is any uppercase.
10612 vBRotated = _mm_add_epi8(vB, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10613 vMaskB = _mm_cmpgt_epi8(vBRotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10614 vMaskB = _mm_and_si128(vMaskB, v32); //Prepare 32 for the elements with uppercase letters.
10615 vB = _mm_add_epi8(vB, vMaskB); //Add 32 only to the uppercase letters to make them lowercase letters.
10616
10617 //Compare vA & vB
10618 vA = _mm_cmpeq_epi8(vA, vB);
10619
10620 //Return if any different.
10621 is_equal = _mm_movemask_epi8(vA);
10622 is_equal = is_equal & 0xffff;
10623 if(is_equal != 0xffff)
10624 {
10625 return(mDNSfalse);
10626 }
10627
10628 len_count -= 16;
10629 }
10630
10631 while(len_count > 0)
10632 {
10633 mDNSu8 ac = *a++;
10634 mDNSu8 bc = *b++;
10635
10636 //Table will return 32 for upper case letters only.
10637 //0 will be returned for all others.
10638 ac += upper_to_lower_case_table[ac];
10639 bc += upper_to_lower_case_table[bc];
10640
10641 //Return if a & b are different.
10642 if (ac != bc)
10643 {
10644 return(mDNSfalse);
10645 }
10646
10647 len_count -= 1;
10648 }
10649 return(mDNStrue);
10650 }
10651
10652 // Use vectorized implementation if it is supported on this platform.
10653 mDNSlocal void setSameDomainLabelPointer(void)
10654 {
10655 if(_cpu_capabilities & kHasSSE4_1)
10656 {
10657 // Use SSE Code
10658 SameDomainLabelPointer = vectorSameDomainLabel;
10659 LogMsg("setSameDomainLabelPointer: using vector code");
10660 }
10661 else
10662 LogMsg("setSameDomainLabelPointer: using scalar code");
10663 }
10664
10665 #endif // TARGET_OS_EMBEDDED
10666
10667 // Original SameDomainLabel() implementation.
10668 mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10669 {
10670 int i;
10671 const int len = *a++;
10672
10673 if (len > MAX_DOMAIN_LABEL)
10674 { debugf("Malformed label (too long)"); return(mDNSfalse); }
10675
10676 if (len != *b++) return(mDNSfalse);
10677 for (i=0; i<len; i++)
10678 {
10679 mDNSu8 ac = *a++;
10680 mDNSu8 bc = *b++;
10681 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
10682 if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
10683 if (ac != bc) return(mDNSfalse);
10684 }
10685 return(mDNStrue);
10686 }
10687
10688 mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10689 {
10690 return (*SameDomainLabelPointer)(a, b);
10691 }
10692
10693 #endif // APPLE_OSX_mDNSResponder
10694
10695
10696 #ifdef UNIT_TEST
10697 #include "../unittests/mdns_macosx_ut.c"
10698 #endif
10699