]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mDNSMacOSX.c
mDNSResponder-878.230.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 #include <network_information.h> // for nwi_state
97
98 #if MDNSRESPONDER_BTMM_SUPPORT
99 #include <AWACS.h>
100 #endif
101
102 #if APPLE_OSX_mDNSResponder
103 #include <ne_session.h> // for ne_session_set_socket_attributes()
104 #endif
105
106 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
107 #include <IOKit/platform/IOPlatformSupportPrivate.h>
108 #endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
109
110 #ifdef UNIT_TEST
111 #include "unittest.h"
112 #endif
113
114 #define kInterfaceSpecificOption "interface="
115
116 #define mDNS_IOREG_KEY "mDNS_KEY"
117 #define mDNS_IOREG_VALUE "2009-07-30"
118 #define mDNS_IOREG_KA_KEY "mDNS_Keepalive"
119 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
120
121 #define DARK_WAKE_TIME 16 // Time we hold an idle sleep assertion for maintenance after a wake notification
122
123 // cache the InterfaceID of the AWDL interface
124 mDNSInterfaceID AWDLInterfaceID;
125
126 // ***************************************************************************
127 // Globals
128
129 #if COMPILER_LIKES_PRAGMA_MARK
130 #pragma mark - Globals
131 #endif
132
133 // By default we don't offer sleep proxy service
134 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
135 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
136 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
137 mDNSexport int OfferSleepProxyService = 0;
138 mDNSexport int DisableSleepProxyClient = 0;
139 mDNSexport int UseInternalSleepProxy = 1; // Set to non-zero to use internal (in-NIC) Sleep Proxy
140
141 mDNSexport int OSXVers, iOSVers;
142 mDNSexport int KQueueFD;
143
144 #ifndef NO_SECURITYFRAMEWORK
145 static CFArrayRef ServerCerts;
146 OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
147 #endif /* NO_SECURITYFRAMEWORK */
148
149 static CFStringRef NetworkChangedKey_IPv4;
150 static CFStringRef NetworkChangedKey_IPv6;
151 static CFStringRef NetworkChangedKey_Hostnames;
152 static CFStringRef NetworkChangedKey_Computername;
153 static CFStringRef NetworkChangedKey_DNS;
154 static CFStringRef NetworkChangedKey_StateInterfacePrefix;
155 static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
156 static CFStringRef NetworkChangedKey_PowerSettings = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
157 #if MDNSRESPONDER_BTMM_SUPPORT
158 static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
159 static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity");
160 #endif
161
162 static char HINFO_HWstring_buffer[32];
163 static char *HINFO_HWstring = "Device";
164 static int HINFO_HWstring_prefixlen = 6;
165
166 mDNSexport int WatchDogReportingThreshold = 250;
167
168 dispatch_queue_t SSLqueue;
169
170 #if TARGET_OS_EMBEDDED
171 #define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
172 #endif
173
174 #if APPLE_OSX_mDNSResponder
175 static mDNSu8 SPMetricPortability = 99;
176 static mDNSu8 SPMetricMarginalPower = 99;
177 static mDNSu8 SPMetricTotalPower = 99;
178 static mDNSu8 SPMetricFeatures = 1; /* The current version supports TCP Keep Alive Feature */
179 mDNSexport domainname ActiveDirectoryPrimaryDomain;
180 mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
181 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
182 #endif // APPLE_OSX_mDNSResponder
183
184 // Don't send triggers too often. We arbitrarily limit it to three minutes.
185 #define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
186
187 // Used by AutoTunnel
188 const char btmmprefix[] = "btmmdns:";
189 const char dnsprefix[] = "dns:";
190
191 // String Array used to write list of private domains to Dynamic Store
192 static CFArrayRef privateDnsArray = NULL;
193
194 // ***************************************************************************
195 // Functions
196
197 #if COMPILER_LIKES_PRAGMA_MARK
198 #pragma mark -
199 #pragma mark - Utility Functions
200 #endif
201
202 // We only attempt to send and receive multicast packets on interfaces that are
203 // (a) flagged as multicast-capable
204 // (b) *not* flagged as point-to-point (e.g. modem)
205 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
206 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
207 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
208
209 #if BONJOUR_ON_DEMAND
210 #define MulticastInterface(i) ((i)->m->BonjourEnabled && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
211 #else
212 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
213 #endif
214 #define SPSInterface(i) ((i)->ifinfo.McastTxRx && !((i)->ifa_flags & IFF_LOOPBACK) && !(i)->D2DInterface)
215
216 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
217 {
218 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
219 #if !ForceAlerts
220 {
221 // Determine if we're at Apple (17.*.*.*)
222 NetworkInterfaceInfoOSX *i;
223 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
224 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
225 break;
226 if (!i)
227 return; // If not at Apple, don't show the alert
228 }
229 #endif
230
231 LogMsg("NotifyOfElusiveBug: %s", title);
232 LogMsg("NotifyOfElusiveBug: %s", msg);
233
234 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
235 // To avoid this, we don't try to display alerts in the first three minutes after boot.
236 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180))
237 {
238 LogMsg("Suppressing notification early in boot: %d", mDNSPlatformRawTime());
239 return;
240 }
241
242 #ifndef NO_CFUSERNOTIFICATION
243 static int notifyCount = 0; // To guard against excessive display of warning notifications
244 if (notifyCount < 5)
245 {
246 notifyCount++;
247 mDNSNotify(title, msg);
248 }
249 #endif /* NO_CFUSERNOTIFICATION */
250
251 }
252
253 // Write a syslog message and display an alert, then if ForceAlerts is set, generate a stack trace
254 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
255 mDNSexport void LogMemCorruption(const char *format, ...)
256 {
257 char buffer[512];
258 va_list ptr;
259 va_start(ptr,format);
260 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
261 va_end(ptr);
262 LogMsg("!!!! %s !!!!", buffer);
263 NotifyOfElusiveBug("Memory Corruption", buffer);
264 #if ForceAlerts
265 *(volatile long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
266 #endif
267 }
268 #endif
269
270 // Like LogMemCorruption above, but only display the alert if ForceAlerts is set and we're going to generate a stack trace
271 #if APPLE_OSX_mDNSResponder
272 mDNSexport void LogFatalError(const char *format, ...)
273 {
274 char buffer[512];
275 va_list ptr;
276 va_start(ptr,format);
277 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
278 va_end(ptr);
279 LogMsg("!!!! %s !!!!", buffer);
280 #if ForceAlerts
281 NotifyOfElusiveBug("Fatal Error. See /Library/Logs/DiagnosticReports", buffer);
282 *(volatile long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
283 #endif
284 }
285 #endif
286
287 // Returns true if it is an AppleTV based hardware running iOS, false otherwise
288 mDNSlocal mDNSBool IsAppleTV(void)
289 {
290 #if TARGET_OS_EMBEDDED
291 static mDNSBool sInitialized = mDNSfalse;
292 static mDNSBool sIsAppleTV = mDNSfalse;
293 CFStringRef deviceClass = NULL;
294
295 if(!sInitialized)
296 {
297 deviceClass = (CFStringRef) MGCopyAnswer(kMGQDeviceClass, NULL);
298 if(deviceClass)
299 {
300 if(CFEqual(deviceClass, kMGDeviceClassAppleTV))
301 sIsAppleTV = mDNStrue;
302 CFRelease(deviceClass);
303 }
304 sInitialized = mDNStrue;
305 }
306 return(sIsAppleTV);
307 #else
308 return mDNSfalse;
309 #endif // TARGET_OS_EMBEDDED
310 }
311
312 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
313 {
314 static struct ifaddrs *ifa = NULL;
315
316 if (refresh && ifa)
317 {
318 freeifaddrs(ifa);
319 ifa = NULL;
320 }
321
322 if (ifa == NULL)
323 getifaddrs(&ifa);
324 return ifa;
325 }
326
327 mDNSlocal void DynamicStoreWrite(int key, const char* subkey, uintptr_t value, signed long valueCnt)
328 {
329 CFStringRef sckey = NULL;
330 Boolean release_sckey = FALSE;
331 CFDataRef bytes = NULL;
332 CFPropertyListRef plist = NULL;
333
334 switch ((enum mDNSDynamicStoreSetConfigKey)key)
335 {
336 case kmDNSMulticastConfig:
337 sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
338 break;
339 case kmDNSDynamicConfig:
340 sckey = CFSTR("State:/Network/DynamicDNS");
341 break;
342 case kmDNSPrivateConfig:
343 sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
344 break;
345 case kmDNSBackToMyMacConfig:
346 sckey = CFSTR("State:/Network/BackToMyMac");
347 break;
348 case kmDNSSleepProxyServersState:
349 {
350 CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0);
351 CFStringAppend(tmp, CFSTR("State:/Network/Interface/"));
352 CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8);
353 CFStringAppend(tmp, CFSTR("/SleepProxyServers"));
354 sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp);
355 release_sckey = TRUE;
356 CFRelease(tmp);
357 break;
358 }
359 case kmDNSDebugState:
360 sckey = CFSTR("State:/Network/mDNSResponder/DebugState");
361 break;
362 default:
363 LogMsg("unrecognized key %d", key);
364 goto fin;
365 }
366 if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
367 valueCnt, kCFAllocatorNull)))
368 {
369 LogMsg("CFDataCreateWithBytesNoCopy of value failed");
370 goto fin;
371 }
372 if (NULL == (plist = CFPropertyListCreateWithData(NULL, bytes, kCFPropertyListImmutable, NULL, NULL)))
373 {
374 LogMsg("CFPropertyListCreateWithData of bytes failed");
375 goto fin;
376 }
377 CFRelease(bytes);
378 bytes = NULL;
379 SCDynamicStoreSetValue(NULL, sckey, plist);
380
381 fin:
382 if (NULL != bytes)
383 CFRelease(bytes);
384 if (NULL != plist)
385 CFRelease(plist);
386 if (release_sckey && sckey)
387 CFRelease(sckey);
388 }
389
390 mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value)
391 {
392 CFPropertyListRef valueCopy;
393 char *subkeyCopy = NULL;
394 if (!value)
395 return;
396
397 // We need to copy the key and value before we dispatch off the block below as the
398 // caller will free the memory once we return from this function.
399 valueCopy = CFPropertyListCreateDeepCopy(NULL, value, kCFPropertyListImmutable);
400 if (!valueCopy)
401 {
402 LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
403 return;
404 }
405 if (subkey)
406 {
407 int len = strlen(subkey);
408 subkeyCopy = mDNSPlatformMemAllocate(len + 1);
409 if (!subkeyCopy)
410 {
411 LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
412 CFRelease(valueCopy);
413 return;
414 }
415 mDNSPlatformMemCopy(subkeyCopy, subkey, len);
416 subkeyCopy[len] = 0;
417 }
418
419 dispatch_async(dispatch_get_main_queue(), ^{
420 CFWriteStreamRef stream = NULL;
421 CFDataRef bytes = NULL;
422 CFIndex ret;
423 KQueueLock();
424
425 if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL)))
426 {
427 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
428 goto END;
429 }
430 CFWriteStreamOpen(stream);
431 ret = CFPropertyListWrite(valueCopy, stream, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
432 if (ret == 0)
433 {
434 LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
435 goto END;
436 }
437 if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten)))
438 {
439 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
440 goto END;
441 }
442 CFWriteStreamClose(stream);
443 CFRelease(stream);
444 stream = NULL;
445 DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes));
446
447 END:
448 CFRelease(valueCopy);
449 if (NULL != stream)
450 {
451 CFWriteStreamClose(stream);
452 CFRelease(stream);
453 }
454 if (NULL != bytes)
455 CFRelease(bytes);
456 if (subkeyCopy)
457 mDNSPlatformMemFree(subkeyCopy);
458
459 KQueueUnlock("mDNSDynamicStoreSetConfig");
460 });
461 }
462
463 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
464 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(const char *ifname, int type)
465 {
466 NetworkInterfaceInfoOSX *i;
467 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
468 if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
469 ((type == AF_UNSPEC ) ||
470 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
471 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
472 return(NULL);
473 }
474
475 mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
476 {
477 struct ifaddrs *ifa;
478 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
479 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
480 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
481 { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
482 return -1;
483 }
484
485 mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(mDNSInterfaceID ifindex)
486 {
487 mDNS *const m = &mDNSStorage;
488 mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
489 NetworkInterfaceInfoOSX *i;
490
491 // Don't get tricked by inactive interfaces
492 for (i = m->p->InterfaceList; i; i = i->next)
493 if (i->Registered && i->scope_id == scope_id) return(i);
494
495 return mDNSNULL;
496 }
497
498 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
499 {
500 (void) m;
501 if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
502 if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
503 if (ifindex == kDNSServiceInterfaceIndexBLE ) return(mDNSInterface_BLE);
504 if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
505
506 NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
507 if (!ifi)
508 {
509 // Not found. Make sure our interface list is up to date, then try again.
510 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
511 mDNSMacOSXNetworkChanged();
512 ifi = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
513 }
514
515 if (!ifi) return(mDNSNULL);
516
517 return(ifi->ifinfo.InterfaceID);
518 }
519
520
521 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
522 {
523 NetworkInterfaceInfoOSX *i;
524 if (id == mDNSInterface_Any ) return(0);
525 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
526 if (id == mDNSInterface_Unicast ) return(0);
527 if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
528 if (id == mDNSInterface_BLE ) return(kDNSServiceInterfaceIndexBLE);
529
530 mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
531
532 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
533 for (i = m->p->InterfaceList; i; i = i->next)
534 if (i->scope_id == scope_id) return(i->scope_id);
535
536 // If we are supposed to suppress network change, return "id" back
537 if (suppressNetworkChange) return scope_id;
538
539 // Not found. Make sure our interface list is up to date, then try again.
540 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
541 mDNSMacOSXNetworkChanged();
542 for (i = m->p->InterfaceList; i; i = i->next)
543 if (i->scope_id == scope_id) return(i->scope_id);
544
545 return(0);
546 }
547
548 #if COMPILER_LIKES_PRAGMA_MARK
549 #pragma mark -
550 #pragma mark - UDP & TCP send & receive
551 #endif
552
553 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
554 {
555 mDNSBool result = mDNSfalse;
556 SCNetworkConnectionFlags flags;
557 CFDataRef remote_addr;
558 CFMutableDictionaryRef options;
559 SCNetworkReachabilityRef ReachRef = NULL;
560
561 options = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
562 remote_addr = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len);
563 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, remote_addr);
564 CFDictionarySetValue(options, kSCNetworkReachabilityOptionServerBypass, kCFBooleanTrue);
565 ReachRef = SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault, options);
566 CFRelease(options);
567 CFRelease(remote_addr);
568
569 if (!ReachRef)
570 {
571 LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions");
572 goto end;
573 }
574 if (!SCNetworkReachabilityGetFlags(ReachRef, &flags))
575 {
576 LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags");
577 goto end;
578 }
579 result = flags & kSCNetworkFlagsConnectionRequired;
580
581 end:
582 if (ReachRef)
583 CFRelease(ReachRef);
584 return result;
585 }
586
587 // Set traffic class for socket
588 mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass)
589 {
590 int traffic_class;
591
592 if (useBackgroundTrafficClass)
593 traffic_class = SO_TC_BK_SYS;
594 else
595 traffic_class = SO_TC_CTL;
596
597 (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class));
598 }
599
600 #ifdef UNIT_TEST
601 // Run the unit test main
602 UNITTEST_SETSOCKOPT
603 #else
604 mDNSlocal int mDNSPlatformGetSocktFd(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType)
605 {
606 if (transType == mDNSTransport_UDP)
607 {
608 UDPSocket* sock = (UDPSocket*) sockCxt;
609 return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6;
610 }
611 else if (transType == mDNSTransport_TCP)
612 {
613 TCPSocket* sock = (TCPSocket*) sockCxt;
614 return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6;
615 }
616 else
617 {
618 LogInfo("mDNSPlatformGetSocktFd: invalid transport %d", transType);
619 return kInvalidSocketRef;
620 }
621 }
622
623 mDNSexport void mDNSPlatformSetSocktOpt(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType, const DNSQuestion *q)
624 {
625 int sockfd;
626 char unenc_name[MAX_ESCAPED_DOMAIN_NAME];
627
628 // verify passed-in arguments exist and that sockfd is valid
629 if (q == mDNSNULL || sockCxt == mDNSNULL || (sockfd = mDNSPlatformGetSocktFd(sockCxt, transType, addrType)) < 0)
630 return;
631
632 if (q->pid)
633 {
634 if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1)
635 LogMsg("mDNSPlatformSetSocktOpt: Delegate PID failed %s for PID %d", strerror(errno), q->pid);
636 }
637 else
638 {
639 if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1)
640 LogMsg("mDNSPlatformSetSocktOpt: Delegate UUID failed %s", strerror(errno));
641 }
642
643 // set the domain on the socket
644 ConvertDomainNameToCString(&q->qname, unenc_name);
645 if (!(ne_session_set_socket_attributes(sockfd, unenc_name, NULL)))
646 LogInfo("mDNSPlatformSetSocktOpt: ne_session_set_socket_attributes()-> setting domain failed for %s", unenc_name);
647
648 int nowake = 1;
649 if (setsockopt(sockfd, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
650 LogInfo("mDNSPlatformSetSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
651 }
652 #endif // UNIT_TEST
653
654 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
655 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
656 // OR send via our primary v4 unicast socket
657 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
658 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
659 mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
660 mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
661 {
662 NetworkInterfaceInfoOSX *info = mDNSNULL;
663 struct sockaddr_storage to;
664 int s = -1, err;
665 mStatus result = mStatus_NoError;
666 int sendto_errno;
667
668 if (InterfaceID)
669 {
670 info = IfindexToInterfaceInfoOSX(InterfaceID);
671 if (info == NULL)
672 {
673 // We may not have registered interfaces with the "core" as we may not have
674 // seen any interface notifications yet. This typically happens during wakeup
675 // where we might try to send DNS requests (non-SuppressUnusable questions internal
676 // to mDNSResponder) before we receive network notifications.
677 LogInfo("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
678 return mStatus_BadParamErr;
679 }
680 }
681
682 char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
683
684 if (dst->type == mDNSAddrType_IPv4)
685 {
686 struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
687 sin_to->sin_len = sizeof(*sin_to);
688 sin_to->sin_family = AF_INET;
689 sin_to->sin_port = dstPort.NotAnInteger;
690 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
691 s = (src ? src->ss : m->p->permanentsockets).sktv4;
692
693 if (!mDNSAddrIsDNSMulticast(dst))
694 {
695 #ifdef IP_BOUND_IF
696 const mDNSu32 ifindex = info ? info->scope_id : IFSCOPE_NONE;
697 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
698 #else
699 static int displayed = 0;
700 if (displayed < 1000)
701 {
702 displayed++;
703 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
704 }
705 #endif
706 }
707 else if (info)
708 {
709 #ifdef IP_MULTICAST_IFINDEX
710 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IFINDEX, &info->scope_id, sizeof(info->scope_id));
711 // We get an error when we compile on a machine that supports this option and run the binary on
712 // a different machine that does not support it
713 if (err < 0)
714 {
715 if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno);
716 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
717 if (err < 0 && !m->NetworkChanged)
718 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
719 }
720 #else
721 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
722 if (err < 0 && !m->NetworkChanged)
723 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
724 #endif
725 }
726 }
727 else if (dst->type == mDNSAddrType_IPv6)
728 {
729 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
730 sin6_to->sin6_len = sizeof(*sin6_to);
731 sin6_to->sin6_family = AF_INET6;
732 sin6_to->sin6_port = dstPort.NotAnInteger;
733 sin6_to->sin6_flowinfo = 0;
734 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
735 sin6_to->sin6_scope_id = info ? info->scope_id : 0;
736 s = (src ? src->ss : m->p->permanentsockets).sktv6;
737 if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
738 {
739 err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
740 if (err < 0)
741 {
742 const int setsockopt_errno = errno;
743 char name[IFNAMSIZ];
744 if (if_indextoname(info->scope_id, name) != NULL)
745 LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, setsockopt_errno, strerror(setsockopt_errno));
746 else
747 LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id);
748 }
749 }
750 #ifdef IPV6_BOUND_IF
751 if (info) // Specify outgoing interface for non-multicast destination
752 {
753 if (!mDNSAddrIsDNSMulticast(dst))
754 {
755 if (info->scope_id == 0)
756 LogInfo("IPV6_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
757 else
758 setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
759 }
760 }
761 #endif
762 }
763
764 else
765 {
766 LogFatalError("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
767 return mStatus_BadParamErr;
768 }
769
770 if (s >= 0)
771 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
772 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
773 else
774 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
775 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
776
777 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
778 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
779 if (s < 0) return(mStatus_Invalid);
780
781 // switch to background traffic class for this message if requested
782 if (useBackgroundTrafficClass)
783 setTrafficClass(s, useBackgroundTrafficClass);
784
785 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
786 sendto_errno = (err < 0) ? errno : 0;
787
788 // set traffic class back to default value
789 if (useBackgroundTrafficClass)
790 setTrafficClass(s, mDNSfalse);
791
792 if (err < 0)
793 {
794 static int MessageCount = 0;
795 LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
796 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
797 if (!mDNSAddressIsAllDNSLinkGroup(dst))
798 {
799 if ((sendto_errno == EHOSTUNREACH) || (sendto_errno == ENETUNREACH)) return(mStatus_HostUnreachErr);
800 if ((sendto_errno == EHOSTDOWN) || (sendto_errno == ENETDOWN)) return(mStatus_TransientErr);
801 }
802 // Don't report EHOSTUNREACH in the first three minutes after boot
803 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
804 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
805 if (sendto_errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
806 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
807 if (sendto_errno == EADDRNOTAVAIL && m->NetworkChanged) return(mStatus_TransientErr);
808 if (sendto_errno == EHOSTUNREACH || sendto_errno == EADDRNOTAVAIL || sendto_errno == ENETDOWN)
809 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
810 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
811 else
812 {
813 MessageCount++;
814 if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs
815 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",
816 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
817 else // If logging is enabled, remove the cap and log aggressively
818 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",
819 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
820 }
821
822 result = mStatus_UnknownErr;
823 }
824
825 return(result);
826 }
827
828 mDNSexport ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
829 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
830 {
831 static unsigned int numLogMessages = 0;
832 struct iovec databuffers = { (char *)buffer, max };
833 struct msghdr msg;
834 ssize_t n;
835 struct cmsghdr *cmPtr;
836 char ancillary[1024];
837
838 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
839
840 // Set up the message
841 msg.msg_name = (caddr_t)from;
842 msg.msg_namelen = *fromlen;
843 msg.msg_iov = &databuffers;
844 msg.msg_iovlen = 1;
845 msg.msg_control = (caddr_t)&ancillary;
846 msg.msg_controllen = sizeof(ancillary);
847 msg.msg_flags = 0;
848
849 // Receive the data
850 n = recvmsg(s, &msg, 0);
851 if (n<0)
852 {
853 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
854 return(-1);
855 }
856 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
857 {
858 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d",
859 s, n, msg.msg_controllen, sizeof(struct cmsghdr), errno);
860 return(-1);
861 }
862 if (msg.msg_flags & MSG_CTRUNC)
863 {
864 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
865 return(-1);
866 }
867
868 *fromlen = msg.msg_namelen;
869
870 // Parse each option out of the ancillary data.
871 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
872 {
873 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
874 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
875 {
876 dstaddr->type = mDNSAddrType_IPv4;
877 dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
878 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
879 }
880 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
881 {
882 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
883 if (sdl->sdl_nlen < IF_NAMESIZE)
884 {
885 mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
886 ifname[sdl->sdl_nlen] = 0;
887 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
888 }
889 }
890 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
891 *ttl = *(u_char*)CMSG_DATA(cmPtr);
892 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
893 {
894 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
895 dstaddr->type = mDNSAddrType_IPv6;
896 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
897 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
898 }
899 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
900 *ttl = *(int*)CMSG_DATA(cmPtr);
901 }
902
903 return(n);
904 }
905
906 // What is this for, and why does it use xor instead of a simple quality check? -- SC
907 mDNSlocal mDNSInterfaceID FindMyInterface(const mDNSAddr *addr)
908 {
909 NetworkInterfaceInfo *intf;
910
911 if (addr->type == mDNSAddrType_IPv4)
912 {
913 for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
914 {
915 if (intf->ip.type == addr->type && intf->McastTxRx)
916 {
917 if ((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) == 0)
918 {
919 return(intf->InterfaceID);
920 }
921 }
922 }
923 }
924
925 if (addr->type == mDNSAddrType_IPv6)
926 {
927 for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
928 {
929 if (intf->ip.type == addr->type && intf->McastTxRx)
930 {
931 if (((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) == 0) &&
932 ((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) == 0) &&
933 ((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) == 0) &&
934 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) == 0)))
935 {
936 return(intf->InterfaceID);
937 }
938 }
939 }
940 }
941 return(mDNSInterface_Any);
942 }
943
944 mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool encounteredEOF)
945 {
946 KQSocketSet *const ss = (KQSocketSet *)context;
947 mDNS *const m = ss->m;
948 int err = 0, count = 0, closed = 0;
949
950 if (filter != EVFILT_READ)
951 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
952
953 if (s1 != ss->sktv4 && s1 != ss->sktv6)
954 {
955 LogMsg("myKQSocketCallBack: native socket %d", s1);
956 LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6);
957 }
958
959 if (encounteredEOF)
960 {
961 LogMsg("myKQSocketCallBack: socket %d is no longer readable (EOF)", s1);
962 if (s1 == ss->sktv4)
963 {
964 ss->sktv4EOF = mDNStrue;
965 KQueueSet(ss->sktv4, EV_DELETE, EVFILT_READ, &ss->kqsv4);
966 }
967 else if (s1 == ss->sktv6)
968 {
969 ss->sktv6EOF = mDNStrue;
970 KQueueSet(ss->sktv6, EV_DELETE, EVFILT_READ, &ss->kqsv6);
971 }
972 return;
973 }
974
975 while (!closed)
976 {
977 mDNSAddr senderAddr, destAddr = zeroAddr;
978 mDNSIPPort senderPort;
979 struct sockaddr_storage from;
980 size_t fromlen = sizeof(from);
981 char packetifname[IF_NAMESIZE] = "";
982 mDNSu8 ttl;
983 err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
984 if (err < 0) break;
985
986 if ((destAddr.type == mDNSAddrType_IPv4 && (destAddr.ip.v4.b[0] & 0xF0) == 0xE0) ||
987 (destAddr.type == mDNSAddrType_IPv6 && (destAddr.ip.v6.b[0] == 0xFF))) m->p->num_mcasts++;
988
989 count++;
990 if (from.ss_family == AF_INET)
991 {
992 struct sockaddr_in *s = (struct sockaddr_in*)&from;
993 senderAddr.type = mDNSAddrType_IPv4;
994 senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
995 senderPort.NotAnInteger = s->sin_port;
996 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
997 }
998 else if (from.ss_family == AF_INET6)
999 {
1000 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
1001 senderAddr.type = mDNSAddrType_IPv6;
1002 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
1003 senderPort.NotAnInteger = sin6->sin6_port;
1004 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1005 }
1006 else
1007 {
1008 LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
1009 return;
1010 }
1011
1012 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1013 mDNSInterfaceID InterfaceID = mDNSNULL;
1014 NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
1015 while (intf)
1016 {
1017 if (intf->Exists && !strcmp(intf->ifinfo.ifname, packetifname))
1018 break;
1019 intf = intf->next;
1020 }
1021
1022 // When going to sleep we deregister all our interfaces, but if the machine
1023 // takes a few seconds to sleep we may continue to receive multicasts
1024 // during that time, which would confuse mDNSCoreReceive, because as far
1025 // as it's concerned, we should have no active interfaces any more.
1026 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1027 if (intf)
1028 InterfaceID = intf->ifinfo.InterfaceID;
1029 else if (mDNSAddrIsDNSMulticast(&destAddr))
1030 continue;
1031
1032 if (!InterfaceID)
1033 {
1034 InterfaceID = FindMyInterface(&destAddr);
1035 }
1036
1037 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1038 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
1039
1040 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
1041 // loop when that happens, or we may try to read from an invalid FD. We do this by
1042 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
1043 // if it closes the socketset.
1044 ss->closeFlag = &closed;
1045
1046 if (ss->proxy)
1047 {
1048 m->p->UDPProxyCallback(&m->p->UDPProxy, &m->imsg.m, (unsigned char*)&m->imsg + err, &senderAddr,
1049 senderPort, &destAddr, ss->port, InterfaceID, NULL);
1050 }
1051 else
1052 {
1053 mDNSCoreReceive(m, &m->imsg.m, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
1054 }
1055
1056 // if we didn't close, we can safely dereference the socketset, and should to
1057 // reset the closeFlag, since it points to something on the stack
1058 if (!closed) ss->closeFlag = mDNSNULL;
1059 }
1060
1061 // If a client application's sockets are marked as defunct
1062 // sockets we have delegated to it with SO_DELEGATED will also go defunct.
1063 // We get an ENOTCONN error for defunct sockets and should just close the socket in that case.
1064 if (err < 0 && errno == ENOTCONN)
1065 {
1066 LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
1067 close(s1);
1068 return;
1069 }
1070
1071 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
1072 {
1073 // Something is busted here.
1074 // kqueue says there is a packet, but myrecvfrom says there is not.
1075 // Try calling select() to get another opinion.
1076 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1077 // All of this is racy, as data may have arrived after the call to select()
1078 static unsigned int numLogMessages = 0;
1079 const int save_errno = errno;
1080 int so_error = -1;
1081 int so_nread = -1;
1082 int fionread = -1;
1083 socklen_t solen = sizeof(int);
1084 fd_set readfds;
1085 struct timeval timeout;
1086 int selectresult;
1087 FD_ZERO(&readfds);
1088 FD_SET(s1, &readfds);
1089 timeout.tv_sec = 0;
1090 timeout.tv_usec = 0;
1091 selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
1092 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
1093 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
1094 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
1095 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
1096 if (ioctl(s1, FIONREAD, &fionread) == -1)
1097 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
1098 if (numLogMessages++ < 100)
1099 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1100 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
1101 if (numLogMessages > 5)
1102 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1103 "Congratulations, you've reproduced an elusive bug.\r"
1104 "Please send email to radar-3387020@group.apple.com.)\r"
1105 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1106
1107 sleep(1); // After logging this error, rate limit so we don't flood syslog
1108 }
1109 }
1110
1111 mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
1112 {
1113 mDNSBool c = !sock->connected;
1114 sock->connected = mDNStrue;
1115 sock->callback(sock, sock->context, c, sock->err);
1116 // Note: the callback may call CloseConnection here, which frees the context structure!
1117 }
1118
1119 #ifndef NO_SECURITYFRAMEWORK
1120
1121 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
1122 {
1123 int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1124 if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1125 if (ret >= 0) { *dataLength = ret; return(noErr); }
1126 *dataLength = 0;
1127 if (errno == EAGAIN ) return(errSSLWouldBlock);
1128 if (errno == ENOENT ) return(errSSLClosedGraceful);
1129 if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
1130 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
1131 return(errSSLClosedAbort);
1132 }
1133
1134 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
1135 {
1136 int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1137 if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1138 if (ret > 0) { *dataLength = ret; return(noErr); }
1139 *dataLength = 0;
1140 if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
1141 if ( errno == EAGAIN ) return(errSSLWouldBlock);
1142 if ( errno == ECONNRESET) return(errSSLClosedAbort);
1143 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
1144 return(errSSLClosedAbort);
1145 }
1146
1147 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConnectionType ctype)
1148 {
1149 char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
1150
1151 sock->tlsContext = SSLCreateContext(kCFAllocatorDefault, pside, ctype);
1152 if (!sock->tlsContext)
1153 {
1154 LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
1155 return(mStatus_UnknownErr);
1156 }
1157
1158 mStatus err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
1159 if (err)
1160 {
1161 LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err);
1162 goto fail;
1163 }
1164
1165 err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
1166 if (err)
1167 {
1168 LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err);
1169 goto fail;
1170 }
1171
1172 // Set the default ciphersuite configuration
1173 err = SSLSetSessionConfig(sock->tlsContext, CFSTR("default"));
1174 if (err)
1175 {
1176 LogMsg("ERROR: tlsSetupSock: SSLSetSessionConfig failed with error code: %d", err);
1177 goto fail;
1178 }
1179
1180 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
1181 // (error not in OSStatus space) is okay.
1182 if (!sock->hostname.c[0])
1183 {
1184 LogMsg("ERROR: tlsSetupSock: hostname NULL");
1185 err = -1;
1186 goto fail;
1187 }
1188
1189 ConvertDomainNameToCString(&sock->hostname, domname_cstr);
1190 err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
1191 if (err)
1192 {
1193 LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err);
1194 goto fail;
1195 }
1196
1197 return(err);
1198
1199 fail:
1200 if (sock->tlsContext)
1201 CFRelease(sock->tlsContext);
1202 return(err);
1203 }
1204
1205 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1206 mDNSlocal void doSSLHandshake(TCPSocket *sock)
1207 {
1208 mStatus err = SSLHandshake(sock->tlsContext);
1209
1210 //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
1211 //defined, KQueueLock is a noop. Hence we need to serialize here
1212 //
1213 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
1214 //We need the rest of the logic also. Otherwise, we can enable the READ
1215 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
1216 //ConnFailed which means we are going to free the tcpInfo. While it
1217 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
1218 //and potentially call doTCPCallback with error which can close the fd and free the
1219 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
1220 //is already freed.
1221
1222 dispatch_async(dispatch_get_main_queue(), ^{
1223
1224 LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1225
1226 if (sock->handshake == handshake_to_be_closed)
1227 {
1228 LogInfo("SSLHandshake completed after close");
1229 mDNSPlatformTCPCloseConnection(sock);
1230 }
1231 else
1232 {
1233 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1234 else LogMsg("doSSLHandshake: sock->fd is -1");
1235
1236 if (err == errSSLWouldBlock)
1237 sock->handshake = handshake_required;
1238 else
1239 {
1240 if (err)
1241 {
1242 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1243 CFRelease(sock->tlsContext);
1244 sock->tlsContext = NULL;
1245 }
1246
1247 sock->err = err ? mStatus_ConnFailed : 0;
1248 sock->handshake = handshake_completed;
1249
1250 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1251 doTcpSocketCallback(sock);
1252 }
1253 }
1254
1255 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1256 return;
1257 });
1258 }
1259 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1260 mDNSlocal void *doSSLHandshake(TCPSocket *sock)
1261 {
1262 // Warning: Touching sock without the kqueue lock!
1263 // We're protected because sock->handshake == handshake_in_progress
1264 mStatus err = SSLHandshake(sock->tlsContext);
1265
1266 KQueueLock();
1267 debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1268
1269 if (sock->handshake == handshake_to_be_closed)
1270 {
1271 LogInfo("SSLHandshake completed after close");
1272 mDNSPlatformTCPCloseConnection(sock);
1273 }
1274 else
1275 {
1276 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1277 else LogMsg("doSSLHandshake: sock->fd is -1");
1278
1279 if (err == errSSLWouldBlock)
1280 sock->handshake = handshake_required;
1281 else
1282 {
1283 if (err)
1284 {
1285 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1286 CFRelease(sock->tlsContext);
1287 sock->tlsContext = NULL;
1288 }
1289
1290 sock->err = err ? mStatus_ConnFailed : 0;
1291 sock->handshake = handshake_completed;
1292
1293 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1294 doTcpSocketCallback(sock);
1295 }
1296 }
1297
1298 debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1299 KQueueUnlock("doSSLHandshake");
1300 return NULL;
1301 }
1302 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1303
1304 mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
1305 {
1306 debugf("spawnSSLHandshake %p: entry", sock);
1307
1308 if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
1309 sock->handshake = handshake_in_progress;
1310 KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
1311
1312 // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
1313 // to limit the number of threads used for SSLHandshake
1314 dispatch_async(SSLqueue, ^{doSSLHandshake(sock);});
1315
1316 debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
1317 }
1318
1319 #endif /* NO_SECURITYFRAMEWORK */
1320
1321 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context, __unused mDNSBool encounteredEOF)
1322 {
1323 TCPSocket *sock = context;
1324 sock->err = mStatus_NoError;
1325
1326 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1327 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1328 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1329 if (filter == EVFILT_WRITE)
1330 KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
1331
1332 if (sock->flags & kTCPSocketFlags_UseTLS)
1333 {
1334 #ifndef NO_SECURITYFRAMEWORK
1335 if (!sock->setup)
1336 {
1337 sock->setup = mDNStrue;
1338 sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
1339 if (sock->err)
1340 {
1341 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
1342 return;
1343 }
1344 }
1345 if (sock->handshake == handshake_required)
1346 {
1347 spawnSSLHandshake(sock);
1348 return;
1349 }
1350 else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
1351 {
1352 return;
1353 }
1354 else if (sock->handshake != handshake_completed)
1355 {
1356 if (!sock->err)
1357 sock->err = mStatus_UnknownErr;
1358 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
1359 }
1360 #else /* NO_SECURITYFRAMEWORK */
1361 sock->err = mStatus_UnsupportedErr;
1362 #endif /* NO_SECURITYFRAMEWORK */
1363 }
1364
1365 doTcpSocketCallback(sock);
1366 }
1367
1368 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1369 mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef)
1370 {
1371 dispatch_queue_t queue = dispatch_get_main_queue();
1372 dispatch_source_t source;
1373 if (flags == EV_DELETE)
1374 {
1375 if (filter == EVFILT_READ)
1376 {
1377 dispatch_source_cancel(entryRef->readSource);
1378 dispatch_release(entryRef->readSource);
1379 entryRef->readSource = mDNSNULL;
1380 debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource);
1381 }
1382 else if (filter == EVFILT_WRITE)
1383 {
1384 dispatch_source_cancel(entryRef->writeSource);
1385 dispatch_release(entryRef->writeSource);
1386 entryRef->writeSource = mDNSNULL;
1387 debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource);
1388 }
1389 else
1390 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
1391 return 0;
1392 }
1393 if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
1394
1395 if (filter == EVFILT_READ)
1396 {
1397 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
1398 }
1399 else if (filter == EVFILT_WRITE)
1400 {
1401 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
1402 }
1403 else
1404 {
1405 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
1406 return -1;
1407 }
1408 if (!source) return -1;
1409 dispatch_source_set_event_handler(source, ^{
1410
1411 mDNSs32 stime = mDNSPlatformRawTime();
1412 entryRef->KQcallback(fd, filter, entryRef->KQcontext);
1413 mDNSs32 etime = mDNSPlatformRawTime();
1414 if (etime - stime >= WatchDogReportingThreshold)
1415 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime);
1416
1417 // Trigger the event delivery to the application. Even though we trigger the
1418 // event completion after handling every event source, these all will hopefully
1419 // get merged
1420 TriggerEventCompletion();
1421
1422 });
1423 dispatch_source_set_cancel_handler(source, ^{
1424 if (entryRef->fdClosed)
1425 {
1426 //LogMsg("CancelHandler: closing fd %d", fd);
1427 close(fd);
1428 }
1429 });
1430 dispatch_resume(source);
1431 if (filter == EVFILT_READ)
1432 entryRef->readSource = source;
1433 else
1434 entryRef->writeSource = source;
1435
1436 return 0;
1437 }
1438
1439 mDNSexport void KQueueLock()
1440 {
1441 }
1442 mDNSexport void KQueueUnlock(const char const *task)
1443 {
1444 (void)task; //unused
1445 }
1446 #else
1447 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
1448 {
1449 struct kevent new_event;
1450 EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
1451 return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
1452 }
1453
1454 mDNSexport void KQueueLock()
1455 {
1456 mDNS *const m = &mDNSStorage;
1457 pthread_mutex_lock(&m->p->BigMutex);
1458 m->p->BigMutexStartTime = mDNSPlatformRawTime();
1459 }
1460
1461 mDNSexport void KQueueUnlock(const char* task)
1462 {
1463 mDNS *const m = &mDNSStorage;
1464 mDNSs32 end = mDNSPlatformRawTime();
1465 (void)task;
1466 if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
1467 LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
1468
1469 pthread_mutex_unlock(&m->p->BigMutex);
1470
1471 char wake = 1;
1472 if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
1473 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
1474 }
1475 #endif
1476
1477 mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
1478 {
1479 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1480 (void) fd; //unused
1481 if (kq->readSource)
1482 {
1483 dispatch_source_cancel(kq->readSource);
1484 kq->readSource = mDNSNULL;
1485 }
1486 if (kq->writeSource)
1487 {
1488 dispatch_source_cancel(kq->writeSource);
1489 kq->writeSource = mDNSNULL;
1490 }
1491 // Close happens in the cancellation handler
1492 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
1493 kq->fdClosed = mDNStrue;
1494 #else
1495 (void)kq; //unused
1496 close(fd);
1497 #endif
1498 }
1499
1500 mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
1501 {
1502 KQSocketSet *cp = &sock->ss;
1503 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
1504 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
1505 const int on = 1; // "on" for setsockopt
1506 mStatus err;
1507
1508 int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
1509 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
1510
1511 // for TCP sockets, the traffic class is set once and not changed
1512 setTrafficClass(skt, useBackgroundTrafficClass);
1513
1514 if (sa_family == AF_INET)
1515 {
1516 // Bind it
1517 struct sockaddr_in addr;
1518 mDNSPlatformMemZero(&addr, sizeof(addr));
1519 addr.sin_family = AF_INET;
1520 addr.sin_port = port->NotAnInteger;
1521 err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
1522 if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); close(skt); return err; }
1523
1524 // Receive interface identifiers
1525 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
1526 if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); close(skt); return err; }
1527
1528 mDNSPlatformMemZero(&addr, sizeof(addr));
1529 socklen_t len = sizeof(addr);
1530 err = getsockname(skt, (struct sockaddr*) &addr, &len);
1531 if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); close(skt); return err; }
1532
1533 port->NotAnInteger = addr.sin_port;
1534 }
1535 else
1536 {
1537 // Bind it
1538 struct sockaddr_in6 addr6;
1539 mDNSPlatformMemZero(&addr6, sizeof(addr6));
1540 addr6.sin6_family = AF_INET6;
1541 addr6.sin6_port = port->NotAnInteger;
1542 err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
1543 if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); close(skt); return err; }
1544
1545 // We want to receive destination addresses and receive interface identifiers
1546 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
1547 if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); close(skt); return err; }
1548
1549 mDNSPlatformMemZero(&addr6, sizeof(addr6));
1550 socklen_t len = sizeof(addr6);
1551 err = getsockname(skt, (struct sockaddr *) &addr6, &len);
1552 if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); close(skt); return err; }
1553
1554 port->NotAnInteger = addr6.sin6_port;
1555
1556 }
1557 *s = skt;
1558 k->KQcallback = tcpKQSocketCallback;
1559 k->KQcontext = sock;
1560 k->KQtask = "mDNSPlatformTCPSocket";
1561 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1562 k->readSource = mDNSNULL;
1563 k->writeSource = mDNSNULL;
1564 k->fdClosed = mDNSfalse;
1565 #endif
1566 return mStatus_NoError;
1567 }
1568
1569 mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
1570 {
1571 mStatus err;
1572
1573 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
1574 if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
1575
1576 mDNSPlatformMemZero(sock, sizeof(TCPSocket));
1577
1578 sock->ss.m = &mDNSStorage;
1579 sock->ss.sktv4 = -1;
1580 sock->ss.sktv6 = -1;
1581 err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
1582
1583 if (!err)
1584 {
1585 err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass);
1586 if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
1587 }
1588 if (err)
1589 {
1590 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
1591 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
1592 return(mDNSNULL);
1593 }
1594 // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
1595 sock->fd = sock->ss.sktv4;
1596 sock->callback = mDNSNULL;
1597 sock->flags = flags;
1598 sock->context = mDNSNULL;
1599 sock->setup = mDNSfalse;
1600 sock->connected = mDNSfalse;
1601 sock->handshake = handshake_required;
1602 sock->m = &mDNSStorage;
1603 sock->err = mStatus_NoError;
1604
1605 return sock;
1606 }
1607
1608 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
1609 {
1610 KQSocketSet *cp = &sock->ss;
1611 int *s = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
1612 KQueueEntry *k = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
1613 mStatus err = mStatus_NoError;
1614 struct sockaddr_storage ss;
1615
1616 sock->callback = callback;
1617 sock->context = context;
1618 sock->setup = mDNSfalse;
1619 sock->connected = mDNSfalse;
1620 sock->handshake = handshake_required;
1621 sock->err = mStatus_NoError;
1622
1623 if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
1624
1625 if (dst->type == mDNSAddrType_IPv4)
1626 {
1627 struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
1628 mDNSPlatformMemZero(saddr, sizeof(*saddr));
1629 saddr->sin_family = AF_INET;
1630 saddr->sin_port = dstport.NotAnInteger;
1631 saddr->sin_len = sizeof(*saddr);
1632 saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1633 }
1634 else
1635 {
1636 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss;
1637 mDNSPlatformMemZero(saddr6, sizeof(*saddr6));
1638 saddr6->sin6_family = AF_INET6;
1639 saddr6->sin6_port = dstport.NotAnInteger;
1640 saddr6->sin6_len = sizeof(*saddr6);
1641 saddr6->sin6_addr = *(struct in6_addr *)&dst->ip.v6;
1642 }
1643
1644 // Watch for connect complete (write is ready)
1645 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1646 if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
1647 {
1648 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1649 return errno;
1650 }
1651
1652 // Watch for incoming data
1653 if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
1654 {
1655 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1656 return errno;
1657 }
1658
1659 if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
1660 {
1661 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
1662 return mStatus_UnknownErr;
1663 }
1664
1665 // We bind to the interface and all subsequent packets including the SYN will be sent out
1666 // on this interface
1667 //
1668 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
1669 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
1670 if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
1671 {
1672 NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(InterfaceID);
1673 if (dst->type == mDNSAddrType_IPv4)
1674 {
1675 #ifdef IP_BOUND_IF
1676 if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1677 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
1678 #else
1679 (void)InterfaceID; // Unused
1680 (void)info; // Unused
1681 #endif
1682 }
1683 else
1684 {
1685 #ifdef IPV6_BOUND_IF
1686 if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1687 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
1688 #else
1689 (void)InterfaceID; // Unused
1690 (void)info; // Unused
1691 #endif
1692 }
1693 }
1694
1695 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
1696 // from which we can infer the destination address family. Hence we need to remember that here.
1697 // Instead of remembering the address family, we remember the right fd.
1698 sock->fd = *s;
1699 sock->kqEntry = k;
1700 // initiate connection wth peer
1701 if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
1702 {
1703 if (errno == EINPROGRESS) return mStatus_ConnPending;
1704 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
1705 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
1706 else
1707 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
1708 return mStatus_ConnFailed;
1709 }
1710
1711 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1712 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1713 return err;
1714 }
1715
1716 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1717 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
1718 {
1719 mStatus err = mStatus_NoError;
1720
1721 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
1722 if (!sock) return(mDNSNULL);
1723
1724 mDNSPlatformMemZero(sock, sizeof(*sock));
1725 sock->fd = fd;
1726 sock->flags = flags;
1727
1728 if (flags & kTCPSocketFlags_UseTLS)
1729 {
1730 #ifndef NO_SECURITYFRAMEWORK
1731 if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
1732
1733 err = tlsSetupSock(sock, kSSLServerSide, kSSLStreamType);
1734 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
1735
1736 err = SSLSetCertificate(sock->tlsContext, ServerCerts);
1737 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
1738 #else
1739 err = mStatus_UnsupportedErr;
1740 #endif /* NO_SECURITYFRAMEWORK */
1741 }
1742 #ifndef NO_SECURITYFRAMEWORK
1743 exit:
1744 #endif
1745
1746 if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
1747 return(sock);
1748 }
1749
1750 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
1751 {
1752 mDNSu16 port;
1753
1754 port = -1;
1755 if (sock)
1756 {
1757 port = sock->ss.port.NotAnInteger;
1758 }
1759 return port;
1760 }
1761
1762 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
1763 {
1764 if (ss->sktv4 != -1)
1765 {
1766 mDNSPlatformCloseFD(&ss->kqsv4, ss->sktv4);
1767 ss->sktv4 = -1;
1768 }
1769 if (ss->sktv6 != -1)
1770 {
1771 mDNSPlatformCloseFD(&ss->kqsv6, ss->sktv6);
1772 ss->sktv6 = -1;
1773 }
1774 if (ss->closeFlag) *ss->closeFlag = 1;
1775 }
1776
1777 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
1778 {
1779 if (sock)
1780 {
1781 #ifndef NO_SECURITYFRAMEWORK
1782 if (sock->tlsContext)
1783 {
1784 if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
1785 {
1786 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
1787 // When we come back from SSLHandshake, we will notice that a close was here and
1788 // call this function again which will do the cleanup then.
1789 sock->handshake = handshake_to_be_closed;
1790 return;
1791 }
1792
1793 SSLClose(sock->tlsContext);
1794 CFRelease(sock->tlsContext);
1795 sock->tlsContext = NULL;
1796 }
1797 #endif /* NO_SECURITYFRAMEWORK */
1798 if (sock->ss.sktv4 != -1)
1799 shutdown(sock->ss.sktv4, 2);
1800 if (sock->ss.sktv6 != -1)
1801 shutdown(sock->ss.sktv6, 2);
1802 CloseSocketSet(&sock->ss);
1803 sock->fd = -1;
1804
1805 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
1806 }
1807 }
1808
1809 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
1810 {
1811 ssize_t nread = 0;
1812 *closed = mDNSfalse;
1813
1814 if (sock->flags & kTCPSocketFlags_UseTLS)
1815 {
1816 #ifndef NO_SECURITYFRAMEWORK
1817 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
1818 else if (sock->handshake == handshake_in_progress) return 0;
1819 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
1820
1821 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
1822 mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t *)&nread);
1823 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
1824 if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
1825 else if (err && err != errSSLWouldBlock)
1826 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
1827 #else
1828 nread = -1;
1829 *closed = mDNStrue;
1830 #endif /* NO_SECURITYFRAMEWORK */
1831 }
1832 else
1833 {
1834 static int CLOSEDcount = 0;
1835 static int EAGAINcount = 0;
1836 nread = recv(sock->fd, buf, buflen, 0);
1837
1838 if (nread > 0)
1839 {
1840 CLOSEDcount = 0;
1841 EAGAINcount = 0;
1842 } // On success, clear our error counters
1843 else if (nread == 0)
1844 {
1845 *closed = mDNStrue;
1846 if ((++CLOSEDcount % 1000) == 0)
1847 {
1848 LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount);
1849 assert(CLOSEDcount < 1000);
1850 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
1851 // crash mDNSResponder using assert() and restart fresh. See advantages below:
1852 // 1.Better User Experience
1853 // 2.CrashLogs frequency can be monitored
1854 // 3.StackTrace can be used for more info
1855 }
1856 }
1857 // else nread is negative -- see what kind of error we got
1858 else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
1859 else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
1860 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
1861 {
1862 nread = 0;
1863 if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
1864 }
1865 }
1866
1867 return nread;
1868 }
1869
1870 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
1871 {
1872 int nsent;
1873
1874 if (sock->flags & kTCPSocketFlags_UseTLS)
1875 {
1876 #ifndef NO_SECURITYFRAMEWORK
1877 size_t processed;
1878 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
1879 if (sock->handshake == handshake_in_progress) return 0;
1880 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
1881
1882 mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
1883
1884 if (!err) nsent = (int) processed;
1885 else if (err == errSSLWouldBlock) nsent = 0;
1886 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
1887 #else
1888 nsent = -1;
1889 #endif /* NO_SECURITYFRAMEWORK */
1890 }
1891 else
1892 {
1893 nsent = send(sock->fd, msg, len, 0);
1894 if (nsent < 0)
1895 {
1896 if (errno == EAGAIN) nsent = 0;
1897 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
1898 }
1899 }
1900
1901 return nsent;
1902 }
1903
1904 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
1905 {
1906 return sock->fd;
1907 }
1908
1909 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1910 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1911 mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
1912 {
1913 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
1914 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
1915 const int on = 1;
1916 const int twofivefive = 255;
1917 mStatus err = mStatus_NoError;
1918 char *errstr = mDNSNULL;
1919 const int mtu = 0;
1920 int saved_errno;
1921
1922 cp->closeFlag = mDNSNULL;
1923
1924 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
1925 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
1926
1927 // set default traffic class
1928 setTrafficClass(skt, mDNSfalse);
1929
1930 #ifdef SO_RECV_ANYIF
1931 // Enable inbound packets on IFEF_AWDL interface.
1932 // Only done for multicast sockets, since we don't expect unicast socket operations
1933 // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
1934 if (mDNSSameIPPort(port, MulticastDNSPort))
1935 {
1936 err = setsockopt(skt, SOL_SOCKET, SO_RECV_ANYIF, &on, sizeof(on));
1937 if (err < 0) { errstr = "setsockopt - SO_RECV_ANYIF"; goto fail; }
1938 }
1939 #endif // SO_RECV_ANYIF
1940
1941 // ... with a shared UDP port, if it's for multicast receiving
1942 if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort))
1943 {
1944 err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
1945 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
1946 }
1947
1948 // Don't want to wake from sleep for inbound packets on the mDNS sockets
1949 if (mDNSSameIPPort(port, MulticastDNSPort))
1950 {
1951 int nowake = 1;
1952 if (setsockopt(skt, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
1953 LogInfo("SetupSocket: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
1954 }
1955
1956 if (sa_family == AF_INET)
1957 {
1958 // We want to receive destination addresses
1959 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
1960 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
1961
1962 // We want to receive interface identifiers
1963 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
1964 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
1965
1966 // We want to receive packet TTL value so we can check it
1967 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
1968 if (err < 0) { errstr = "setsockopt - IP_RECVTTL"; goto fail; }
1969
1970 // Send unicast packets with TTL 255
1971 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
1972 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
1973
1974 // And multicast packets with TTL 255 too
1975 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
1976 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
1977
1978 // And start listening for packets
1979 struct sockaddr_in listening_sockaddr;
1980 listening_sockaddr.sin_family = AF_INET;
1981 listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
1982 listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0;
1983 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
1984 if (err) { errstr = "bind"; goto fail; }
1985 if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
1986 }
1987 else if (sa_family == AF_INET6)
1988 {
1989 // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
1990 if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; close(skt); return mStatus_NoError; }
1991
1992 // We want to receive destination addresses and receive interface identifiers
1993 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
1994 if (err < 0) { errstr = "setsockopt - IPV6_RECVPKTINFO"; goto fail; }
1995
1996 // We want to receive packet hop count value so we can check it
1997 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
1998 if (err < 0) { errstr = "setsockopt - IPV6_RECVHOPLIMIT"; goto fail; }
1999
2000 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
2001 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
2002 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
2003 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
2004
2005 // Send unicast packets with TTL 255
2006 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
2007 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
2008
2009 // And multicast packets with TTL 255 too
2010 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
2011 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
2012
2013 // Want to receive our own packets
2014 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
2015 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
2016
2017 // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
2018 err = setsockopt(skt, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &mtu, sizeof(mtu));
2019 if (err < 0) // Since it is an optimization if we fail just log the err, no need to close the skt
2020 LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
2021 skt, err, errno, strerror(errno));
2022
2023 // And start listening for packets
2024 struct sockaddr_in6 listening_sockaddr6;
2025 mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
2026 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
2027 listening_sockaddr6.sin6_family = AF_INET6;
2028 listening_sockaddr6.sin6_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
2029 listening_sockaddr6.sin6_flowinfo = 0;
2030 listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
2031 listening_sockaddr6.sin6_scope_id = 0;
2032 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
2033 if (err) { errstr = "bind"; goto fail; }
2034 if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
2035 }
2036
2037 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
2038 fcntl(skt, F_SETFD, 1); // set close-on-exec
2039 *s = skt;
2040 k->KQcallback = myKQSocketCallBack;
2041 k->KQcontext = cp;
2042 k->KQtask = "UDP packet reception";
2043 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2044 k->readSource = mDNSNULL;
2045 k->writeSource = mDNSNULL;
2046 k->fdClosed = mDNSfalse;
2047 #endif
2048 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
2049
2050 return(mStatus_NoError);
2051
2052 fail:
2053 saved_errno = errno;
2054 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
2055 if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
2056 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, saved_errno, strerror(saved_errno));
2057
2058 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
2059 if (!strcmp(errstr, "bind") && saved_errno == EADDRINUSE)
2060 {
2061 err = EADDRINUSE;
2062 if (mDNSSameIPPort(port, MulticastDNSPort))
2063 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
2064 "Congratulations, you've reproduced an elusive bug.\r"
2065 "Please contact the current assignee of <rdar://problem/3814904>.\r"
2066 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2067 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2068 }
2069
2070 mDNSPlatformCloseFD(k, skt);
2071 return(err);
2072 }
2073
2074 mDNSexport UDPSocket *mDNSPlatformUDPSocket(const mDNSIPPort requestedport)
2075 {
2076 mStatus err;
2077 mDNSIPPort port = requestedport;
2078 mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
2079 int i = 10000; // Try at most 10000 times to get a unique random port
2080 UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
2081 if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
2082 mDNSPlatformMemZero(p, sizeof(UDPSocket));
2083 p->ss.port = zeroIPPort;
2084 p->ss.m = &mDNSStorage;
2085 p->ss.sktv4 = -1;
2086 p->ss.sktv6 = -1;
2087 p->ss.proxy = mDNSfalse;
2088
2089 do
2090 {
2091 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
2092 if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
2093 err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
2094 if (!err)
2095 {
2096 err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
2097 if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
2098 }
2099 i--;
2100 } while (err == EADDRINUSE && randomizePort && i);
2101
2102 if (err)
2103 {
2104 // In customer builds we don't want to log failures with port 5351, because this is a known issue
2105 // of failing to bind to this port when Internet Sharing has already bound to it
2106 // We also don't want to log about port 5350, due to a known bug when some other
2107 // process is bound to it.
2108 if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
2109 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2110 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2111 freeL("UDPSocket", p);
2112 return(mDNSNULL);
2113 }
2114 return(p);
2115 }
2116
2117 #ifdef UNIT_TEST
2118 UNITTEST_UDPCLOSE
2119 #else
2120 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
2121 {
2122 CloseSocketSet(&sock->ss);
2123 freeL("UDPSocket", sock);
2124 }
2125 #endif
2126
2127 mDNSexport mDNSBool mDNSPlatformUDPSocketEncounteredEOF(const UDPSocket *sock)
2128 {
2129 return (sock->ss.sktv4EOF || sock->ss.sktv6EOF);
2130 }
2131
2132 #if COMPILER_LIKES_PRAGMA_MARK
2133 #pragma mark -
2134 #pragma mark - BPF Raw packet sending/receiving
2135 #endif
2136
2137 #if APPLE_OSX_mDNSResponder
2138
2139 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
2140 {
2141 if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2142 NetworkInterfaceInfoOSX *info;
2143
2144 info = IfindexToInterfaceInfoOSX(InterfaceID);
2145 if (info == NULL)
2146 {
2147 LogMsg("mDNSPlatformSendRawPacket: Invalid interface index %p", InterfaceID);
2148 return;
2149 }
2150 if (info->BPF_fd < 0)
2151 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
2152 else
2153 {
2154 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
2155 if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
2156 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
2157 }
2158 }
2159
2160 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
2161 {
2162 if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
2163 NetworkInterfaceInfoOSX *info;
2164 info = IfindexToInterfaceInfoOSX(InterfaceID);
2165 if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; }
2166 // Manually inject an entry into our local ARP cache.
2167 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
2168 if (!mDNS_AddressIsLocalSubnet(&mDNSStorage, InterfaceID, tpa))
2169 LogSPS("Don't need address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
2170 else
2171 {
2172 int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b);
2173 if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
2174 else LogSPS("Set local address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
2175 }
2176 }
2177
2178 mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
2179 {
2180 LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
2181 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2182 // close will happen in the cancel handler
2183 dispatch_source_cancel(i->BPF_source);
2184 #else
2185
2186 // Note: MUST NOT close() the underlying native BSD sockets.
2187 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
2188 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
2189 CFRunLoopRemoveSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode);
2190 CFRelease(i->BPF_rls);
2191 CFSocketInvalidate(i->BPF_cfs);
2192 CFRelease(i->BPF_cfs);
2193 #endif
2194 i->BPF_fd = -1;
2195 if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
2196 }
2197
2198 mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
2199 {
2200 KQueueLock();
2201
2202 // 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
2203 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
2204 if (info->BPF_fd < 0) goto exit;
2205
2206 ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
2207 const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
2208 const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
2209 debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
2210
2211 if (n<0)
2212 {
2213 /* <rdar://problem/10287386>
2214 * sometimes there can be a race condition btw when the bpf socket
2215 * gets data and the callback get scheduled and when we call BIOCSETF (which
2216 * clears the socket). this can cause the read to hang for a really long time
2217 * and effectively prevent us from responding to requests for long periods of time.
2218 * to prevent this make the socket non blocking and just bail if we dont get anything
2219 */
2220 if (errno == EAGAIN)
2221 {
2222 LogMsg("bpf_callback got EAGAIN bailing");
2223 goto exit;
2224 }
2225 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
2226 CloseBPF(info);
2227 goto exit;
2228 }
2229
2230 while (ptr < end)
2231 {
2232 const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr;
2233 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
2234 info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen,
2235 ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
2236 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
2237 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
2238 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
2239 mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
2240 ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
2241 }
2242 exit:
2243 KQueueUnlock("bpf_callback");
2244 }
2245 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2246 mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
2247 {
2248 bpf_callback_common(info);
2249 }
2250 #else
2251 mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
2252 {
2253 (void)cfs;
2254 (void)CallBackType;
2255 (void)address;
2256 (void)data;
2257 bpf_callback_common((NetworkInterfaceInfoOSX *)context);
2258 }
2259 #endif
2260
2261 mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
2262 {
2263 LogMsg("mDNSPlatformSendKeepalive called\n");
2264 mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win);
2265 }
2266
2267 mDNSexport mStatus mDNSPlatformClearSPSData(void)
2268 {
2269 CFStringRef spsAddressKey = NULL;
2270 CFStringRef ownerOPTRecKey = NULL;
2271 SCDynamicStoreRef addrStore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SPSAddresses"), NULL, NULL);
2272 SCDynamicStoreRef optStore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SPSOPTRecord"), NULL, NULL);
2273
2274 spsAddressKey = SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyAddress"));
2275 if (spsAddressKey != NULL)
2276 {
2277 CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, spsAddressKey);
2278 if (keyList != NULL)
2279 {
2280 if (SCDynamicStoreSetMultiple(addrStore, NULL, keyList, NULL) == false)
2281 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr( spsAddressKey, kCFStringEncodingASCII), SCErrorString(SCError()));
2282 }
2283 if (keyList) CFRelease(keyList);
2284 }
2285 ownerOPTRecKey= SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyOPTRecord"));
2286 if(ownerOPTRecKey != NULL)
2287 {
2288 CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, ownerOPTRecKey);
2289 if (keyList != NULL)
2290 {
2291 if (SCDynamicStoreSetMultiple(optStore, NULL, keyList, NULL) == false)
2292 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr(ownerOPTRecKey, kCFStringEncodingASCII), SCErrorString(SCError()));
2293 }
2294 if (keyList) CFRelease(keyList);
2295 }
2296
2297 if (addrStore) CFRelease(addrStore);
2298 if (optStore) CFRelease(optStore);
2299 if (spsAddressKey) CFRelease(spsAddressKey);
2300 if (ownerOPTRecKey) CFRelease(ownerOPTRecKey);
2301 return KERN_SUCCESS;
2302 }
2303
2304 mDNSlocal int getMACAddress(int family, v6addr_t raddr, v6addr_t gaddr, int *gfamily, ethaddr_t eth)
2305 {
2306 struct
2307 {
2308 struct rt_msghdr m_rtm;
2309 char m_space[512];
2310 } m_rtmsg;
2311
2312 struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
2313 char *cp = m_rtmsg.m_space;
2314 int seq = 6367, sock, rlen, i;
2315 struct sockaddr_in *sin = NULL;
2316 struct sockaddr_in6 *sin6 = NULL;
2317 struct sockaddr_dl *sdl = NULL;
2318 struct sockaddr_storage sins;
2319 struct sockaddr_dl sdl_m;
2320
2321 #define NEXTADDR(w, s, len) \
2322 if (rtm->rtm_addrs & (w)) \
2323 { \
2324 bcopy((char *)s, cp, len); \
2325 cp += len; \
2326 }
2327
2328 bzero(&sins, sizeof(struct sockaddr_storage));
2329 bzero(&sdl_m, sizeof(struct sockaddr_dl));
2330 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
2331
2332 sock = socket(PF_ROUTE, SOCK_RAW, 0);
2333 if (sock < 0)
2334 {
2335 const int socket_errno = errno;
2336 LogMsg("getMACAddress: Can not open the socket - %s", strerror(socket_errno));
2337 return socket_errno;
2338 }
2339
2340 rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY;
2341 rtm->rtm_type = RTM_GET;
2342 rtm->rtm_flags = 0;
2343 rtm->rtm_version = RTM_VERSION;
2344 rtm->rtm_seq = ++seq;
2345
2346 sdl_m.sdl_len = sizeof(sdl_m);
2347 sdl_m.sdl_family = AF_LINK;
2348 if (family == AF_INET)
2349 {
2350 sin = (struct sockaddr_in*)&sins;
2351 sin->sin_family = AF_INET;
2352 sin->sin_len = sizeof(struct sockaddr_in);
2353 memcpy(&sin->sin_addr, raddr, sizeof(struct in_addr));
2354 NEXTADDR(RTA_DST, sin, sin->sin_len);
2355 }
2356 else if (family == AF_INET6)
2357 {
2358 sin6 = (struct sockaddr_in6 *)&sins;
2359 sin6->sin6_len = sizeof(struct sockaddr_in6);
2360 sin6->sin6_family = AF_INET6;
2361 memcpy(&sin6->sin6_addr, raddr, sizeof(struct in6_addr));
2362 NEXTADDR(RTA_DST, sin6, sin6->sin6_len);
2363 }
2364 NEXTADDR(RTA_GATEWAY, &sdl_m, sdl_m.sdl_len);
2365 rtm->rtm_msglen = rlen = cp - (char *)&m_rtmsg;
2366
2367 if (write(sock, (char *)&m_rtmsg, rlen) < 0)
2368 {
2369 const int write_errno = errno;
2370 LogMsg("getMACAddress: writing to routing socket: %s", strerror(write_errno));
2371 close(sock);
2372 return write_errno;
2373 }
2374
2375 do
2376 {
2377 rlen = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
2378 }
2379 while (rlen > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid()));
2380
2381 if (rlen < 0)
2382 LogMsg("getMACAddress: Read from routing socket failed");
2383
2384 if (family == AF_INET)
2385 {
2386 sin = (struct sockaddr_in *) (rtm + 1);
2387 sdl = (struct sockaddr_dl *) (sin->sin_len + (char *) sin);
2388 }
2389 else if (family == AF_INET6)
2390 {
2391 sin6 = (struct sockaddr_in6 *) (rtm +1);
2392 sdl = (struct sockaddr_dl *) (sin6->sin6_len + (char *) sin6);
2393 }
2394
2395 if (!sdl)
2396 {
2397 LogMsg("getMACAddress: sdl is NULL for family %d", family);
2398 close(sock);
2399 return -1;
2400 }
2401
2402 // If the address is not on the local net, we get the IP address of the gateway.
2403 // We would have to repeat the process to get the MAC address of the gateway
2404 *gfamily = sdl->sdl_family;
2405 if (sdl->sdl_family == AF_INET)
2406 {
2407 if (sin)
2408 {
2409 struct sockaddr_in *new_sin = (struct sockaddr_in *)(sin->sin_len +(char*) sin);
2410 memcpy(gaddr, &new_sin->sin_addr, sizeof(struct in_addr));
2411 }
2412 else
2413 {
2414 LogMsg("getMACAddress: sin is NULL");
2415 }
2416 close(sock);
2417 return -1;
2418 }
2419 else if (sdl->sdl_family == AF_INET6)
2420 {
2421 if (sin6)
2422 {
2423 struct sockaddr_in6 *new_sin6 = (struct sockaddr_in6 *)(sin6->sin6_len +(char*) sin6);
2424 memcpy(gaddr, &new_sin6->sin6_addr, sizeof(struct in6_addr));
2425 }
2426 else
2427 {
2428 LogMsg("getMACAddress: sin6 is NULL");
2429 }
2430 close(sock);
2431 return -1;
2432 }
2433
2434 unsigned char *ptr = (unsigned char *)LLADDR(sdl);
2435 for (i = 0; i < ETHER_ADDR_LEN; i++)
2436 (eth)[i] = *(ptr +i);
2437
2438 close(sock);
2439
2440 return KERN_SUCCESS;
2441 }
2442
2443 mDNSlocal int GetRemoteMacinternal(int family, v6addr_t raddr, ethaddr_t eth)
2444 {
2445 int ret = 0;
2446 v6addr_t gateway;
2447 int gfamily = 0;
2448 int count = 0;
2449
2450 do
2451 {
2452 ret = getMACAddress(family, raddr, gateway, &gfamily, eth);
2453 if (ret == -1)
2454 {
2455 memcpy(raddr, gateway, sizeof(family));
2456 family = gfamily;
2457 count++;
2458 }
2459 }
2460 while ((ret == -1) && (count < 5));
2461 return ret;
2462 }
2463
2464 mDNSlocal int StoreSPSMACAddressinternal(int family, v6addr_t spsaddr, const char *ifname)
2465 {
2466 ethaddr_t eth;
2467 char spsip[INET6_ADDRSTRLEN];
2468 int ret = 0;
2469 CFStringRef sckey = NULL;
2470 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL, NULL);
2471 SCDynamicStoreRef ipstore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL, NULL);
2472 CFMutableDictionaryRef dict = NULL;
2473 CFStringRef entityname = NULL;
2474 CFDictionaryRef ipdict = NULL;
2475 CFArrayRef addrs = NULL;
2476
2477 if ((store == NULL) || (ipstore == NULL))
2478 {
2479 LogMsg("StoreSPSMACAddressinternal: Unable to accesss SC Dynamic Store");
2480 ret = -1;
2481 goto fin;
2482 }
2483
2484 // Get the MAC address of the Sleep Proxy Server
2485 memset(eth, 0, sizeof(eth));
2486 ret = GetRemoteMacinternal(family, spsaddr, eth);
2487 if (ret != 0)
2488 {
2489 LogMsg("StoreSPSMACAddressinternal: Failed to determine the MAC address");
2490 goto fin;
2491 }
2492
2493 // Create/Update the dynamic store entry for the specified interface
2494 sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyAddress");
2495 dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2496 if (!dict)
2497 {
2498 LogMsg("StoreSPSMACAddressinternal: SPSCreateDict() Could not create CFDictionary dict");
2499 ret = -1;
2500 goto fin;
2501 }
2502
2503 CFStringRef macaddr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
2504 CFDictionarySetValue(dict, CFSTR("MACAddress"), macaddr);
2505 if (NULL != macaddr)
2506 CFRelease(macaddr);
2507
2508 if( NULL == inet_ntop(family, (void *)spsaddr, spsip, sizeof(spsip)))
2509 {
2510 LogMsg("StoreSPSMACAddressinternal: inet_ntop failed: %s", strerror(errno));
2511 ret = -1;
2512 goto fin;
2513 }
2514
2515 CFStringRef ipaddr = CFStringCreateWithCString(NULL, spsip, kCFStringEncodingUTF8);
2516 CFDictionarySetValue(dict, CFSTR("IPAddress"), ipaddr);
2517 if (NULL != ipaddr)
2518 CFRelease(ipaddr);
2519
2520 // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup
2521 if ((entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/IPv6"), ifname)) != NULL)
2522 {
2523 if ((ipdict = SCDynamicStoreCopyValue(ipstore, entityname)) != NULL)
2524 {
2525 if((addrs = CFDictionaryGetValue(ipdict, CFSTR("Addresses"))) != NULL)
2526 {
2527 addrs = CFRetain(addrs);
2528 CFDictionarySetValue(dict, CFSTR("RegisteredAddresses"), addrs);
2529 }
2530 }
2531 }
2532 SCDynamicStoreSetValue(store, sckey, dict);
2533
2534 fin:
2535 if (store) CFRelease(store);
2536 if (ipstore) CFRelease(ipstore);
2537 if (sckey) CFRelease(sckey);
2538 if (dict) CFRelease(dict);
2539 if (ipdict) CFRelease(ipdict);
2540 if (entityname) CFRelease(entityname);
2541 if (addrs) CFRelease(addrs);
2542
2543 return ret;
2544 }
2545
2546 mDNSlocal void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname)
2547 {
2548 struct
2549 {
2550 v6addr_t saddr;
2551 } addr;
2552 int err = 0;
2553
2554 mDNSPlatformMemCopy(addr.saddr, spsaddr, sizeof(v6addr_t));
2555
2556 err = StoreSPSMACAddressinternal(family, (uint8_t *)addr.saddr, ifname);
2557 if (err != 0)
2558 LogMsg("mDNSStoreSPSMACAddress : failed");
2559 }
2560
2561 mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
2562 {
2563 int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2564
2565 LogInfo("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname);
2566 mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname);
2567
2568 return KERN_SUCCESS;
2569 }
2570
2571
2572 mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage* msg, int length)
2573 {
2574 int ret = 0;
2575 CFStringRef sckey = NULL;
2576 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreOwnerOPTRecord"), NULL, NULL);
2577 CFMutableDictionaryRef dict = NULL;
2578
2579 if (store == NULL)
2580 {
2581 LogMsg("mDNSPlatformStoreOwnerOptRecord: Unable to accesss SC Dynamic Store");
2582 ret = -1;
2583 goto fin;
2584 }
2585
2586 // Create/Update the dynamic store entry for the specified interface
2587 sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyOPTRecord");
2588 dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2589 if (!dict)
2590 {
2591 LogMsg("mDNSPlatformStoreOwnerOptRecord: Could not create CFDictionary dictionary to store OPT Record");
2592 ret =-1;
2593 goto fin;
2594 }
2595
2596 CFDataRef optRec = NULL;
2597 optRec = CFDataCreate(NULL, (const uint8_t *)msg, (CFIndex)length);
2598 CFDictionarySetValue(dict, CFSTR("OwnerOPTRecord"), optRec);
2599 if (NULL != optRec) CFRelease(optRec);
2600
2601 SCDynamicStoreSetValue(store, sckey, dict);
2602
2603 fin:
2604 if (NULL != store) CFRelease(store);
2605 if (NULL != sckey) CFRelease(sckey);
2606 if (NULL != dict) CFRelease(dict);
2607 return ret;
2608 }
2609
2610 mDNSlocal void mDNSGet_RemoteMAC(int family, v6addr_t raddr)
2611 {
2612 ethaddr_t eth;
2613 IPAddressMACMapping *addrMapping;
2614 int kr = KERN_FAILURE;
2615 struct
2616 {
2617 v6addr_t addr;
2618 } dst;
2619
2620 bzero(eth, sizeof(ethaddr_t));
2621 mDNSPlatformMemCopy(dst.addr, raddr, sizeof(v6addr_t));
2622
2623 kr = GetRemoteMacinternal(family, (uint8_t *)dst.addr, eth);
2624
2625 // If the call to get the remote MAC address succeeds, allocate and copy
2626 // the values and schedule a task to update the MAC address in the TCP Keepalive record.
2627 if (kr == 0)
2628 {
2629 addrMapping = mDNSPlatformMemAllocate(sizeof(IPAddressMACMapping));
2630 snprintf(addrMapping->ethaddr, sizeof(addrMapping->ethaddr), "%02x:%02x:%02x:%02x:%02x:%02x",
2631 eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
2632 if (family == AF_INET)
2633 {
2634 addrMapping->ipaddr.type = mDNSAddrType_IPv4;
2635 mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, raddr, sizeof(v6addr_t));
2636 }
2637 else
2638 {
2639 addrMapping->ipaddr.type = mDNSAddrType_IPv6;
2640 mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v6.b, raddr, sizeof(v6addr_t));
2641 }
2642 UpdateRMAC(&mDNSStorage, addrMapping);
2643 }
2644 }
2645
2646 mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr)
2647 {
2648 int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2649
2650 LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC");
2651 mDNSGet_RemoteMAC(family, raddr->ip.v6.b);
2652
2653 return KERN_SUCCESS;
2654 }
2655
2656 mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
2657 {
2658 mDNSs32 intfid;
2659 mDNSs32 error = 0;
2660 int family = (laddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2661
2662 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);
2663 if (error != KERN_SUCCESS)
2664 {
2665 LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error);
2666 return error;
2667 }
2668 mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, intfid);
2669 return error;
2670 }
2671
2672 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2673
2674 mDNSlocal int CountProxyTargets(NetworkInterfaceInfoOSX *x, int *p4, int *p6)
2675 {
2676 int numv4 = 0, numv6 = 0;
2677 AuthRecord *rr;
2678
2679 for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
2680 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2681 {
2682 if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
2683 numv4++;
2684 }
2685
2686 for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
2687 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2688 {
2689 if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
2690 numv6++;
2691 }
2692
2693 if (p4) *p4 = numv4;
2694 if (p6) *p6 = numv6;
2695 return(numv4 + numv6);
2696 }
2697
2698 mDNSexport void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)
2699 {
2700 mDNS *const m = &mDNSStorage;
2701 NetworkInterfaceInfoOSX *x;
2702
2703 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
2704 for (x = m->p->InterfaceList; x; x = x->next) if ((x->ifinfo.InterfaceID == InterfaceID) && (x->BPF_fd >= 0)) break;
2705
2706 if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
2707
2708 #define MAX_BPF_ADDRS 250
2709 int numv4 = 0, numv6 = 0;
2710
2711 if (CountProxyTargets(x, &numv4, &numv6) > MAX_BPF_ADDRS)
2712 {
2713 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
2714 if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
2715 numv6 = MAX_BPF_ADDRS - numv4;
2716 }
2717
2718 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
2719
2720 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
2721 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
2722 static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
2723 {
2724 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13)
2725
2726 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
2727 BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP
2728
2729 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
2730
2731 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
2732 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
2733 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
2734 BPF_STMT(BPF_RET + BPF_K, 86), // 7 Return 86-byte ND
2735
2736 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
2737 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
2738 };
2739
2740 // Special filter program to use when there are no address proxy records
2741 static struct bpf_insn nullfilter[] =
2742 {
2743 BPF_STMT(BPF_RET | BPF_K, 0) // 0 Match no packets and return size 0
2744 };
2745
2746 struct bpf_program prog;
2747 if (!numv4 && !numv6)
2748 {
2749 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
2750 if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
2751
2752 // Cancel any previous ND group memberships we had
2753 if (x->BPF_mcfd >= 0)
2754 {
2755 close(x->BPF_mcfd);
2756 x->BPF_mcfd = -1;
2757 }
2758
2759 // Schedule check to see if we can close this BPF_fd now
2760 if (!m->NetworkChanged) m->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
2761 if (x->BPF_fd < 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
2762 prog.bf_len = 1;
2763 prog.bf_insns = nullfilter;
2764 }
2765 else
2766 {
2767 struct bpf_insn *pc = &filter[9];
2768 struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0"
2769 struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks
2770 struct bpf_insn *ret4 = fail + 1;
2771 struct bpf_insn *ret6 = ret4 + 4;
2772
2773 static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing
2774
2775 static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
2776
2777 static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20)
2778 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)
2779 static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length
2780 static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
2781
2782 static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
2783
2784 BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail
2785 BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check
2786
2787 // BPF Byte-Order Note
2788 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
2789 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
2790 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
2791 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
2792 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
2793 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
2794 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
2795 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
2796 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
2797 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
2798
2799 // IPSEC capture size notes:
2800 // 8 bytes UDP header
2801 // 4 bytes Non-ESP Marker
2802 // 28 bytes IKE Header
2803 // --
2804 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
2805
2806 AuthRecord *rr;
2807 for (rr = m->ResourceRecords; rr; rr=rr->next)
2808 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2809 {
2810 mDNSv4Addr a = rr->AddressProxy.ip.v4;
2811 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2812 BPF_SetOffset(pc, jt, ret4);
2813 pc->jf = 0;
2814 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];
2815 pc++;
2816 }
2817 *pc++ = rf;
2818
2819 if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
2820 *pc++ = g6; // chk6 points here
2821
2822 // First cancel any previous ND group memberships we had, then create a fresh socket
2823 if (x->BPF_mcfd >= 0) close(x->BPF_mcfd);
2824 x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0);
2825
2826 for (rr = m->ResourceRecords; rr; rr=rr->next)
2827 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2828 {
2829 const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
2830 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2831 BPF_SetOffset(pc, jt, ret6);
2832 pc->jf = 0;
2833 pc->k = (bpf_u_int32)a->b[0x0C] << 24 | (bpf_u_int32)a->b[0x0D] << 16 | (bpf_u_int32)a->b[0x0E] << 8 | (bpf_u_int32)a->b[0x0F];
2834 pc++;
2835
2836 struct ipv6_mreq i6mr;
2837 i6mr.ipv6mr_interface = x->scope_id;
2838 i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix;
2839 i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD];
2840 i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE];
2841 i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF];
2842
2843 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
2844 mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
2845 if (err < 0 && (errno != EADDRNOTAVAIL))
2846 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2847
2848 err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
2849 if (err < 0 && (errno != EADDRINUSE)) // Joining same group twice can give "Address already in use" error -- no need to report that
2850 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2851
2852 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
2853 }
2854
2855 if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
2856 *pc++ = rf; // fail points here
2857
2858 if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
2859 *pc++ = r4a; // ret4 points here
2860 *pc++ = r4b;
2861 *pc++ = r4c;
2862 *pc++ = r4d;
2863
2864 if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
2865 *pc++ = r6a; // ret6 points here
2866 #if 0
2867 // For debugging BPF filter program
2868 unsigned int q;
2869 for (q=0; q<prog.bf_len; q++)
2870 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);
2871 #endif
2872 prog.bf_len = (u_int)(pc - filter);
2873 prog.bf_insns = filter;
2874 }
2875
2876 if (ioctl(x->BPF_fd, BIOCSETFNR, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
2877 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog.bf_len);
2878 }
2879
2880 mDNSexport void mDNSPlatformReceiveBPF_fd(int fd)
2881 {
2882 mDNS *const m = &mDNSStorage;
2883 mDNS_Lock(m);
2884
2885 NetworkInterfaceInfoOSX *i;
2886 for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
2887 if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
2888 else
2889 {
2890 LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd);
2891
2892 struct bpf_version v;
2893 if (ioctl(fd, BIOCVERSION, &v) < 0)
2894 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2895 else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
2896 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
2897 fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
2898
2899 if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
2900 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2901
2902 if (i->BPF_len > sizeof(m->imsg))
2903 {
2904 i->BPF_len = sizeof(m->imsg);
2905 if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
2906 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2907 else
2908 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd, i->ifinfo.ifname, i->BPF_len);
2909 }
2910
2911 static const u_int opt_one = 1;
2912 if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0)
2913 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2914
2915 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
2916 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2917
2918 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
2919 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2920
2921 /* <rdar://problem/10287386>
2922 * make socket non blocking see comments in bpf_callback_common for more info
2923 */
2924 if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
2925 {
2926 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2927 }
2928
2929 struct ifreq ifr;
2930 mDNSPlatformMemZero(&ifr, sizeof(ifr));
2931 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
2932 if (ioctl(fd, BIOCSETIF, &ifr) < 0)
2933 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
2934 else
2935 {
2936 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2937 i->BPF_fd = fd;
2938 i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());
2939 if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
2940 dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);});
2941 dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);});
2942 dispatch_resume(i->BPF_source);
2943 #else
2944 CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
2945 i->BPF_fd = fd;
2946 i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
2947 i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
2948 CFRunLoopAddSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode);
2949 #endif
2950 mDNSPlatformUpdateProxyList(i->ifinfo.InterfaceID);
2951 }
2952 }
2953
2954 mDNS_Unlock(m);
2955 }
2956
2957 #endif // APPLE_OSX_mDNSResponder
2958
2959 #if COMPILER_LIKES_PRAGMA_MARK
2960 #pragma mark -
2961 #pragma mark - Key Management
2962 #endif
2963
2964 #ifndef NO_SECURITYFRAMEWORK
2965 mDNSlocal CFArrayRef CopyCertChain(SecIdentityRef identity)
2966 {
2967 CFMutableArrayRef certChain = NULL;
2968 if (!identity) { LogMsg("CopyCertChain: identity is NULL"); return(NULL); }
2969 SecCertificateRef cert;
2970 OSStatus err = SecIdentityCopyCertificate(identity, &cert);
2971 if (err || !cert) LogMsg("CopyCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
2972 else
2973 {
2974 #pragma clang diagnostic push
2975 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2976 SecPolicySearchRef searchRef;
2977 err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
2978 if (err || !searchRef) LogMsg("CopyCertChain: SecPolicySearchCreate() returned %d", (int) err);
2979 else
2980 {
2981 SecPolicyRef policy;
2982 err = SecPolicySearchCopyNext(searchRef, &policy);
2983 if (err || !policy) LogMsg("CopyCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
2984 else
2985 {
2986 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
2987 if (!wrappedCert) LogMsg("CopyCertChain: wrappedCert is NULL");
2988 else
2989 {
2990 SecTrustRef trust;
2991 err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
2992 if (err || !trust) LogMsg("CopyCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
2993 else
2994 {
2995 err = SecTrustEvaluate(trust, NULL);
2996 if (err) LogMsg("CopyCertChain: SecTrustEvaluate() returned %d", (int) err);
2997 else
2998 {
2999 CFArrayRef rawCertChain;
3000 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
3001 err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
3002 if (err || !rawCertChain || !statusChain) LogMsg("CopyCertChain: SecTrustGetResult() returned %d", (int) err);
3003 else
3004 {
3005 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
3006 if (!certChain) LogMsg("CopyCertChain: certChain is NULL");
3007 else
3008 {
3009 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
3010 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
3011 CFArraySetValueAtIndex(certChain, 0, identity);
3012 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
3013 if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
3014 }
3015 CFRelease(rawCertChain);
3016 // Do not free statusChain:
3017 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
3018 // certChain: Call the CFRelease function to release this object when you are finished with it.
3019 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
3020 }
3021 }
3022 CFRelease(trust);
3023 }
3024 CFRelease(wrappedCert);
3025 }
3026 CFRelease(policy);
3027 }
3028 CFRelease(searchRef);
3029 }
3030 #pragma clang diagnostic pop
3031 CFRelease(cert);
3032 }
3033 return certChain;
3034 }
3035 #endif /* NO_SECURITYFRAMEWORK */
3036
3037 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
3038 {
3039 #ifdef NO_SECURITYFRAMEWORK
3040 return mStatus_UnsupportedErr;
3041 #else
3042 SecIdentityRef identity = nil;
3043 SecIdentitySearchRef srchRef = nil;
3044 OSStatus err;
3045
3046 #pragma clang diagnostic push
3047 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3048 // search for "any" identity matching specified key use
3049 // In this app, we expect there to be exactly one
3050 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
3051 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
3052
3053 err = SecIdentitySearchCopyNext(srchRef, &identity);
3054 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
3055 #pragma clang diagnostic pop
3056
3057 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
3058 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
3059
3060 // Found one. Call CopyCertChain to create the correct certificate chain.
3061 ServerCerts = CopyCertChain(identity);
3062 if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: CopyCertChain error"); return mStatus_UnknownErr; }
3063
3064 return mStatus_NoError;
3065 #endif /* NO_SECURITYFRAMEWORK */
3066 }
3067
3068 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
3069 {
3070 #ifndef NO_SECURITYFRAMEWORK
3071 if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
3072 #endif /* NO_SECURITYFRAMEWORK */
3073 }
3074
3075 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
3076 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
3077 {
3078 CFStringEncoding encoding = kCFStringEncodingUTF8;
3079 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
3080 if (cfs)
3081 {
3082 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3083 CFRelease(cfs);
3084 }
3085 }
3086
3087 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
3088 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
3089 {
3090 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
3091 if (cfs)
3092 {
3093 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3094 CFRelease(cfs);
3095 }
3096 }
3097
3098 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
3099 {
3100 mDNSs32 val;
3101 CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
3102 if (!state) return mDNSfalse;
3103 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
3104 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
3105 return val ? mDNStrue : mDNSfalse;
3106 }
3107
3108 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
3109 {
3110 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
3111
3112 if (sa->sa_family == AF_INET)
3113 {
3114 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
3115 ip->type = mDNSAddrType_IPv4;
3116 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
3117 return(mStatus_NoError);
3118 }
3119
3120 if (sa->sa_family == AF_INET6)
3121 {
3122 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
3123 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
3124 // value into the second word of the IPv6 link-local address, so they can just
3125 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
3126 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
3127 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
3128 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
3129 ip->type = mDNSAddrType_IPv6;
3130 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
3131 return(mStatus_NoError);
3132 }
3133
3134 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
3135 return(mStatus_Invalid);
3136 }
3137
3138 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
3139 {
3140 mDNSEthAddr eth = zeroEthAddr;
3141
3142 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
3143 if (entityname)
3144 {
3145 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, entityname);
3146 if (dict)
3147 {
3148 CFRange range = { 0, 6 }; // Offset, length
3149 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
3150 if (data && CFDataGetLength(data) == 6)
3151 CFDataGetBytes(data, range, eth.b);
3152 CFRelease(dict);
3153 }
3154 CFRelease(entityname);
3155 }
3156
3157 return(eth);
3158 }
3159
3160 mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
3161 {
3162 struct ifaddrs *ifa;
3163 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
3164 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
3165 {
3166 const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
3167 if (sdl->sdl_index == ifindex)
3168 { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
3169 }
3170 *eth = zeroEthAddr;
3171 return -1;
3172 }
3173
3174 #ifndef SIOCGIFWAKEFLAGS
3175 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
3176 #endif
3177
3178 #ifndef IF_WAKE_ON_MAGIC_PACKET
3179 #define IF_WAKE_ON_MAGIC_PACKET 0x01
3180 #endif
3181
3182 #ifndef ifr_wake_flags
3183 #define ifr_wake_flags ifr_ifru.ifru_intval
3184 #endif
3185
3186 mDNSlocal mDNSBool CheckInterfaceSupport(NetworkInterfaceInfo *const intf, const char *key)
3187 {
3188 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
3189 if (!service)
3190 {
3191 LogSPS("CheckInterfaceSupport: No service for interface %s", intf->ifname);
3192 return mDNSfalse;
3193 }
3194
3195 io_name_t n1, n2;
3196 IOObjectGetClass(service, n1);
3197 io_object_t parent = IO_OBJECT_NULL;
3198 mDNSBool ret = mDNSfalse;
3199
3200 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
3201 if (kr == KERN_SUCCESS)
3202 {
3203 CFStringRef keystr = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
3204 IOObjectGetClass(parent, n2);
3205 LogSPS("CheckInterfaceSupport: Interface %s service %s parent %s", intf->ifname, n1, n2);
3206 CFTypeRef ref = mDNSNULL;
3207
3208 // Currently, the key can be in a different part of the IOKit hierarchy on the AppleTV.
3209 // TODO: revist if it is ok to have the same call for all platforms.
3210 if (IsAppleTV())
3211 ref = IORegistryEntrySearchCFProperty(parent, kIOServicePlane, keystr, kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively);
3212 else
3213 ref = IORegistryEntryCreateCFProperty(parent, keystr, kCFAllocatorDefault, mDNSNULL);
3214
3215 if (!ref)
3216 {
3217 LogSPS("CheckInterfaceSupport: No %s for interface %s/%s/%s", key, intf->ifname, n1, n2);
3218 ret = mDNSfalse;
3219 }
3220 else
3221 {
3222 ret = mDNStrue;
3223 CFRelease(ref);
3224 }
3225 IOObjectRelease(parent);
3226 CFRelease(keystr);
3227 }
3228 else
3229 {
3230 LogSPS("CheckInterfaceSupport: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
3231 ret = mDNSfalse;
3232 }
3233
3234 IOObjectRelease(service);
3235 return ret;
3236 }
3237
3238
3239 mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
3240 {
3241 return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
3242 }
3243
3244 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
3245 {
3246 // We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D.
3247 if (!MulticastInterface(i) || (i->ifa_flags & IFF_LOOPBACK) || i->D2DInterface)
3248 {
3249 LogSPS("NetWakeInterface: returning false for %s", i->ifinfo.ifname);
3250 return(mDNSfalse);
3251 }
3252
3253 // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
3254 // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
3255 // when the power source is not AC Power.
3256 if (InterfaceSupportsKeepAlive(&i->ifinfo))
3257 {
3258 LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i->ifinfo.ifname);
3259 return mDNStrue;
3260 }
3261
3262 int s = socket(AF_INET, SOCK_DGRAM, 0);
3263 if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); }
3264
3265 struct ifreq ifr;
3266 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3267 if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
3268 {
3269 const int ioctl_errno = errno;
3270 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
3271 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
3272 // error code is being returned from the kernel, we need to use the kernel version.
3273 #define KERNEL_EOPNOTSUPP 102
3274 if (ioctl_errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
3275 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, ioctl_errno, strerror(ioctl_errno));
3276 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
3277 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
3278 ifr.ifr_wake_flags = (ioctl_errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
3279 }
3280
3281 close(s);
3282
3283 // 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
3284
3285 LogSPS("NetWakeInterface: %-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
3286
3287 return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
3288 }
3289
3290 mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
3291 {
3292 int sockFD;
3293 struct ifreq ifr;
3294
3295 sockFD = socket(AF_INET, SOCK_DGRAM, 0);
3296 if (sockFD < 0)
3297 {
3298 LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno, strerror(errno));
3299 return 0;
3300 }
3301
3302 ifr.ifr_addr.sa_family = AF_INET;
3303 strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
3304
3305 if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
3306 {
3307 LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno));
3308 ifr.ifr_eflags = 0;
3309 }
3310
3311 close(sockFD);
3312 return ifr.ifr_eflags;
3313 }
3314
3315 #if TARGET_OS_OSX
3316 // IFRTYPE_FUNCTIONAL_INTCOPROC type interfaces on macOS do not support Bonjour discovery.
3317 mDNSlocal mDNSBool isCoprocessorInterface(int sockFD, char * ifa_name)
3318 {
3319 struct ifreq ifr;
3320
3321 if (sockFD < 0)
3322 {
3323 LogMsg("isCoprocessorInterface: invalid socket FD passed: %d", sockFD);
3324 return mDNSfalse;
3325 }
3326
3327 memset(&ifr, 0, sizeof(struct ifreq));
3328 strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
3329
3330 if (ioctl(sockFD, SIOCGIFFUNCTIONALTYPE, (caddr_t)&ifr) == -1)
3331 {
3332 LogMsg("isCoprocessorInterface: SIOCGIFFUNCTIONALTYPE failed, errno = %d (%s)", errno, strerror(errno));
3333 return mDNSfalse;
3334 }
3335
3336 if (ifr.ifr_functional_type == IFRTYPE_FUNCTIONAL_INTCOPROC)
3337 {
3338 LogMsg("isCoprocessorInterface: %s marked as coprocessor interface", ifa_name);
3339 return mDNStrue;
3340 }
3341 else
3342 return mDNSfalse;
3343 }
3344
3345 #else // TARGET_OS_OSX
3346 #define isCoprocessorInterface(A, B) mDNSfalse
3347 #endif // TARGET_OS_OSX
3348
3349 #if TARGET_OS_IPHONE
3350
3351 // Function pointers for the routines we use in the MobileWiFi framework.
3352 static WiFiManagerClientRef (*WiFiManagerClientCreate_p)(CFAllocatorRef allocator, WiFiClientType type) = mDNSNULL;
3353 static CFArrayRef (*WiFiManagerClientCopyDevices_p)(WiFiManagerClientRef manager) = mDNSNULL;
3354 static WiFiNetworkRef (*WiFiDeviceClientCopyCurrentNetwork_p)(WiFiDeviceClientRef device) = mDNSNULL;
3355 static bool (*WiFiNetworkIsCarPlay_p)(WiFiNetworkRef network) = mDNSNULL;
3356
3357 mDNSlocal mDNSBool MobileWiFiLibLoad(void)
3358 {
3359 static mDNSBool isInitialized = mDNSfalse;
3360 static void *MobileWiFiLib_p = mDNSNULL;
3361 static const char path[] = "/System/Library/PrivateFrameworks/MobileWiFi.framework/MobileWiFi";
3362
3363 if (!isInitialized)
3364 {
3365 if (!MobileWiFiLib_p)
3366 {
3367 MobileWiFiLib_p = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
3368 if (!MobileWiFiLib_p)
3369 {
3370 LogInfo("MobileWiFiLibLoad: dlopen() failed.");
3371 goto exit;
3372 }
3373 }
3374
3375 if (!WiFiManagerClientCreate_p)
3376 {
3377 WiFiManagerClientCreate_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCreate");
3378 if (!WiFiManagerClientCreate_p)
3379 {
3380 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCreate symbol failed.");
3381 goto exit;
3382 }
3383 }
3384
3385 if (!WiFiManagerClientCopyDevices_p)
3386 {
3387 WiFiManagerClientCopyDevices_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCopyDevices");
3388 if (!WiFiManagerClientCopyDevices_p)
3389 {
3390 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCopyDevices symbol failed.");
3391 goto exit;
3392 }
3393 }
3394
3395 if (!WiFiDeviceClientCopyCurrentNetwork_p)
3396 {
3397 WiFiDeviceClientCopyCurrentNetwork_p = dlsym(MobileWiFiLib_p, "WiFiDeviceClientCopyCurrentNetwork");
3398 if (!WiFiDeviceClientCopyCurrentNetwork_p)
3399 {
3400 LogInfo("MobileWiFiLibLoad: load of WiFiDeviceClientCopyCurrentNetwork symbol failed.");
3401 goto exit;
3402 }
3403 }
3404
3405 if (!WiFiNetworkIsCarPlay_p)
3406 {
3407 WiFiNetworkIsCarPlay_p = dlsym(MobileWiFiLib_p, "WiFiNetworkIsCarPlay");
3408 if (!WiFiNetworkIsCarPlay_p)
3409 {
3410 LogInfo("MobileWiFiLibLoad: load of WiFiNetworkIsCarPlay symbol failed.");
3411 goto exit;
3412 }
3413 }
3414
3415 isInitialized = mDNStrue;
3416 }
3417
3418 exit:
3419 return isInitialized;
3420 }
3421
3422 #define CARPLAY_DEBUG 0
3423
3424 // Return true if the interface is associate to a CarPlay hosted SSID.
3425 // If we have associated with a CarPlay hosted SSID, then use the same
3426 // optimizations that are used when an interface has the IFEF_DIRECTLINK flag set.
3427 mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
3428 {
3429 static WiFiManagerClientRef manager = NULL;
3430 CFArrayRef devices;
3431 WiFiDeviceClientRef device;
3432 WiFiNetworkRef network;
3433 mDNSBool rvalue = mDNSfalse;
3434
3435 if (!MobileWiFiLibLoad())
3436 {
3437 LogInfo("IsCarPlaySSID: MobileWiFiLibLoad() failed!");
3438 return mDNSfalse;
3439 }
3440
3441 // Cache the WiFiManagerClientRef.
3442 if (manager == NULL)
3443 manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
3444
3445 if (manager == NULL)
3446 {
3447 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3448 return mDNSfalse;
3449 }
3450
3451 devices = WiFiManagerClientCopyDevices_p(manager);
3452
3453 // If the first call fails, update the cached WiFiManagerClientRef pointer and try again.
3454 if (devices == NULL)
3455 {
3456 LogInfo("IsCarPlaySSID: First call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
3457
3458 // Release the previously cached WiFiManagerClientRef which is apparently now stale.
3459 CFRelease(manager);
3460 manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
3461 if (manager == NULL)
3462 {
3463 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3464 return mDNSfalse;
3465 }
3466 devices = WiFiManagerClientCopyDevices_p(manager);
3467 if (devices == NULL)
3468 {
3469 LogInfo("IsCarPlaySSID: Second call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
3470 return mDNSfalse;
3471 }
3472 }
3473
3474 device = (WiFiDeviceClientRef)CFArrayGetValueAtIndex(devices, 0);
3475 network = WiFiDeviceClientCopyCurrentNetwork_p(device);
3476 if (network != NULL)
3477 {
3478 if (WiFiNetworkIsCarPlay_p(network))
3479 {
3480 LogInfo("IsCarPlaySSID: %s is CarPlay hosted", ifa_name);
3481 rvalue = mDNStrue;
3482 }
3483 #if CARPLAY_DEBUG
3484 else
3485 LogInfo("IsCarPlaySSID: %s is NOT CarPlay hosted", ifa_name);
3486 #endif // CARPLAY_DEBUG
3487
3488 CFRelease(network);
3489 }
3490 else
3491 LogInfo("IsCarPlaySSID: WiFiDeviceClientCopyCurrentNetwork() returned NULL for %s", ifa_name);
3492
3493 CFRelease(devices);
3494
3495 return rvalue;
3496 }
3497
3498 #else // TARGET_OS_IPHONE
3499
3500 mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
3501 {
3502 (void)ifa_name; // unused
3503
3504 // OSX WifiManager currently does not implement WiFiNetworkIsCarPlay()
3505 return mDNSfalse;;
3506 }
3507
3508 #endif // TARGET_OS_IPHONE
3509
3510 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
3511 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
3512 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
3513 // (e.g. sa_family not AF_INET or AF_INET6)
3514 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(struct ifaddrs *ifa, mDNSs32 utc)
3515 {
3516 mDNS *const m = &mDNSStorage;
3517 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
3518 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
3519 u_int64_t eflags = getExtendedFlags(ifa->ifa_name);
3520
3521 mDNSAddr ip, mask;
3522 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
3523 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
3524
3525 NetworkInterfaceInfoOSX **p;
3526 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
3527 if (scope_id == (*p)->scope_id &&
3528 mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
3529 mDNSSameEthAddress(&bssid, &(*p)->BSSID))
3530 {
3531 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);
3532 // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
3533 // When interfaces are created with same MAC address, kernel resurrects the old interface.
3534 // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
3535 // we get the corresponding name for the interface index on which the packet was received and check against
3536 // the InterfaceList for a matching name. So, keep the name in sync
3537 strlcpy((*p)->ifinfo.ifname, ifa->ifa_name, sizeof((*p)->ifinfo.ifname));
3538
3539 // Determine if multicast state has changed.
3540 const mDNSBool txrx = MulticastInterface(*p);
3541 if ((*p)->ifinfo.McastTxRx != txrx)
3542 {
3543 (*p)->ifinfo.McastTxRx = txrx;
3544 (*p)->Exists = MulticastStateChanged; // State change; need to deregister and reregister this interface
3545 }
3546 else
3547 (*p)->Exists = mDNStrue;
3548
3549 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
3550 if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
3551
3552 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
3553 // we may need to start or stop or sleep proxy browse operation
3554 const mDNSBool NetWake = NetWakeInterface(*p);
3555 if ((*p)->ifinfo.NetWake != NetWake)
3556 {
3557 (*p)->ifinfo.NetWake = NetWake;
3558 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
3559 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
3560 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
3561 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
3562 if ((*p)->Registered)
3563 {
3564 mDNS_Lock(m);
3565 if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo);
3566 else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
3567 mDNS_Unlock(m);
3568 }
3569 }
3570 // Reset the flag if it has changed this time.
3571 (*p)->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
3572
3573 return(*p);
3574 }
3575
3576 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
3577 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
3578 if (!i) return(mDNSNULL);
3579 mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
3580 i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
3581 i->ifinfo.ip = ip;
3582 i->ifinfo.mask = mask;
3583 strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
3584 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
3585 // We can be configured to disable multicast advertisement, but we want to to support
3586 // local-only services, which need a loopback address record.
3587 i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
3588 i->ifinfo.Loopback = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse;
3589 i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
3590
3591 // Setting DirectLink indicates we can do the optimization of skipping the probe phase
3592 // for the interface address records since they should be unique.
3593 // Unfortunately, the legacy p2p* interfaces do not set the IFEF_LOCALNET_PRIVATE
3594 // or IFEF_DIRECTLINK flags, so we have to match against the name.
3595 if ((eflags & (IFEF_DIRECTLINK | IFEF_AWDL)) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0))
3596 i->ifinfo.DirectLink = mDNStrue;
3597 else
3598 i->ifinfo.DirectLink = IsCarPlaySSID(ifa->ifa_name);
3599
3600 if (i->ifinfo.DirectLink)
3601 LogInfo("AddInterfaceToList: DirectLink set for %s", ifa->ifa_name);
3602
3603 i->next = mDNSNULL;
3604 i->m = m;
3605 i->Exists = mDNStrue;
3606 i->Flashing = mDNSfalse;
3607 i->Occulting = mDNSfalse;
3608
3609 i->D2DInterface = ((eflags & IFEF_LOCALNET_PRIVATE) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0)) ? mDNStrue: mDNSfalse;
3610 if (i->D2DInterface)
3611 LogInfo("AddInterfaceToList: D2DInterface set for %s", ifa->ifa_name);
3612
3613 i->isExpensive = (eflags & IFEF_EXPENSIVE) ? mDNStrue: mDNSfalse;
3614 i->isAWDL = (eflags & IFEF_AWDL) ? mDNStrue: mDNSfalse;
3615 i->isCLAT46 = (eflags & IFEF_CLAT46) ? mDNStrue: mDNSfalse;
3616 if (eflags & IFEF_AWDL)
3617 {
3618 // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
3619 // limited AWDL resources so we don't set the kDNSQClass_UnicastResponse bit in
3620 // Bonjour requests over the AWDL interface.
3621 i->ifinfo.SupportsUnicastMDNSResponse = mDNSfalse;
3622 AWDLInterfaceID = i->ifinfo.InterfaceID;
3623 LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
3624 }
3625 else
3626 {
3627 i->ifinfo.SupportsUnicastMDNSResponse = mDNStrue;
3628 }
3629 i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
3630 i->LastSeen = utc;
3631 i->ifa_flags = ifa->ifa_flags;
3632 i->scope_id = scope_id;
3633 i->BSSID = bssid;
3634 i->sa_family = ifa->ifa_addr->sa_family;
3635 i->BPF_fd = -1;
3636 i->BPF_mcfd = -1;
3637 i->BPF_len = 0;
3638 i->Registered = mDNSNULL;
3639
3640 // MulticastInterface() depends on the "m" and "ifa_flags" values being initialized above.
3641 i->ifinfo.McastTxRx = MulticastInterface(i);
3642 // Do this AFTER i->BSSID has been set up
3643 i->ifinfo.NetWake = (eflags & IFEF_EXPENSIVE)? mDNSfalse : NetWakeInterface(i);
3644 GetMAC(&i->ifinfo.MAC, scope_id);
3645 if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
3646 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
3647
3648 *p = i;
3649 return(i);
3650 }
3651
3652 #if APPLE_OSX_mDNSResponder
3653
3654 #if COMPILER_LIKES_PRAGMA_MARK
3655 #pragma mark -
3656 #pragma mark - AutoTunnel
3657 #endif
3658
3659 #define kRacoonPort 4500
3660
3661 static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
3662
3663 #ifndef NO_SECURITYFRAMEWORK
3664
3665 static CFMutableDictionaryRef domainStatusDict = NULL;
3666
3667 mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
3668 {
3669 if (q->LongLived)
3670 {
3671 if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
3672 return mStatus_NoSuchRecord;
3673 else if (q->state == LLQ_Poll)
3674 return mStatus_PollingMode;
3675 else if (q->state != LLQ_Established && !q->DuplicateOf)
3676 return mStatus_TransientErr;
3677 }
3678
3679 return mStatus_NoError;
3680 }
3681
3682 mDNSlocal mStatus UpdateLLQStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
3683 {
3684 mStatus status = mStatus_NoError;
3685 DNSQuestion* q, *worst_q = mDNSNULL;
3686 for (q = mDNSStorage.Questions; q; q=q->next)
3687 if (q->AuthInfo == info)
3688 {
3689 mStatus newStatus = CheckQuestionForStatus(q);
3690 if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
3691 else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; }
3692 else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
3693 }
3694
3695 if (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success");
3696 else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
3697 else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
3698 else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
3699 return status;
3700 }
3701
3702 mDNSlocal mStatus UpdateRRStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
3703 {
3704 AuthRecord *r;
3705
3706 if (info->deltime) return mStatus_NoError;
3707 for (r = mDNSStorage.ResourceRecords; r; r = r->next)
3708 {
3709 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
3710 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
3711 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
3712 // has already checked
3713 const domainname *n = r->resrec.name;
3714 while (n->c[0])
3715 {
3716 DomainAuthInfo *ptr;
3717 for (ptr = mDNSStorage.AuthInfoList; ptr; ptr = ptr->next)
3718 if (SameDomainName(&ptr->domain, n))
3719 {
3720 if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime))
3721 {
3722 mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
3723 return r->updateError;
3724 }
3725 }
3726 n = (const domainname *)(n->c + 1 + n->c[0]);
3727 }
3728 }
3729 return mStatus_NoError;
3730 }
3731
3732 #endif // ndef NO_SECURITYFRAMEWORK
3733
3734 // MUST be called with lock held
3735 mDNSlocal void UpdateAutoTunnelDomainStatus(const DomainAuthInfo *const info)
3736 {
3737 #ifdef NO_SECURITYFRAMEWORK
3738 (void)info;
3739 #else
3740 // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
3741 // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
3742 mDNS *const m = &mDNSStorage;
3743 const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL;
3744 const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL;
3745 char buffer[1024];
3746 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3747 CFStringRef domain = NULL;
3748 CFStringRef tmp = NULL;
3749 CFNumberRef num = NULL;
3750 mStatus status = mStatus_NoError;
3751 mStatus llqStatus = mStatus_NoError;
3752 char llqBuffer[1024];
3753
3754 mDNS_CheckLock(m);
3755
3756 if (!domainStatusDict)
3757 {
3758 domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3759 if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
3760 }
3761
3762 if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
3763
3764 mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c);
3765 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3766 if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3767
3768 if (info->deltime)
3769 {
3770 if (CFDictionaryContainsKey(domainStatusDict, domain))
3771 {
3772 CFDictionaryRemoveValue(domainStatusDict, domain);
3773 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3774 }
3775 CFRelease(domain);
3776 CFRelease(dict);
3777
3778 return;
3779 }
3780
3781 mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
3782 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3783 if (!tmp)
3784 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
3785 else
3786 {
3787 CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
3788 CFRelease(tmp);
3789 }
3790
3791 if (llq)
3792 {
3793 mDNSu32 port = mDNSVal16(llq->ExternalPort);
3794
3795 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3796 if (!num)
3797 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
3798 else
3799 {
3800 CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
3801 CFRelease(num);
3802 }
3803
3804 if (llq->Result)
3805 {
3806 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
3807 if (!num)
3808 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
3809 else
3810 {
3811 CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
3812 CFRelease(num);
3813 }
3814 }
3815 }
3816
3817 if (tun)
3818 {
3819 mDNSu32 port = mDNSVal16(tun->ExternalPort);
3820
3821 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3822 if (!num)
3823 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
3824 else
3825 {
3826 CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
3827 CFRelease(num);
3828 }
3829
3830 mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress);
3831 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3832 if (!tmp)
3833 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
3834 else
3835 {
3836 CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
3837 CFRelease(tmp);
3838 }
3839
3840 if (tun->Result)
3841 {
3842 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
3843 if (!num)
3844 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
3845 else
3846 {
3847 CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
3848 CFRelease(num);
3849 }
3850 }
3851 }
3852 if (tun || llq)
3853 {
3854 mDNSu32 code = m->LastNATMapResultCode;
3855
3856 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
3857 if (!num)
3858 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
3859 else
3860 {
3861 CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
3862 CFRelease(num);
3863 }
3864 }
3865
3866 mDNS_snprintf(buffer, sizeof(buffer), "Success");
3867 llqStatus = UpdateLLQStatus(llqBuffer, sizeof(llqBuffer), info);
3868 status = UpdateRRStatus(buffer, sizeof(buffer), info);
3869
3870 // If we have a bad signature error updating a RR, it overrides any error as it needs to be
3871 // reported so that it can be fixed automatically (or the user needs to be notified)
3872 if (status != mStatus_NoError)
3873 {
3874 LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer);
3875 }
3876 else if (m->Router.type == mDNSAddrType_None)
3877 {
3878 status = mStatus_NoRouter;
3879 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
3880 }
3881 else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
3882 {
3883 status = mStatus_NoRouter;
3884 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
3885 }
3886 else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress))
3887 {
3888 status = mStatus_ServiceNotRunning;
3889 mDNS_snprintf(buffer, sizeof(buffer), "No inner address");
3890 }
3891 else if (!llq && !tun)
3892 {
3893 status = mStatus_NotInitializedErr;
3894 mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
3895 }
3896 else if (llqStatus == mStatus_NoSuchRecord)
3897 {
3898 status = llqStatus;
3899 mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
3900 }
3901 else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
3902 {
3903 status = mStatus_DoubleNAT;
3904 mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address");
3905 }
3906 else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) ||
3907 (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
3908 (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
3909 {
3910 status = mStatus_NATPortMappingDisabled;
3911 mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router");
3912 }
3913 else if ((llq && llq->Result) || (tun && tun->Result))
3914 {
3915 status = mStatus_NATTraversal;
3916 mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
3917 }
3918 else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
3919 {
3920 status = mStatus_NATTraversal;
3921 mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
3922 }
3923 else
3924 {
3925 status = llqStatus;
3926 mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
3927 LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer);
3928 }
3929
3930 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
3931 if (!num)
3932 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
3933 else
3934 {
3935 CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
3936 CFRelease(num);
3937 }
3938
3939 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3940 if (!tmp)
3941 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
3942 else
3943 {
3944 CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
3945 CFRelease(tmp);
3946 }
3947
3948 if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
3949 !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
3950 {
3951 CFDictionarySetValue(domainStatusDict, domain, dict);
3952 if (!m->ShutdownTime)
3953 {
3954 LogInfo("UpdateAutoTunnelDomainStatus: %s status %d", status ? "failure" : "success", status);
3955 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3956 }
3957 }
3958
3959 CFRelease(domain);
3960 CFRelease(dict);
3961
3962 debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
3963 #endif // def NO_SECURITYFRAMEWORK
3964 }
3965
3966 // MUST be called with lock held
3967 mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
3968 {
3969 #ifdef NO_SECURITYFRAMEWORK
3970 (void) m;
3971 #else
3972 mDNS_CheckLock(m);
3973 DomainAuthInfo* info;
3974 for (info = m->AuthInfoList; info; info = info->next)
3975 if (info->AutoTunnel && !info->deltime)
3976 UpdateAutoTunnelDomainStatus(info);
3977 #endif // def NO_SECURITYFRAMEWORK
3978 }
3979
3980 mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we need racoon to accept incoming connections
3981 {
3982 DomainAuthInfo *info;
3983
3984 for (info = m->AuthInfoList; info; info = info->next)
3985 if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
3986 break;
3987
3988 if (info != AnonymousRacoonConfig)
3989 {
3990 AnonymousRacoonConfig = info;
3991 LogInfo("UpdateAnonymousRacoonConfig need not be done in mDNSResponder");
3992 }
3993 }
3994
3995 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
3996
3997 // Caller must hold the lock
3998 mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record)
3999 {
4000 mDNS_CheckLock(m);
4001
4002 LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c);
4003
4004 if (record->resrec.RecordType > kDNSRecordTypeDeregistering)
4005 {
4006 mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal);
4007 if (err)
4008 {
4009 record->resrec.RecordType = kDNSRecordTypeUnregistered;
4010 LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c);
4011 return mDNSfalse;
4012 }
4013 else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
4014 }
4015 else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType);
4016
4017 return mDNStrue;
4018 }
4019
4020 // Caller must hold the lock
4021 mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
4022 {
4023 if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord))
4024 {
4025 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
4026 m->NextSRVUpdate = NonZeroTime(m->timenow);
4027 }
4028 }
4029
4030 // Caller must hold the lock
4031 mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
4032 {
4033 mStatus err;
4034 mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result;
4035
4036 mDNS_CheckLock(m);
4037
4038 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem))
4039 {
4040 LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
4041 info->domain.c, info->AutoTunnelServiceStarted, info->deltime, &info->AutoTunnelInnerAddress, m->SleepState);
4042 DeregisterAutoTunnelHostRecord(m, info);
4043 }
4044 else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
4045 {
4046 mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
4047 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4048 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
4049 AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
4050 AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
4051 info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = info->AutoTunnelInnerAddress;
4052 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
4053
4054 err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
4055 if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c);
4056 else
4057 {
4058 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
4059 m->NextSRVUpdate = NonZeroTime(m->timenow);
4060 LogInfo("UpdateAutoTunnelHostRecord registering %##s", info->AutoTunnelHostRecord.namestorage.c);
4061 }
4062 }
4063 else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType);
4064 }
4065
4066 // Caller must hold the lock
4067 mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4068 {
4069 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
4070
4071 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget);
4072 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService);
4073 UpdateAutoTunnelHostRecord(m, info);
4074 }
4075
4076 // Caller must hold the lock
4077 mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4078 {
4079 mDNS_CheckLock(m);
4080
4081 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)
4082 {
4083 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);
4084 DeregisterAutoTunnelServiceRecords(m, info);
4085 }
4086 else
4087 {
4088 if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
4089 {
4090 // 1. Set up our address record for the external tunnel address
4091 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
4092 mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL,
4093 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4094 AssignDomainName (&info->AutoTunnelTarget.namestorage, (const domainname*) "\x0B" "_autotunnel");
4095 AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->hostlabel);
4096 AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
4097 info->AutoTunnelTarget.resrec.rdata->u.ipv4 = m->AutoTunnelNAT.ExternalAddress;
4098 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
4099
4100 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelTarget);
4101 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelTarget.namestorage.c);
4102 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelTarget.namestorage.c);
4103 }
4104 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType);
4105
4106 if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
4107 {
4108 // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
4109 mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL,
4110 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4111 AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4112 AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
4113 AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
4114 info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
4115 info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
4116 info->AutoTunnelService.resrec.rdata->u.srv.port = m->AutoTunnelNAT.ExternalPort;
4117 AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
4118 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
4119
4120 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelService);
4121 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelService.namestorage.c);
4122 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelService.namestorage.c);
4123 }
4124 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType);
4125
4126 UpdateAutoTunnelHostRecord(m, info);
4127
4128 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
4129 info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(m->AutoTunnelNAT.IntPort),
4130 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4131
4132 }
4133 }
4134
4135 // Caller must hold the lock
4136 mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4137 {
4138 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo);
4139 }
4140
4141 // Caller must hold the lock
4142 mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4143 {
4144 mDNS_CheckLock(m);
4145
4146 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime)
4147 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4148 else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
4149 {
4150 mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4151 ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
4152
4153 info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data);
4154 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
4155
4156 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
4157 if (err) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
4158 else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info->AutoTunnelDeviceInfo.namestorage.c);
4159 }
4160 else
4161 LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType);
4162 }
4163
4164 // Caller must hold the lock
4165 mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4166 {
4167 LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
4168
4169 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
4170 UpdateAutoTunnelHostRecord(m, info);
4171 UpdateAutoTunnelDomainStatus(info);
4172 }
4173
4174 // Caller must hold the lock
4175 mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4176 {
4177 mDNS_CheckLock(m);
4178
4179 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr) || m->SleepState != SleepState_Awake)
4180 DeregisterAutoTunnel6Record(m, info);
4181 else if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
4182 {
4183 mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
4184 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4185 AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
4186 AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
4187 AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
4188 info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr;
4189 info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
4190
4191 mStatus err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
4192 if (err) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err, info->AutoTunnel6Record.namestorage.c);
4193 else LogInfo("UpdateAutoTunnel6Record registering %##s", info->AutoTunnel6Record.namestorage.c);
4194
4195 UpdateAutoTunnelHostRecord(m, info);
4196
4197 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
4198 info->AutoTunnel6Record.namestorage.c, &m->AutoTunnelRelayAddr,
4199 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4200
4201 }
4202 else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType);
4203 }
4204
4205 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
4206 {
4207 DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
4208 if (result == mStatus_MemFree)
4209 {
4210 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
4211
4212 mDNS_Lock(m);
4213
4214 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
4215 if (rr == &info->AutoTunnelHostRecord)
4216 {
4217 rr->namestorage.c[0] = 0;
4218 m->NextSRVUpdate = NonZeroTime(m->timenow);
4219 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4220 }
4221 if (m->ShutdownTime)
4222 {
4223 LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
4224 mDNS_Unlock(m);
4225 return;
4226 }
4227 if (rr == &info->AutoTunnelHostRecord)
4228 {
4229 LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
4230 UpdateAutoTunnelHostRecord(m,info);
4231 }
4232 else if (rr == &info->AutoTunnelDeviceInfo)
4233 {
4234 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
4235 UpdateAutoTunnelDeviceInfoRecord(m,info);
4236 }
4237 else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
4238 {
4239 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
4240 UpdateAutoTunnelServiceRecords(m,info);
4241 }
4242 else if (rr == &info->AutoTunnel6Record)
4243 {
4244 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
4245 UpdateAutoTunnel6Record(m,info);
4246 }
4247
4248 mDNS_Unlock(m);
4249 }
4250 }
4251
4252 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
4253 {
4254 DomainAuthInfo *info;
4255
4256 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
4257 n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort));
4258
4259 mDNS_Lock(m);
4260
4261 m->NextSRVUpdate = NonZeroTime(m->timenow);
4262 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4263
4264 for (info = m->AuthInfoList; info; info = info->next)
4265 if (info->AutoTunnel)
4266 UpdateAutoTunnelServiceRecords(m, info);
4267
4268 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
4269
4270 UpdateAutoTunnelDomainStatuses(m);
4271
4272 mDNS_Unlock(m);
4273 }
4274
4275 mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
4276 {
4277 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
4278
4279 mDNS_Lock(m);
4280 // We forcibly deregister the records that are based on the hostname.
4281 // When deregistration of each completes, the MemFree callback will make the
4282 // appropriate Update* call to use the new name to reregister.
4283 DeregisterAutoTunnelHostRecord(m, info);
4284 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4285 DeregisterAutoTunnelServiceRecords(m, info);
4286 DeregisterAutoTunnel6Record(m, info);
4287 m->NextSRVUpdate = NonZeroTime(m->timenow);
4288 mDNS_Unlock(m);
4289 }
4290
4291 // Must be called with the lock held
4292 mDNSexport void StartServerTunnel(DomainAuthInfo *const info)
4293 {
4294 mDNS *const m = &mDNSStorage;
4295 if (info->deltime) return;
4296
4297 if (info->AutoTunnelServiceStarted)
4298 {
4299 // On wake from sleep, this function will be called when determining SRV targets,
4300 // and needs to re-register the host record for the target to be set correctly
4301 UpdateAutoTunnelHostRecord(m, info);
4302 return;
4303 }
4304
4305 info->AutoTunnelServiceStarted = mDNStrue;
4306
4307 // Now that we have a service in this domain, we need to try to register the
4308 // AutoTunnel records, because the relay connection & NAT-T may have already been
4309 // started for another domain. If the relay connection is not up or the NAT-T has not
4310 // yet succeeded, the Update* functions are smart enough to not register the records.
4311 // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
4312 // decide whether to register the AutoTunnel records in the calls below.
4313 UpdateAutoTunnelServiceRecords(m, info);
4314 UpdateAutoTunnel6Record(m, info);
4315 UpdateAutoTunnelDeviceInfoRecord(m, info);
4316 UpdateAutoTunnelHostRecord(m, info);
4317
4318 // If the global AutoTunnel NAT-T is not yet started, start it.
4319 if (!m->AutoTunnelNAT.clientContext)
4320 {
4321 m->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
4322 m->AutoTunnelNAT.clientContext = (void*)1; // Means AutoTunnelNAT Traversal is active;
4323 m->AutoTunnelNAT.Protocol = NATOp_MapUDP;
4324 m->AutoTunnelNAT.IntPort = IPSECPort;
4325 m->AutoTunnelNAT.RequestedPort = IPSECPort;
4326 m->AutoTunnelNAT.NATLease = 0;
4327 mStatus err = mDNS_StartNATOperation_internal(m, &m->AutoTunnelNAT);
4328 if (err) LogMsg("StartServerTunnel: error %d starting NAT mapping", err);
4329 }
4330 }
4331
4332 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
4333 {
4334 mDNSv6Addr loc_outer6;
4335 mDNSv6Addr rmt_outer6;
4336
4337 // When we are tunneling over IPv6 Relay address, the port number is zero
4338 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4339 {
4340 loc_outer6 = tun->loc_outer6;
4341 rmt_outer6 = tun->rmt_outer6;
4342 }
4343 else
4344 {
4345 loc_outer6 = zerov6Addr;
4346 loc_outer6.b[0] = tun->loc_outer.b[0];
4347 loc_outer6.b[1] = tun->loc_outer.b[1];
4348 loc_outer6.b[2] = tun->loc_outer.b[2];
4349 loc_outer6.b[3] = tun->loc_outer.b[3];
4350
4351 rmt_outer6 = zerov6Addr;
4352 rmt_outer6.b[0] = tun->rmt_outer.b[0];
4353 rmt_outer6.b[1] = tun->rmt_outer.b[1];
4354 rmt_outer6.b[2] = tun->rmt_outer.b[2];
4355 rmt_outer6.b[3] = tun->rmt_outer.b[3];
4356 }
4357
4358 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)));
4359 }
4360
4361 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
4362 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
4363
4364 mDNSlocal void ReissueBlockedQuestionWithType(domainname *d, mDNSBool success, mDNSu16 qtype)
4365 {
4366 mDNS *const m = &mDNSStorage;
4367 DNSQuestion *q = m->Questions;
4368 while (q)
4369 {
4370 if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
4371 {
4372 LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4373 mDNSQuestionCallback *tmp = q->QuestionCallback;
4374 q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
4375 mDNS_StopQuery(m, q);
4376 mDNS_StartQuery(m, q);
4377 q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
4378 if (!success) q->NoAnswer = NoAnswer_Fail;
4379 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
4380 // In general we have to assume that the question list might have changed in arbitrary ways.
4381 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
4382 // already in use. The safest solution is just to go back to the start of the list and start again.
4383 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
4384 // just one suspended question, so it's really a 2n algorithm.
4385 q = m->Questions;
4386 }
4387 else
4388 q = q->next;
4389 }
4390 }
4391
4392 mDNSlocal void ReissueBlockedQuestions(domainname *d, mDNSBool success)
4393 {
4394 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
4395 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
4396 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
4397 // 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.
4398 // 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.
4399 ReissueBlockedQuestionWithType(d, success, kDNSType_AAAA);
4400 ReissueBlockedQuestionWithType(d, mDNStrue, kDNSType_A);
4401 }
4402
4403 mDNSlocal void UnlinkAndReissueBlockedQuestions(ClientTunnel *tun, mDNSBool success)
4404 {
4405 mDNS *const m = &mDNSStorage;
4406 ClientTunnel **p = &m->TunnelClients;
4407 while (*p != tun && *p) p = &(*p)->next;
4408 if (*p) *p = tun->next;
4409 ReissueBlockedQuestions(&tun->dstname, success);
4410 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
4411 freeL("ClientTunnel", tun);
4412 }
4413
4414 mDNSlocal mDNSBool TunnelClientDeleteMatching(ClientTunnel *tun, mDNSBool v6Tunnel)
4415 {
4416 mDNS *const m = &mDNSStorage;
4417 ClientTunnel **p;
4418 mDNSBool needSetKeys = mDNStrue;
4419
4420 p = &tun->next;
4421 while (*p)
4422 {
4423 // Is this a tunnel to the same host that we are trying to setup now?
4424 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4425 else
4426 {
4427 ClientTunnel *old = *p;
4428 if (v6Tunnel)
4429 {
4430 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4431 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4432 if (old->q.ThisQInterval >= 0)
4433 {
4434 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4435 mDNS_StopQuery(m, &old->q);
4436 }
4437 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4438 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4439 !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
4440 !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
4441 {
4442 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4443 // the other parameters of the tunnel are different
4444 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4445 AutoTunnelSetKeys(old, mDNSfalse);
4446 }
4447 else
4448 {
4449 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4450 // as "tun" and "old" are identical
4451 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
4452 &old->rmt_inner);
4453 needSetKeys = mDNSfalse;
4454 }
4455 }
4456 else
4457 {
4458 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4459 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4460 if (old->q.ThisQInterval >= 0)
4461 {
4462 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4463 mDNS_StopQuery(m, &old->q);
4464 }
4465 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4466 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4467 !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
4468 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
4469 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
4470 {
4471 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4472 // the other parameters of the tunnel are different
4473 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4474 AutoTunnelSetKeys(old, mDNSfalse);
4475 }
4476 else
4477 {
4478 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4479 // as "tun" and "old" are identical
4480 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
4481 &old->rmt_inner);
4482 needSetKeys = mDNSfalse;
4483 }
4484 }
4485
4486 *p = old->next;
4487 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
4488 freeL("ClientTunnel", old);
4489 }
4490 }
4491 return needSetKeys;
4492 }
4493
4494 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
4495 // tunnel will be deleted
4496 mDNSlocal void TunnelClientDeleteAny(ClientTunnel *tun, mDNSBool v6Tunnel)
4497 {
4498 ClientTunnel **p;
4499
4500 p = &tun->next;
4501 while (*p)
4502 {
4503 // If there is more than one client tunnel to the same host, delete all of them.
4504 // We do this by just checking against the EUI64 rather than the full address
4505 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4506 else
4507 {
4508 ClientTunnel *old = *p;
4509 if (v6Tunnel)
4510 {
4511 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4512 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4513 }
4514 else
4515 {
4516 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4517 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4518 }
4519 if (old->q.ThisQInterval >= 0)
4520 {
4521 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4522 mDNS_StopQuery(&mDNSStorage, &old->q);
4523 }
4524 else
4525 {
4526 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4527 AutoTunnelSetKeys(old, mDNSfalse);
4528 }
4529 *p = old->next;
4530 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
4531 freeL("ClientTunnel", old);
4532 }
4533 }
4534 }
4535
4536 mDNSlocal void TunnelClientFinish(DNSQuestion *question, const ResourceRecord *const answer)
4537 {
4538 mDNS *const m = &mDNSStorage;
4539 mDNSBool needSetKeys = mDNStrue;
4540 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4541 mDNSBool v6Tunnel = mDNSfalse;
4542 DomainAuthInfo *info;
4543
4544 // If the port is zero, then we have a relay address of the peer
4545 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4546 v6Tunnel = mDNStrue;
4547
4548 if (v6Tunnel)
4549 {
4550 LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
4551 tun->rmt_outer6 = answer->rdata->u.ipv6;
4552 tun->loc_outer6 = m->AutoTunnelRelayAddr;
4553 }
4554 else
4555 {
4556 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
4557 tun->rmt_outer = answer->rdata->u.ipv4;
4558 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
4559 tmpDst.ip.v4 = tun->rmt_outer;
4560 mDNSAddr tmpSrc = zeroAddr;
4561 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
4562 if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
4563 else tun->loc_outer = m->AdvertisedV4.ip.v4;
4564 }
4565
4566 question->ThisQInterval = -1; // So we know this tunnel setup has completed
4567
4568 info = GetAuthInfoForName(m, &tun->dstname);
4569 if (!info)
4570 {
4571 LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
4572 ReissueBlockedQuestions(&tun->dstname, mDNSfalse);
4573 return;
4574 }
4575
4576 tun->loc_inner = info->AutoTunnelInnerAddress;
4577
4578 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
4579 // look for existing tunnels to see whether they have the same information for our peer.
4580 // If not, delete them and need to create a new tunnel. If they are same, just use the
4581 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
4582 TunnelClientDeleteAny(tun, !v6Tunnel);
4583 needSetKeys = TunnelClientDeleteMatching(tun, v6Tunnel);
4584
4585 if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
4586 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
4587
4588 mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
4589 LogInfo("TunnelClientFinish: Tunnel setup result %d", result);
4590 // Kick off any questions that were held pending this tunnel setup
4591 ReissueBlockedQuestions(&tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
4592 }
4593
4594 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
4595 {
4596 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4597 DomainAuthInfo *info;
4598
4599 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
4600
4601 if (!AddRecord) return;
4602 mDNS_StopQuery(m, question);
4603
4604 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
4605 // The code below will look for _autotunnel._udp SRV record followed by A record
4606 if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
4607 {
4608 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
4609 UnlinkAndReissueBlockedQuestions(tun, mDNSfalse);
4610 return;
4611 }
4612
4613 switch (tun->tc_state)
4614 {
4615 case TC_STATE_AAAA_PEER:
4616 if (question->qtype != kDNSType_AAAA)
4617 {
4618 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
4619 }
4620 info = GetAuthInfoForName(m, &tun->dstname);
4621 if (!info)
4622 {
4623 LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
4624 UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4625 return;
4626 }
4627 if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
4628 {
4629 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
4630 UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4631 return;
4632 }
4633 if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
4634 {
4635 LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6);
4636 UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4637 return;
4638 }
4639 tun->rmt_inner = answer->rdata->u.ipv6;
4640 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
4641 if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
4642 {
4643 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
4644 tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
4645 question->qtype = kDNSType_AAAA;
4646 AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
4647 }
4648 else
4649 {
4650 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
4651 tun->tc_state = TC_STATE_SRV_PEER;
4652 question->qtype = kDNSType_SRV;
4653 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4654 }
4655 AppendDomainName(&question->qname, &tun->dstname);
4656 mDNS_StartQuery(m, &tun->q);
4657 return;
4658 case TC_STATE_AAAA_PEER_RELAY:
4659 if (question->qtype != kDNSType_AAAA)
4660 {
4661 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
4662 }
4663 // If it failed, look for the SRV record.
4664 if (!answer->rdlength)
4665 {
4666 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
4667 tun->tc_state = TC_STATE_SRV_PEER;
4668 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4669 AppendDomainName(&question->qname, &tun->dstname);
4670 question->qtype = kDNSType_SRV;
4671 mDNS_StartQuery(m, &tun->q);
4672 return;
4673 }
4674 TunnelClientFinish(question, answer);
4675 return;
4676 case TC_STATE_SRV_PEER:
4677 if (question->qtype != kDNSType_SRV)
4678 {
4679 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
4680 }
4681 LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
4682 tun->tc_state = TC_STATE_ADDR_PEER;
4683 AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
4684 tun->rmt_outer_port = answer->rdata->u.srv.port;
4685 question->qtype = kDNSType_A;
4686 mDNS_StartQuery(m, &tun->q);
4687 return;
4688 case TC_STATE_ADDR_PEER:
4689 if (question->qtype != kDNSType_A)
4690 {
4691 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
4692 }
4693 TunnelClientFinish(question, answer);
4694 return;
4695 default:
4696 LogMsg("AutoTunnelCallback: Unknown question %p", question);
4697 }
4698 }
4699
4700 // Must be called with the lock held
4701 mDNSexport void AddNewClientTunnel(DNSQuestion *const q)
4702 {
4703 mDNS *const m = &mDNSStorage;
4704 ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
4705 if (!p) return;
4706 AssignDomainName(&p->dstname, &q->qname);
4707 p->MarkedForDeletion = mDNSfalse;
4708 p->loc_inner = zerov6Addr;
4709 p->loc_outer = zerov4Addr;
4710 p->loc_outer6 = zerov6Addr;
4711 p->rmt_inner = zerov6Addr;
4712 p->rmt_outer = zerov4Addr;
4713 p->rmt_outer6 = zerov6Addr;
4714 p->rmt_outer_port = zeroIPPort;
4715 p->tc_state = TC_STATE_AAAA_PEER;
4716 p->next = m->TunnelClients;
4717 m->TunnelClients = p; // We intentionally build list in reverse order
4718
4719 p->q.InterfaceID = mDNSInterface_Any;
4720 p->q.flags = 0;
4721 p->q.Target = zeroAddr;
4722 AssignDomainName(&p->q.qname, &q->qname);
4723 p->q.qtype = kDNSType_AAAA;
4724 p->q.qclass = kDNSClass_IN;
4725 p->q.LongLived = mDNSfalse;
4726 p->q.ExpectUnique = mDNStrue;
4727 p->q.ForceMCast = mDNSfalse;
4728 p->q.ReturnIntermed = mDNStrue;
4729 p->q.SuppressUnusable = mDNSfalse;
4730 p->q.SearchListIndex = 0;
4731 p->q.AppendSearchDomains = 0;
4732 p->q.RetryWithSearchDomains = mDNSfalse;
4733 p->q.TimeoutQuestion = 0;
4734 p->q.WakeOnResolve = 0;
4735 p->q.UseBackgroundTrafficClass = mDNSfalse;
4736 p->q.ValidationRequired = 0;
4737 p->q.ValidatingResponse = 0;
4738 p->q.ProxyQuestion = 0;
4739 p->q.qnameOrig = mDNSNULL;
4740 p->q.AnonInfo = mDNSNULL;
4741 p->q.pid = mDNSPlatformGetPID();
4742 p->q.euid = 0;
4743 p->q.QuestionCallback = AutoTunnelCallback;
4744 p->q.QuestionContext = p;
4745
4746 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
4747 mDNS_StartQuery_internal(m, &p->q);
4748 }
4749
4750 #endif // APPLE_OSX_mDNSResponder
4751
4752 #if COMPILER_LIKES_PRAGMA_MARK
4753 #pragma mark -
4754 #pragma mark - Power State & Configuration Change Management
4755 #endif
4756
4757 mDNSlocal mStatus ReorderInterfaceList()
4758 {
4759 // Disable Reorder lists till <rdar://problem/30071012> is fixed to prevent spurious name conflicts
4760 return (mStatus_NoError);
4761
4762 mDNS *const m = &mDNSStorage;
4763 nwi_state_t state = nwi_state_copy();
4764
4765 if (state == mDNSNULL)
4766 {
4767 LogMsg("NWI State is NULL!");
4768 return (mStatus_Invalid);
4769 }
4770
4771 // Get the count of interfaces
4772 mDNSu32 count = nwi_state_get_interface_names(state, mDNSNULL, 0);
4773 if (count == 0)
4774 {
4775 LogMsg("Unable to get the ordered list of interface names");
4776 nwi_state_release(state);
4777 return (mStatus_Invalid);
4778 }
4779
4780 // Get the ordered interface list
4781 int i;
4782 const char *names[count];
4783 count = nwi_state_get_interface_names(state, names, count);
4784
4785 NetworkInterfaceInfo *newList = mDNSNULL;
4786 for (i = count-1; i >= 0; i--)
4787 { // Build a new ordered interface list
4788 NetworkInterfaceInfo **ptr = &m->HostInterfaces;
4789 while (*ptr != mDNSNULL )
4790 {
4791 if (strcmp((*ptr)->ifname, names[i]) == 0)
4792 {
4793 NetworkInterfaceInfo *node = *ptr;
4794 *ptr = (*ptr)->next;
4795 node->next = newList;
4796 newList = node;
4797 }
4798 else
4799 ptr = &((*ptr)->next);
4800 }
4801 }
4802
4803 // Get to the end of the list
4804 NetworkInterfaceInfo *newListEnd = newList;
4805 while (newListEnd != mDNSNULL && newListEnd->next != mDNSNULL)
4806 newListEnd = newListEnd->next;
4807
4808 // Add any remaing interfaces to the end of the sorted list
4809 if (newListEnd != mDNSNULL)
4810 newListEnd->next = m->HostInterfaces;
4811
4812 // If we have a valid new list, point to that now
4813 if (newList != mDNSNULL)
4814 m->HostInterfaces = newList;
4815
4816 nwi_state_release(state);
4817 return (mStatus_NoError);
4818 }
4819
4820 mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
4821 {
4822 mDNS *const m = &mDNSStorage;
4823 mDNSBool foundav4 = mDNSfalse;
4824 mDNSBool foundav6 = mDNSfalse;
4825 struct ifaddrs *ifa = myGetIfAddrs(0);
4826 struct ifaddrs *v4Loopback = NULL;
4827 struct ifaddrs *v6Loopback = NULL;
4828 char defaultname[64];
4829 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
4830 if (InfoSocket < 3 && errno != EAFNOSUPPORT)
4831 LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
4832
4833 if (m->SleepState == SleepState_Sleeping) ifa = NULL;
4834
4835 while (ifa)
4836 {
4837 #if LIST_ALL_INTERFACES
4838 if (ifa->ifa_addr)
4839 {
4840 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
4841 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
4842 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4843 else if (ifa->ifa_addr->sa_family == AF_LINK)
4844 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
4845 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4846 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
4847 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
4848 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4849 }
4850 else
4851 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X ifa_addr is NOT set",
4852 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags);
4853
4854 if (!(ifa->ifa_flags & IFF_UP))
4855 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
4856 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4857 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4858 if (!(ifa->ifa_flags & IFF_MULTICAST))
4859 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
4860 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4861 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4862 if (ifa->ifa_flags & IFF_POINTOPOINT)
4863 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
4864 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4865 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4866 if (ifa->ifa_flags & IFF_LOOPBACK)
4867 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
4868 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4869 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4870 #endif
4871
4872 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
4873 {
4874 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
4875 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
4876 mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
4877 }
4878
4879 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr && !isCoprocessorInterface(InfoSocket, ifa->ifa_name))
4880 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
4881 {
4882 if (!ifa->ifa_netmask)
4883 {
4884 mDNSAddr ip;
4885 SetupAddr(&ip, ifa->ifa_addr);
4886 LogMsg("UpdateInterfaceList: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
4887 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
4888 }
4889 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
4890 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4891 else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0)
4892 {
4893 mDNSAddr ip;
4894 SetupAddr(&ip, ifa->ifa_addr);
4895 LogMsg("UpdateInterfaceList: ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
4896 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
4897 }
4898 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
4899 else if ((int)if_nametoindex(ifa->ifa_name) <= 0)
4900 {
4901 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
4902 }
4903 else
4904 {
4905 // Make sure ifa_netmask->sa_family is set correctly
4906 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4907 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
4908 int ifru_flags6 = 0;
4909
4910 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
4911 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
4912 {
4913 struct in6_ifreq ifr6;
4914 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
4915 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
4916 ifr6.ifr_addr = *sin6;
4917 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
4918 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
4919 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
4920 }
4921
4922 if (!(ifru_flags6 & (IN6_IFF_TENTATIVE | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
4923 {
4924 if (ifa->ifa_flags & IFF_LOOPBACK)
4925 {
4926 if (ifa->ifa_addr->sa_family == AF_INET)
4927 v4Loopback = ifa;
4928 else if (sin6->sin6_addr.s6_addr[0] != 0xFD)
4929 v6Loopback = ifa;
4930 }
4931 else
4932 {
4933 NetworkInterfaceInfoOSX *i = AddInterfaceToList(ifa, utc);
4934 if (i && MulticastInterface(i) && i->ifinfo.Advertise)
4935 {
4936 if (ifa->ifa_addr->sa_family == AF_INET)
4937 foundav4 = mDNStrue;
4938 else
4939 foundav6 = mDNStrue;
4940 }
4941 }
4942 }
4943 }
4944 }
4945 ifa = ifa->ifa_next;
4946 }
4947
4948 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
4949 if (!foundav4 && v4Loopback) AddInterfaceToList(v4Loopback, utc);
4950 if (!foundav6 && v6Loopback) AddInterfaceToList(v6Loopback, utc);
4951
4952 if (InfoSocket >= 0)
4953 close(InfoSocket);
4954
4955 mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
4956 m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
4957
4958 // Set up the nice label
4959 domainlabel nicelabel;
4960 nicelabel.c[0] = 0;
4961 GetUserSpecifiedFriendlyComputerName(&nicelabel);
4962 if (nicelabel.c[0] == 0)
4963 {
4964 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
4965 MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
4966 }
4967
4968 // Set up the RFC 1034-compliant label
4969 domainlabel hostlabel;
4970 hostlabel.c[0] = 0;
4971 GetUserSpecifiedLocalHostName(&hostlabel);
4972 if (hostlabel.c[0] == 0)
4973 {
4974 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
4975 MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
4976 }
4977
4978 mDNSBool namechange = mDNSfalse;
4979
4980 // We use a case-sensitive comparison here because even though changing the capitalization
4981 // of the name alone is not significant to DNS, it's still a change from the user's point of view
4982 if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
4983 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
4984 else
4985 {
4986 if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
4987 LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
4988 m->p->usernicelabel = m->nicelabel = nicelabel;
4989 namechange = mDNStrue;
4990 }
4991
4992 if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
4993 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
4994 else
4995 {
4996 if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
4997 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
4998 m->p->userhostlabel = m->hostlabel = hostlabel;
4999 mDNS_SetFQDN(m);
5000 namechange = mDNStrue;
5001 }
5002
5003 if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
5004 {
5005 #if APPLE_OSX_mDNSResponder
5006 DomainAuthInfo *info;
5007 for (info = m->AuthInfoList; info; info = info->next)
5008 if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
5009 #endif // APPLE_OSX_mDNSResponder
5010 }
5011
5012 return(mStatus_NoError);
5013 }
5014
5015 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
5016 // Returns -1 if all the one-bits are not contiguous
5017 mDNSlocal int CountMaskBits(mDNSAddr *mask)
5018 {
5019 int i = 0, bits = 0;
5020 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
5021 while (i < bytes)
5022 {
5023 mDNSu8 b = mask->ip.v6.b[i++];
5024 while (b & 0x80) { bits++; b <<= 1; }
5025 if (b) return(-1);
5026 }
5027 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
5028 return(bits);
5029 }
5030
5031 // Returns count of non-link local V4 addresses registered (why? -- SC)
5032 mDNSlocal int SetupActiveInterfaces(mDNSs32 utc)
5033 {
5034 mDNS *const m = &mDNSStorage;
5035 NetworkInterfaceInfoOSX *i;
5036 int count = 0;
5037
5038 // Recalculate SuppressProbes time based on the current set of active interfaces.
5039 m->SuppressProbes = 0;
5040 for (i = m->p->InterfaceList; i; i = i->next)
5041 if (i->Exists)
5042 {
5043 NetworkInterfaceInfo *const n = &i->ifinfo;
5044 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
5045 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
5046
5047 if (i->Registered && i->Registered != primary) // Sanity check
5048 {
5049 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
5050 i->Registered = mDNSNULL;
5051 }
5052
5053 if (!i->Registered)
5054 {
5055 InterfaceActivationSpeed activationSpeed;
5056
5057 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5058 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5059 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it.
5060 i->Registered = primary;
5061
5062 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
5063 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
5064 // 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.
5065 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
5066
5067 // The "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
5068 // every time a new interface is created. We think it is a duplicate and hence consider it
5069 // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
5070 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
5071 // logs a warning message to system.log noting frequent interface transitions.
5072 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
5073 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
5074 {
5075 activationSpeed = FastActivation;
5076 LogInfo("SetupActiveInterfaces: %s DirectLink interface registering", i->ifinfo.ifname);
5077 }
5078 else if (i->Flashing && i->Occulting)
5079 {
5080 activationSpeed = SlowActivation;
5081 }
5082 else
5083 {
5084 activationSpeed = NormalActivation;
5085 }
5086
5087 mDNS_RegisterInterface(m, n, activationSpeed);
5088
5089 if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
5090 LogInfo("SetupActiveInterfaces: Registered %7s(%u) BSSID %.6a Struct addr %p, primary %p, %#a/%d%s%s%s",
5091 i->ifinfo.ifname, i->scope_id, &i->BSSID, i, primary, &n->ip, CountMaskBits(&n->mask),
5092 i->Flashing ? " (Flashing)" : "",
5093 i->Occulting ? " (Occulting)" : "",
5094 n->InterfaceActive ? " (Primary)" : "");
5095
5096 if (!n->McastTxRx)
5097 {
5098 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);
5099 #if TARGET_OS_EMBEDDED
5100 // We join the Bonjour multicast group on Apple embedded platforms ONLY when a client request is active,
5101 // so we leave the multicast group here to clear any residual group membership.
5102 if (i->sa_family == AF_INET)
5103 {
5104 struct ip_mreq imr;
5105 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
5106 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
5107 imr.imr_interface = primary->ifa_v4addr;
5108
5109 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET) == i)
5110 {
5111 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
5112 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
5113 if (err < 0 && (errno != EADDRNOTAVAIL))
5114 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
5115 }
5116 }
5117 if (i->sa_family == AF_INET6)
5118 {
5119 struct ipv6_mreq i6mr;
5120 i6mr.ipv6mr_interface = primary->scope_id;
5121 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
5122
5123 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET6) == i)
5124 {
5125 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IPV6_LEAVE_GROUP for %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5126 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
5127 if (err < 0 && (errno != EADDRNOTAVAIL))
5128 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5129 }
5130 }
5131 #endif // TARGET_OS_EMBEDDED
5132 }
5133 else
5134 {
5135 if (i->sa_family == AF_INET)
5136 {
5137 struct ip_mreq imr;
5138 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
5139 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
5140 imr.imr_interface = primary->ifa_v4addr;
5141
5142 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
5143 // before trying to join the group, to clear out stale kernel state which may be lingering.
5144 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
5145 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
5146 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
5147 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
5148 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
5149 // because by the time we get the configuration change notification, the interface is already gone,
5150 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
5151 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
5152 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET) == i)
5153 {
5154 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);
5155 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
5156 if (err < 0 && (errno != EADDRNOTAVAIL))
5157 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
5158 }
5159
5160 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
5161 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
5162 // Joining same group twice can give "Address already in use" error -- no need to report that
5163 if (err < 0 && (errno != EADDRINUSE))
5164 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
5165 }
5166 if (i->sa_family == AF_INET6)
5167 {
5168 struct ipv6_mreq i6mr;
5169 i6mr.ipv6mr_interface = primary->scope_id;
5170 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
5171
5172 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET6) == i)
5173 {
5174 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);
5175 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
5176 if (err < 0 && (errno != EADDRNOTAVAIL))
5177 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5178 }
5179
5180 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5181 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
5182 // Joining same group twice can give "Address already in use" error -- no need to report that
5183 if (err < 0 && (errno != EADDRINUSE))
5184 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5185 }
5186 }
5187 }
5188 }
5189
5190 return count;
5191 }
5192
5193 mDNSlocal void MarkAllInterfacesInactive(mDNSs32 utc)
5194 {
5195 NetworkInterfaceInfoOSX *i;
5196 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
5197 {
5198 if (i->Exists) i->LastSeen = utc;
5199 i->Exists = mDNSfalse;
5200 }
5201 }
5202
5203 // Returns count of non-link local V4 addresses deregistered (why? -- SC)
5204 mDNSlocal int ClearInactiveInterfaces(mDNSs32 utc)
5205 {
5206 mDNS *const m = &mDNSStorage;
5207 // First pass:
5208 // If an interface is going away, then deregister this from the mDNSCore.
5209 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
5210 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
5211 // it refers to has gone away we'll crash.
5212 NetworkInterfaceInfoOSX *i;
5213 int count = 0;
5214 for (i = m->p->InterfaceList; i; i = i->next)
5215 {
5216 // If this interface is no longer active, or its InterfaceID is changing, deregister it
5217 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
5218 if (i->Registered)
5219 if (i->Exists == 0 || i->Exists == MulticastStateChanged || i->Registered != primary)
5220 {
5221 InterfaceActivationSpeed activationSpeed;
5222
5223 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
5224 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5225 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary,
5226 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
5227 i->Flashing ? " (Flashing)" : "",
5228 i->Occulting ? " (Occulting)" : "",
5229 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5230
5231 // "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
5232 // every time it creates a new interface. We think it is a duplicate and hence consider it
5233 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
5234 // stale data returned to the application even after the interface is removed. The application
5235 // then starts to send data but the new interface is not yet created.
5236 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
5237 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
5238 {
5239 activationSpeed = FastActivation;
5240 LogInfo("ClearInactiveInterfaces: %s DirectLink interface deregistering", i->ifinfo.ifname);
5241 }
5242 else if (i->Flashing && i->Occulting)
5243 {
5244 activationSpeed = SlowActivation;
5245 }
5246 else
5247 {
5248 activationSpeed = NormalActivation;
5249 }
5250 mDNS_DeregisterInterface(m, &i->ifinfo, activationSpeed);
5251
5252 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
5253 i->Registered = mDNSNULL;
5254 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5255 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5256 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
5257
5258 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
5259 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
5260 }
5261 }
5262
5263 // Second pass:
5264 // Now that everything that's going to deregister has done so, we can clean up and free the memory
5265 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
5266 while (*p)
5267 {
5268 i = *p;
5269 // If no longer active, delete interface from list and free memory
5270 if (!i->Exists)
5271 {
5272 if (i->LastSeen == utc) i->LastSeen = utc - 1;
5273 const mDNSBool delete = (i->isAWDL || (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0)) && (utc - i->LastSeen >= 60);
5274 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
5275 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
5276 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
5277 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5278 #if APPLE_OSX_mDNSResponder
5279 if (i->BPF_fd >= 0) CloseBPF(i);
5280 #endif // APPLE_OSX_mDNSResponder
5281 if (delete)
5282 {
5283 *p = i->next;
5284 freeL("NetworkInterfaceInfoOSX", i);
5285 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
5286 }
5287 }
5288 p = &i->next;
5289 }
5290 return count;
5291 }
5292
5293 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
5294 {
5295 DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
5296 if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
5297 else
5298 {
5299 dnle->next = mDNSNULL;
5300 dnle->uid = uid;
5301 AssignDomainName(&dnle->name, name);
5302 **List = dnle;
5303 *List = &dnle->next;
5304 }
5305 }
5306
5307 mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
5308 {
5309 dns_resolver_t *a = *(dns_resolver_t**)aa;
5310 dns_resolver_t *b = *(dns_resolver_t**)bb;
5311
5312 return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
5313 }
5314
5315 mDNSlocal void UpdateSearchDomainHash(MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID)
5316 {
5317 mDNS *const m = &mDNSStorage;
5318 char *buf = ".";
5319 mDNSu32 scopeid = 0;
5320 char ifid_buf[16];
5321
5322 if (domain)
5323 buf = domain;
5324 //
5325 // Hash the search domain name followed by the InterfaceID.
5326 // As we have scoped search domains, we also included InterfaceID. If either of them change,
5327 // we will detect it. Even if the order of them change, we will detect it.
5328 //
5329 // Note: We have to handle a few of these tricky cases.
5330 //
5331 // 1) Current: com, apple.com Changing to: comapple.com
5332 // 2) Current: a.com,b.com Changing to a.comb.com
5333 // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
5334 // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
5335 //
5336 // There are more variants of the above. The key thing is if we include the null in each case
5337 // at the end of name and the InterfaceID, it will prevent a new name (which can't include
5338 // NULL as part of the name) to be mistakenly thought of as a old name.
5339
5340 scopeid = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
5341 // mDNS_snprintf always null terminates
5342 if (mDNS_snprintf(ifid_buf, sizeof(ifid_buf), "%u", scopeid) >= sizeof(ifid_buf))
5343 LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid);
5344
5345 LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf, ifid_buf);
5346 MD5_Update(sdc, buf, strlen(buf) + 1);
5347 MD5_Update(sdc, ifid_buf, strlen(ifid_buf) + 1);
5348 }
5349
5350 mDNSlocal void FinalizeSearchDomainHash(MD5_CTX *sdc)
5351 {
5352 mDNS *const m = &mDNSStorage;
5353 mDNSu8 md5_hash[MD5_LEN];
5354
5355 MD5_Final(md5_hash, sdc);
5356
5357 if (memcmp(md5_hash, m->SearchDomainsHash, MD5_LEN))
5358 {
5359 // If the hash is different, either the search domains have changed or
5360 // the ordering between them has changed. Restart the questions that
5361 // would be affected by this.
5362 LogInfo("FinalizeSearchDomains: The hash is different");
5363 memcpy(m->SearchDomainsHash, md5_hash, MD5_LEN);
5364 RetrySearchDomainQuestions(m);
5365 }
5366 else { LogInfo("FinalizeSearchDomains: The hash is same"); }
5367 }
5368
5369 mDNSexport const char *DNSScopeToString(mDNSu32 scope)
5370 {
5371 switch (scope)
5372 {
5373 case kScopeNone:
5374 return "Unscoped";
5375 case kScopeInterfaceID:
5376 return "InterfaceScoped";
5377 case kScopeServiceID:
5378 return "ServiceScoped";
5379 default:
5380 return "Unknown";
5381 }
5382 }
5383
5384 mDNSlocal void ConfigSearchDomains(dns_resolver_t *resolver, mDNSInterfaceID interfaceId, mDNSu32 scope, MD5_CTX *sdc, uint64_t generation)
5385 {
5386 const char *scopeString = DNSScopeToString(scope);
5387 int j;
5388 domainname d;
5389
5390 if (scope == kScopeNone)
5391 interfaceId = mDNSInterface_Any;
5392
5393 if (scope == kScopeNone || scope == kScopeInterfaceID)
5394 {
5395 for (j = 0; j < resolver->n_search; j++)
5396 {
5397 if (MakeDomainNameFromDNSNameString(&d, resolver->search[j]) != NULL)
5398 {
5399 static char interface_buf[32];
5400 mDNS_snprintf(interface_buf, sizeof(interface_buf), "for interface %s", InterfaceNameForID(&mDNSStorage, interfaceId));
5401 LogInfo("ConfigSearchDomains: (%s) configuring search domain %s %s (generation= %llu)", scopeString,
5402 resolver->search[j], (interfaceId == mDNSInterface_Any) ? "" : interface_buf, generation);
5403 UpdateSearchDomainHash(sdc, resolver->search[j], interfaceId);
5404 mDNS_AddSearchDomain_CString(resolver->search[j], interfaceId);
5405 }
5406 else
5407 {
5408 LogInfo("ConfigSearchDomains: An invalid search domain was detected for %s domain %s n_nameserver %d, (generation= %llu)",
5409 DNSScopeToString(scope), resolver->domain, resolver->n_nameserver, generation);
5410 }
5411 }
5412 }
5413 else
5414 {
5415 LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString, InterfaceNameForID(&mDNSStorage, interfaceId));
5416 }
5417 }
5418
5419 mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNSu32 ifindex)
5420 {
5421 NetworkInterfaceInfoOSX *ni;
5422 mDNSInterfaceID interface;
5423
5424 for (ni = mDNSStorage.p->InterfaceList; ni; ni = ni->next)
5425 {
5426 if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex)
5427 break;
5428 }
5429 if (ni != NULL)
5430 {
5431 interface = ni->ifinfo.InterfaceID;
5432 }
5433 else
5434 {
5435 // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
5436 // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
5437 // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
5438 // As the caller is going to ack the configuration always, we have to add all the DNS servers
5439 // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
5440
5441 LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex);
5442
5443 // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
5444 interface = (mDNSInterfaceID)(unsigned long)ifindex;
5445 }
5446 return interface;
5447 }
5448
5449 mDNSlocal void ConfigNonUnicastResolver(dns_resolver_t *r)
5450 {
5451 char *opt = r->options;
5452 domainname d;
5453
5454 if (opt && !strncmp(opt, "mdns", strlen(opt)))
5455 {
5456 if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5457 {
5458 LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain);
5459 return;
5460 }
5461 mDNS_AddMcastResolver(&mDNSStorage, &d, mDNSInterface_Any, r->timeout);
5462 }
5463 }
5464
5465 mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID)
5466 {
5467 int n;
5468 domainname d;
5469 int serviceID = 0;
5470 mDNSBool cellIntf = mDNSfalse;
5471 mDNSBool reqA, reqAAAA;
5472 NetworkInterfaceInfoOSX *info;
5473 mDNSBool isExpensive;
5474 mDNSBool isCLAT46;
5475
5476 if (!r->domain || !*r->domain)
5477 {
5478 d.c[0] = 0;
5479 }
5480 else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5481 {
5482 LogMsg("ConfigDNSServers: bad domain %s", r->domain);
5483 return;
5484 }
5485 // Parse the resolver specific attributes that affects all the DNS servers.
5486 if (scope == kScopeServiceID)
5487 {
5488 serviceID = r->service_identifier;
5489 }
5490
5491 #if TARGET_OS_IPHONE
5492 cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
5493 #endif
5494 reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse);
5495 reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
5496 info = IfindexToInterfaceInfoOSX(interface);
5497 isExpensive = (info && info->isExpensive) ? mDNStrue : mDNSfalse;
5498 isCLAT46 = (info && info->isCLAT46) ? mDNStrue : mDNSfalse;
5499
5500 for (n = 0; n < r->n_nameserver; n++)
5501 {
5502 mDNSAddr saddr;
5503 DNSServer *s;
5504
5505 if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6)
5506 continue;
5507
5508 if (SetupAddr(&saddr, r->nameserver[n]))
5509 {
5510 LogMsg("ConfigDNSServers: Bad address");
5511 continue;
5512 }
5513
5514 // The timeout value is for all the DNS servers in a given resolver, hence we pass
5515 // the timeout value only for the first DNSServer. If we don't have a value in the
5516 // resolver, then use the core's default value
5517 //
5518 // Note: this assumes that when the core picks a list of DNSServers for a question,
5519 // it takes the sum of all the timeout values for all DNS servers. By doing this, it
5520 // tries all the DNS servers in a specified timeout
5521 s = mDNS_AddDNSServer(&mDNSStorage, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope,
5522 (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, isExpensive, isCLAT46,
5523 resGroupID, reqA, reqAAAA, mDNStrue);
5524 if (s)
5525 {
5526 LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c);
5527 }
5528 }
5529 }
5530
5531 // ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
5532 // Service scope resolvers. This is indicated by the scope argument.
5533 //
5534 // "resolver" has entries that should only be used for unscoped questions.
5535 //
5536 // "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
5537 // interface index (q->InterfaceID)
5538 //
5539 // "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
5540 // a service identifier (q->ServiceID)
5541 //
5542 mDNSlocal void ConfigResolvers(dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc, mDNSu16 resGroupID)
5543 {
5544 int i;
5545 dns_resolver_t **resolver;
5546 int nresolvers;
5547 const char *scopeString = DNSScopeToString(scope);
5548 mDNSInterfaceID interface;
5549
5550 switch (scope)
5551 {
5552 case kScopeNone:
5553 resolver = config->resolver;
5554 nresolvers = config->n_resolver;
5555 break;
5556 case kScopeInterfaceID:
5557 resolver = config->scoped_resolver;
5558 nresolvers = config->n_scoped_resolver;
5559 break;
5560 case kScopeServiceID:
5561 resolver = config->service_specific_resolver;
5562 nresolvers = config->n_service_specific_resolver;
5563 break;
5564 default:
5565 return;
5566 }
5567 qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
5568
5569 for (i = 0; i < nresolvers; i++)
5570 {
5571 dns_resolver_t *r = resolver[i];
5572
5573 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString, i, r->domain, r->n_nameserver);
5574
5575 interface = mDNSInterface_Any;
5576
5577 // Parse the interface index
5578 if (r->if_index != 0)
5579 {
5580 interface = ConfigParseInterfaceID(r->if_index);
5581 }
5582
5583 if (setsearch)
5584 {
5585 ConfigSearchDomains(resolver[i], interface, scope, sdc, config->generation);
5586
5587 // Parse other scoped resolvers for search lists
5588 if (!setservers)
5589 continue;
5590 }
5591
5592 if (r->port == 5353 || r->n_nameserver == 0)
5593 {
5594 ConfigNonUnicastResolver(r);
5595 }
5596 else
5597 {
5598 // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the
5599 // scoped resolver are not used by other non-scoped or scoped resolvers.
5600 if (scope != kScopeNone)
5601 resGroupID++;
5602
5603 ConfigDNSServers(r, interface, scope, resGroupID);
5604 }
5605 }
5606 }
5607
5608 #if APPLE_OSX_mDNSResponder
5609 mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
5610 {
5611 if (QuerySuppressed(q))
5612 {
5613 debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5614 return mDNSfalse;
5615 }
5616 if (mDNSOpaque16IsZero(q->TargetQID))
5617 {
5618 debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5619 return mDNSfalse;
5620 }
5621 // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
5622 // for trigger.
5623 if (q->LOAddressAnswers)
5624 {
5625 debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5626 return mDNSfalse;
5627 }
5628 return mDNStrue;
5629 }
5630 #endif
5631
5632 // This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
5633 // We set our state appropriately so that if we start receiving answers, trigger the
5634 // upper layer to retry DNS questions.
5635 #if APPLE_OSX_mDNSResponder
5636 mDNSexport void mDNSPlatformUpdateDNSStatus(DNSQuestion *q)
5637 {
5638 mDNS *const m = &mDNSStorage;
5639 if (!QuestionValidForDNSTrigger(q))
5640 return;
5641
5642 // Ignore applications that start and stop queries for no reason before we ever talk
5643 // to any DNS server.
5644 if (!q->triedAllServersOnce)
5645 {
5646 LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q->qname.c, DNSTypeName(q->qtype));
5647 return;
5648 }
5649 if (q->qtype == kDNSType_A)
5650 m->p->v4answers = 0;
5651 if (q->qtype == kDNSType_AAAA)
5652 m->p->v6answers = 0;
5653 if (!m->p->v4answers || !m->p->v6answers)
5654 {
5655 LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, question %##s (%s)", m->p->v4answers, m->p->v6answers, q->qname.c,
5656 DNSTypeName(q->qtype));
5657 }
5658 }
5659 #endif
5660
5661 mDNSlocal void AckConfigd(dns_config_t *config)
5662 {
5663 mDNS_CheckLock(&mDNSStorage);
5664
5665 // Acking the configuration triggers configd to reissue the reachability queries
5666 mDNSStorage.p->DNSTrigger = NonZeroTime(mDNSStorage.timenow);
5667 _dns_configuration_ack(config, "com.apple.mDNSResponder");
5668 }
5669
5670 // If v4q is non-NULL, it means we have received some answers for "A" type questions
5671 // If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
5672 #if APPLE_OSX_mDNSResponder
5673 mDNSexport void mDNSPlatformTriggerDNSRetry(DNSQuestion *v4q, DNSQuestion *v6q)
5674 {
5675 mDNS *const m = &mDNSStorage;
5676 mDNSBool trigger = mDNSfalse;
5677 mDNSs32 timenow;
5678
5679 // Don't send triggers too often.
5680 // If we have started delivering answers to questions, we should send a trigger
5681 // if the time permits. If we are delivering answers, we should set the state
5682 // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know
5683 // whether the answers that are being delivered currently is for configd or some
5684 // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
5685 // then we won't deliver the trigger later when it is okay to send one as the
5686 // "answers" are already set to 1. Hence, don't affect the state of v4answers and
5687 // v6answers if we are not delivering triggers.
5688 mDNS_Lock(m);
5689 timenow = m->timenow;
5690 if (m->p->DNSTrigger && (timenow - m->p->DNSTrigger) < DNS_TRIGGER_INTERVAL)
5691 {
5692 if (!m->p->v4answers || !m->p->v6answers)
5693 {
5694 debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
5695 (timenow - m->p->DNSTrigger), m->p->v4answers, m->p->v6answers);
5696 }
5697 mDNS_Unlock(m);
5698 return;
5699 }
5700 mDNS_Unlock(m);
5701 if (v4q != NULL && QuestionValidForDNSTrigger(v4q))
5702 {
5703 int old = m->p->v4answers;
5704
5705 m->p->v4answers = 1;
5706
5707 // If there are IPv4 answers now and previously we did not have
5708 // any answers, trigger a DNS change so that reachability
5709 // can retry the queries again.
5710 if (!old)
5711 {
5712 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
5713 v4q->qname.c, DNSTypeName(v4q->qtype));
5714 trigger = mDNStrue;
5715 }
5716 }
5717 if (v6q != NULL && QuestionValidForDNSTrigger(v6q))
5718 {
5719 int old = m->p->v6answers;
5720
5721 m->p->v6answers = 1;
5722 // If there are IPv6 answers now and previously we did not have
5723 // any answers, trigger a DNS change so that reachability
5724 // can retry the queries again.
5725 if (!old)
5726 {
5727 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
5728 v6q->qname.c, DNSTypeName(v6q->qtype));
5729 trigger = mDNStrue;
5730 }
5731 }
5732 if (trigger)
5733 {
5734 dns_config_t *config = dns_configuration_copy();
5735 if (config)
5736 {
5737 mDNS_Lock(m);
5738 AckConfigd(config);
5739 mDNS_Unlock(m);
5740 dns_configuration_free(config);
5741 }
5742 else
5743 {
5744 LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
5745 }
5746 }
5747 }
5748
5749 mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
5750 {
5751 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
5752 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
5753 if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver &&
5754 config->resolver[0]->nameserver[0])
5755 {
5756 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
5757 }
5758 else
5759 {
5760 ActiveDirectoryPrimaryDomain.c[0] = 0;
5761 }
5762
5763 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
5764 ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
5765 if (config->n_resolver && config->resolver[0]->n_nameserver &&
5766 SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
5767 {
5768 SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
5769 }
5770 else
5771 {
5772 AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
5773 ActiveDirectoryPrimaryDomainLabelCount = 0;
5774 ActiveDirectoryPrimaryDomainServer = zeroAddr;
5775 }
5776 }
5777 #endif
5778
5779 mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
5780 {
5781 int i;
5782 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NULL
5783 domainname d;
5784
5785 CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_DynamicDNS);
5786 if (ddnsdict)
5787 {
5788 if (fqdn)
5789 {
5790 CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
5791 if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
5792 {
5793 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
5794 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
5795 if (fqdnDict && DictionaryIsEnabled(fqdnDict))
5796 {
5797 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
5798 if (name)
5799 {
5800 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5801 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
5802 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
5803 else
5804 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
5805 }
5806 }
5807 }
5808 }
5809 if (RegDomains)
5810 {
5811 CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
5812 if (regArray && CFArrayGetCount(regArray) > 0)
5813 {
5814 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
5815 if (regDict && DictionaryIsEnabled(regDict))
5816 {
5817 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
5818 if (name)
5819 {
5820 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5821 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
5822 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
5823 else
5824 {
5825 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
5826 AppendDNameListElem(&RegDomains, 0, &d);
5827 }
5828 }
5829 }
5830 }
5831 }
5832 if (BrowseDomains)
5833 {
5834 CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
5835 if (browseArray)
5836 {
5837 for (i = 0; i < CFArrayGetCount(browseArray); i++)
5838 {
5839 CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
5840 if (browseDict && DictionaryIsEnabled(browseDict))
5841 {
5842 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
5843 if (name)
5844 {
5845 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5846 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
5847 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
5848 else
5849 {
5850 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
5851 AppendDNameListElem(&BrowseDomains, 0, &d);
5852 }
5853 }
5854 }
5855 }
5856 }
5857 }
5858 CFRelease(ddnsdict);
5859 }
5860 #if MDNSRESPONDER_BTMM_SUPPORT
5861 if (RegDomains)
5862 {
5863 CFDictionaryRef btmm = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BackToMyMac);
5864 if (btmm)
5865 {
5866 CFIndex size = CFDictionaryGetCount(btmm);
5867 const void *key[size];
5868 const void *val[size];
5869 CFDictionaryGetKeysAndValues(btmm, key, val);
5870 for (i = 0; i < size; i++)
5871 {
5872 LogInfo("BackToMyMac %d", i);
5873 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
5874 LogMsg("Can't read BackToMyMac %d key %s", i, buf);
5875 else
5876 {
5877 mDNSu32 uid = atoi(buf);
5878 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
5879 LogMsg("Can't read BackToMyMac %d val %s", i, buf);
5880 else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
5881 {
5882 LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
5883 AppendDNameListElem(&RegDomains, uid, &d);
5884 }
5885 }
5886 }
5887 CFRelease(btmm);
5888 }
5889 }
5890 #endif
5891 }
5892
5893 // Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
5894 mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
5895 DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
5896 {
5897 mDNS *const m = &mDNSStorage;
5898 MD5_CTX sdc; // search domain context
5899 static mDNSu16 resolverGroupID = 0;
5900
5901 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
5902 if (fqdn ) fqdn->c[0] = 0;
5903 if (RegDomains ) *RegDomains = NULL;
5904 if (BrowseDomains) *BrowseDomains = NULL;
5905
5906 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
5907 setservers ? " setservers" : "",
5908 setsearch ? " setsearch" : "",
5909 fqdn ? " fqdn" : "",
5910 RegDomains ? " RegDomains" : "",
5911 BrowseDomains ? " BrowseDomains" : "");
5912
5913 if (setsearch) MD5_Init(&sdc);
5914
5915 // Add the inferred address-based configuration discovery domains
5916 // (should really be in core code I think, not platform-specific)
5917 if (setsearch)
5918 {
5919 struct ifaddrs *ifa = mDNSNULL;
5920 struct sockaddr_in saddr;
5921 mDNSPlatformMemZero(&saddr, sizeof(saddr));
5922 saddr.sin_len = sizeof(saddr);
5923 saddr.sin_family = AF_INET;
5924 saddr.sin_port = 0;
5925 saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
5926
5927 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
5928 if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1);
5929
5930 while (ifa)
5931 {
5932 mDNSAddr a, n;
5933 char buf[64];
5934
5935 if (ifa->ifa_addr->sa_family == AF_INET &&
5936 ifa->ifa_netmask &&
5937 !(ifa->ifa_flags & IFF_LOOPBACK) &&
5938 !SetupAddr(&a, ifa->ifa_addr) &&
5939 !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
5940 {
5941 // 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
5942 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5943 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; // Make sure ifa_netmask->sa_family is set correctly
5944 SetupAddr(&n, ifa->ifa_netmask);
5945 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
5946 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
5947 a.ip.v4.b[2] & n.ip.v4.b[2],
5948 a.ip.v4.b[1] & n.ip.v4.b[1],
5949 a.ip.v4.b[0] & n.ip.v4.b[0]);
5950 UpdateSearchDomainHash(&sdc, buf, NULL);
5951 mDNS_AddSearchDomain_CString(buf, mDNSNULL);
5952 }
5953 ifa = ifa->ifa_next;
5954 }
5955 }
5956
5957 #ifndef MDNS_NO_DNSINFO
5958 if (setservers || setsearch)
5959 {
5960 dns_config_t *config = dns_configuration_copy();
5961 if (!config)
5962 {
5963 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
5964 // Apparently this is expected behaviour -- "not a bug".
5965 // Accordingly, we suppress syslog messages for the first three minutes after boot.
5966 // If we are still getting failures after three minutes, then we log them.
5967 if ((mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
5968 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
5969 }
5970 else
5971 {
5972 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config->n_resolver, config->generation, m->p->LastConfigGeneration);
5973
5974 // For every network change, mDNSPlatformSetDNSConfig is called twice. First,
5975 // to update the search domain list (in which case, the setsearch bool is set);
5976 // and second, to update the DNS server list (in which case, the setservers bool
5977 // is set). The code assumes only one of these flags, setsearch or setserver,
5978 // will be set when mDNSPlatformSetDNSConfig is called to handle a network change.
5979 // The mDNSPlatformSetDNSConfig function also assumes that ackCfg will be set
5980 // when setservers is set.
5981
5982 // The search domains update occurs on every network change to avoid sync issues
5983 // that may occur if a network change happens during the processing
5984 // of a network change. The dns servers update occurs when the DNS config
5985 // changes. The dns servers stay in sync by saving the config's generation number
5986 // on every update; and only updating when the generation number changes.
5987
5988 // If this is a DNS server update and the configuration hasn't changed, then skip update
5989 if (setservers && m->p->LastConfigGeneration == config->generation)
5990 {
5991 LogInfo("mDNSPlatformSetDNSConfig(setservers): generation number %llu same, not processing", config->generation);
5992 dns_configuration_free(config);
5993 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
5994 return mDNSfalse;
5995 }
5996 #if APPLE_OSX_mDNSResponder
5997 SetupActiveDirectoryDomain(config);
5998 #endif
5999
6000 // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry
6001 // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need
6002 // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between
6003 // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the
6004 // same resolverGroupID.
6005 //
6006 // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally.
6007 ConfigResolvers(config, kScopeNone, setsearch, setservers, &sdc, ++resolverGroupID);
6008 resolverGroupID += config->n_resolver;
6009
6010 ConfigResolvers(config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID);
6011 resolverGroupID += config->n_scoped_resolver;
6012
6013 ConfigResolvers(config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID);
6014
6015 // Acking provides a hint to other processes that the current DNS configuration has completed
6016 // its update. When configd receives the ack, it publishes a notification.
6017 // Applications monitoring the notification then know when to re-issue their DNS queries
6018 // after a network change occurs.
6019 if (ackConfig)
6020 {
6021 // Note: We have to set the generation number here when we are acking.
6022 // For every DNS configuration change, we do the following:
6023 //
6024 // 1) Copy dns configuration, handle search domains change
6025 // 2) Copy dns configuration, handle dns server change
6026 //
6027 // If we update the generation number at step (1), we won't process the
6028 // DNS servers the second time because generation number would be the same.
6029 // As we ack only when we process dns servers, we set the generation number
6030 // during acking.
6031 m->p->LastConfigGeneration = config->generation;
6032 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers, setsearch);
6033 AckConfigd(config);
6034 }
6035 dns_configuration_free(config);
6036 if (setsearch) FinalizeSearchDomainHash(&sdc);
6037 }
6038 }
6039 #endif // MDNS_NO_DNSINFO
6040 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6041 return mDNStrue;
6042 }
6043
6044
6045 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
6046 {
6047 char buf[256];
6048
6049 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_IPv4);
6050 if (dict)
6051 {
6052 r->type = mDNSAddrType_IPv4;
6053 r->ip.v4 = zerov4Addr;
6054 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
6055 if (string)
6056 {
6057 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
6058 LogMsg("Could not convert router to CString");
6059 else
6060 {
6061 struct sockaddr_in saddr;
6062 saddr.sin_len = sizeof(saddr);
6063 saddr.sin_family = AF_INET;
6064 saddr.sin_port = 0;
6065 inet_aton(buf, &saddr.sin_addr);
6066 *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
6067 }
6068 }
6069 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
6070 if (string)
6071 {
6072 mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
6073 struct ifaddrs *ifa = myGetIfAddrs(1);
6074 *v4 = *v6 = zeroAddr;
6075
6076 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
6077 {
6078 LogMsg("Could not convert router to CString");
6079 goto exit;
6080 }
6081 // find primary interface in list
6082 while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
6083 {
6084 if (!ifa->ifa_addr)
6085 {
6086 LogMsg("Skip interface, %s, since ifa_addr is not set.", (ifa->ifa_name) ? ifa->ifa_name: "name not found");
6087 ifa = ifa->ifa_next;
6088 continue;
6089 }
6090 mDNSAddr tmp6 = zeroAddr;
6091 if (!strcmp(buf, ifa->ifa_name))
6092 {
6093 if (ifa->ifa_addr->sa_family == AF_INET)
6094 {
6095 if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4))
6096 SetupAddr(v4, ifa->ifa_addr);
6097 }
6098 else if (ifa->ifa_addr->sa_family == AF_INET6)
6099 {
6100 SetupAddr(&tmp6, ifa->ifa_addr);
6101 if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
6102 {
6103 HavePrimaryGlobalv6 = mDNStrue;
6104 *v6 = tmp6;
6105 }
6106 }
6107 }
6108 else
6109 {
6110 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
6111 if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
6112 {
6113 SetupAddr(&tmp6, ifa->ifa_addr);
6114 if (tmp6.ip.v6.b[0] >> 5 == 1)
6115 *v6 = tmp6;
6116 }
6117 }
6118 ifa = ifa->ifa_next;
6119 }
6120 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
6121 // V4 to communicate w/ our DNS server
6122 }
6123
6124 exit:
6125 CFRelease(dict);
6126 }
6127 return mStatus_NoError;
6128 }
6129
6130 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
6131 {
6132 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
6133 char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6134 ConvertDomainNameToCString(dname, uname);
6135
6136 char *p = uname;
6137 while (*p)
6138 {
6139 *p = tolower(*p);
6140 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
6141 p++;
6142 }
6143
6144 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
6145 // That single entity is a CFDictionary with name "HostNames".
6146 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
6147 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
6148 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
6149 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
6150 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
6151
6152 const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
6153 const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
6154 const CFStringRef StatusKeys[1] = { CFSTR("Status") };
6155 if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
6156 else
6157 {
6158 const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
6159 if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
6160 else
6161 {
6162 const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6163 if (HostVals[0])
6164 {
6165 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6166 if (StateVals[0])
6167 {
6168 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6169 if (StateDict)
6170 {
6171 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
6172 CFRelease(StateDict);
6173 }
6174 CFRelease(StateVals[0]);
6175 }
6176 CFRelease(HostVals[0]);
6177 }
6178 CFRelease(StatusVals[0]);
6179 }
6180 CFRelease(HostKeys[0]);
6181 }
6182 }
6183
6184 #if MDNSRESPONDER_BTMM_SUPPORT
6185 #if !NO_AWACS
6186
6187 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
6188 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
6189 // help catch it
6190 mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
6191 {
6192 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
6193 if (!store)
6194 {
6195 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6196 return mDNSfalse;
6197 }
6198 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
6199 if (btmm)
6200 {
6201 CFIndex size = CFDictionaryGetCount(btmm);
6202 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6203 const void *key[size];
6204 const void *val[size];
6205 domainname dom;
6206 int i;
6207 CFDictionaryGetKeysAndValues(btmm, key, val);
6208 for (i = 0; i < size; i++)
6209 {
6210 LogInfo("BackToMyMac %d", i);
6211 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6212 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
6213 else
6214 {
6215 mDNSu32 uid = atoi(buf);
6216 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6217 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
6218 else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
6219 {
6220 if (SameDomainName(&dom, d))
6221 {
6222 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
6223 CFRelease(btmm);
6224 CFRelease(store);
6225 return mDNStrue;
6226 }
6227 }
6228 }
6229 }
6230 CFRelease(btmm);
6231 }
6232 CFRelease(store);
6233 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
6234 return mDNSfalse;
6235 }
6236
6237 // Appends data to the buffer
6238 mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
6239 {
6240 int len;
6241
6242 len = strlcpy(buf + *currlen, data, bufsz - *currlen);
6243 if (len >= (bufsz - *currlen))
6244 {
6245 // if we have exceeded the space in buf, it has already been NULL terminated
6246 // and we have nothing more to do. Set currlen to the last byte so that the caller
6247 // knows to do the right thing
6248 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
6249 *currlen = bufsz - 1;
6250 return -1;
6251 }
6252 else { (*currlen) += len; }
6253
6254 buf[*currlen] = ',';
6255 if (*currlen >= bufsz)
6256 {
6257 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
6258 *currlen = bufsz - 1;
6259 buf[*currlen] = 0;
6260 return -1;
6261 }
6262 // if we have filled up the buffer exactly, then there is no more work to do
6263 if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
6264 (*currlen)++;
6265 return *currlen;
6266 }
6267
6268 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
6269 // BTMM domains, then bring down the connection to the relay.
6270 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6271 {
6272 DomainAuthInfo *BTMMDomain = mDNSNULL;
6273 DomainAuthInfo *FoundInList;
6274 static mDNSBool AWACSDConnected = mDNSfalse;
6275 char AllUsers[1024]; // maximum size of mach message
6276 char AllPass[1024]; // maximum size of mach message
6277 char username[MAX_DOMAIN_LABEL + 1];
6278 int currulen = 0;
6279 int currplen = 0;
6280
6281 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
6282 // we may not be able to send the dns queries over the relay connection which may be needed
6283 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
6284 // need to make sure that we send the disconnect before attempting the next connect as the
6285 // awacs connections are redirected based on usernames.
6286 //
6287 // For now we send a disconnect immediately. When we start sending dns queries over the relay
6288 // connection, we will need to fix this.
6289
6290 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6291 if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
6292 {
6293 // We need the passwd from the first domain.
6294 BTMMDomain = FoundInList;
6295 ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
6296 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
6297 if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
6298 if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
6299 }
6300
6301 if (BTMMDomain)
6302 {
6303 // In the normal case (where we neither exceed the buffer size nor write bytes that
6304 // fit exactly into the buffer), currulen/currplen should be a different size than
6305 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
6306
6307 if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
6308 if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
6309
6310 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
6311 AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
6312 AWACSDConnected = mDNStrue;
6313 }
6314 else
6315 {
6316 // Disconnect only if we connected previously
6317 if (AWACSDConnected)
6318 {
6319 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
6320 AWACS_Disconnect();
6321 AWACSDConnected = mDNSfalse;
6322 }
6323 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
6324 }
6325 }
6326 #else
6327 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6328 {
6329 (void) m; // Unused
6330 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
6331 }
6332 #endif // ! NO_AWACS
6333
6334 mDNSlocal void ProcessConndConfigChanges(void);
6335
6336 #endif // MDNSRESPONDER_BTMM_SUPPORT
6337
6338 // MUST be called holding the lock
6339 mDNSlocal void SetDomainSecrets_internal(mDNS *m)
6340 {
6341 #ifdef NO_SECURITYFRAMEWORK
6342 (void) m;
6343 LogMsg("Note: SetDomainSecrets: no keychain support");
6344 #else
6345 mDNSBool haveAutoTunnels = mDNSfalse;
6346
6347 LogInfo("SetDomainSecrets");
6348
6349 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
6350 // In the case where the user simultaneously removes their DDNS host name and the key
6351 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
6352 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
6353 // address records behind that we no longer have permission to delete.
6354 DomainAuthInfo *ptr;
6355 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
6356 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
6357
6358 #if APPLE_OSX_mDNSResponder
6359 {
6360 // Mark all TunnelClients for deletion
6361 ClientTunnel *client;
6362 for (client = m->TunnelClients; client; client = client->next)
6363 {
6364 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
6365 client->MarkedForDeletion = mDNStrue;
6366 }
6367 }
6368 #endif // APPLE_OSX_mDNSResponder
6369
6370 // String Array used to write list of private domains to Dynamic Store
6371 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6372 if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
6373 CFIndex i;
6374 CFDataRef data = NULL;
6375 const int itemsPerEntry = 4; // domain name, key name, key value, Name value
6376 CFArrayRef secrets = NULL;
6377 int err = mDNSKeychainGetSecrets(&secrets);
6378 if (err || !secrets)
6379 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
6380 else
6381 {
6382 CFIndex ArrayCount = CFArrayGetCount(secrets);
6383 // Iterate through the secrets
6384 for (i = 0; i < ArrayCount; ++i)
6385 {
6386 mDNSBool AutoTunnel;
6387 int j, offset;
6388 CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
6389 if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
6390 { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i, itemsPerEntry); continue; }
6391 for (j = 0; j < CFArrayGetCount(entry); ++j)
6392 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
6393 { LogMsg("SetDomainSecrets: malformed entry item %d", j); continue; }
6394
6395 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
6396
6397 // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
6398 // Get DNS domain this key is for (kmDNSKcWhere)
6399 char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(btmmprefix)];
6400 data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere);
6401 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6402 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
6403 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6404 stringbuf[CFDataGetLength(data)] = '\0';
6405
6406 AutoTunnel = mDNSfalse;
6407 offset = 0;
6408 if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
6409 offset = strlen(dnsprefix);
6410 #if MDNSRESPONDER_BTMM_SUPPORT
6411 else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix)))
6412 {
6413 AutoTunnel = mDNStrue;
6414 offset = strlen(btmmprefix);
6415 }
6416 #endif
6417 domainname domain;
6418 if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
6419
6420 // Get key name (kmDNSKcAccount)
6421 data = CFArrayGetValueAtIndex(entry, kmDNSKcAccount);
6422 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6423 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
6424 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
6425 stringbuf[CFDataGetLength(data)] = '\0';
6426
6427 domainname keyname;
6428 if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
6429
6430 // Get key data (kmDNSKcKey)
6431 data = CFArrayGetValueAtIndex(entry, kmDNSKcKey);
6432 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6433 {
6434 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data));
6435 continue;
6436 }
6437 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6438 stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
6439
6440 // Get the Name of the keychain entry (kmDNSKcName) host or host:port
6441 // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
6442 char hostbuf[MAX_ESCAPED_DOMAIN_NAME + 6]; // Max legal domainname as C-string, including terminating NUL
6443 data = CFArrayGetValueAtIndex(entry, kmDNSKcName);
6444 if (CFDataGetLength(data) >= (int)sizeof(hostbuf))
6445 {
6446 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data));
6447 continue;
6448 }
6449 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)hostbuf);
6450 hostbuf[CFDataGetLength(data)] = '\0';
6451
6452 domainname hostname;
6453 mDNSIPPort port;
6454 char *hptr;
6455 hptr = strchr(hostbuf, ':');
6456
6457 port.NotAnInteger = 0;
6458 if (hptr)
6459 {
6460 mDNSu8 *p;
6461 mDNSu16 val = 0;
6462
6463 *hptr++ = '\0';
6464 while(hptr && *hptr != 0)
6465 {
6466 if (*hptr < '0' || *hptr > '9')
6467 { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr, val); val = 0; break;}
6468 val = val * 10 + *hptr - '0';
6469 hptr++;
6470 }
6471 if (!val) continue;
6472 p = (mDNSu8 *)&val;
6473 port.NotAnInteger = p[0] << 8 | p[1];
6474 }
6475 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
6476 hptr = strchr(hostbuf, '@');
6477 if (hptr)
6478 hptr++;
6479 else
6480 hptr = hostbuf;
6481 if (!MakeDomainNameFromDNSNameString(&hostname, hptr)) { LogMsg("SetDomainSecrets: bad host name %s", hptr); continue; }
6482
6483 DomainAuthInfo *FoundInList;
6484 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6485 if (SameDomainName(&FoundInList->domain, &domain)) break;
6486
6487 #if APPLE_OSX_mDNSResponder
6488 if (FoundInList)
6489 {
6490 // If any client tunnel destination is in this domain, set deletion flag to false
6491 ClientTunnel *client;
6492 for (client = m->TunnelClients; client; client = client->next)
6493 if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
6494 {
6495 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
6496 client->MarkedForDeletion = mDNSfalse;
6497 }
6498 }
6499
6500 #endif // APPLE_OSX_mDNSResponder
6501
6502 // Uncomment the line below to view the keys as they're read out of the system keychain
6503 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
6504 //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]));
6505 LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain.c, &keyname.c, hostname.c, (port.b[0] << 8 | port.b[1]));
6506
6507 // If didn't find desired domain in the list, make a new entry
6508 ptr = FoundInList;
6509 if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
6510 if (!FoundInList)
6511 {
6512 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
6513 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
6514 }
6515
6516 //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
6517
6518 // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
6519 if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port, AutoTunnel) == mStatus_BadParamErr)
6520 {
6521 if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
6522 continue;
6523 }
6524
6525 ConvertDomainNameToCString(&domain, stringbuf);
6526 CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
6527 if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
6528 }
6529 CFRelease(secrets);
6530 }
6531
6532 if (!privateDnsArray || !CFEqual(privateDnsArray, sa))
6533 {
6534 if (privateDnsArray)
6535 CFRelease(privateDnsArray);
6536
6537 privateDnsArray = sa;
6538 CFRetain(privateDnsArray);
6539 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
6540 }
6541 CFRelease(sa);
6542
6543 #if APPLE_OSX_mDNSResponder
6544 {
6545 // clean up ClientTunnels
6546 ClientTunnel **pp = &m->TunnelClients;
6547 while (*pp)
6548 {
6549 if ((*pp)->MarkedForDeletion)
6550 {
6551 ClientTunnel *cur = *pp;
6552 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
6553 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
6554 AutoTunnelSetKeys(cur, mDNSfalse);
6555 *pp = cur->next;
6556 freeL("ClientTunnel", cur);
6557 }
6558 else
6559 pp = &(*pp)->next;
6560 }
6561
6562 mDNSBool needAutoTunnelNAT = mDNSfalse;
6563 DomainAuthInfo *info;
6564 for (info = m->AuthInfoList; info; info = info->next)
6565 {
6566 if (info->AutoTunnel)
6567 {
6568 UpdateAutoTunnelDeviceInfoRecord(m, info);
6569 UpdateAutoTunnelHostRecord(m, info);
6570 UpdateAutoTunnelServiceRecords(m, info);
6571 UpdateAutoTunnel6Record(m, info);
6572 if (info->deltime)
6573 {
6574 if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse;
6575 }
6576 else if (info->AutoTunnelServiceStarted)
6577 needAutoTunnelNAT = true;
6578
6579 UpdateAutoTunnelDomainStatus(info);
6580 }
6581 }
6582
6583 // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
6584 if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext)
6585 {
6586 // stop the NAT operation, reset port, cleanup state
6587 mDNS_StopNATOperation_internal(m, &m->AutoTunnelNAT);
6588 m->AutoTunnelNAT.ExternalAddress = zerov4Addr;
6589 m->AutoTunnelNAT.NewAddress = zerov4Addr;
6590 m->AutoTunnelNAT.ExternalPort = zeroIPPort;
6591 m->AutoTunnelNAT.RequestedPort = zeroIPPort;
6592 m->AutoTunnelNAT.Lifetime = 0;
6593 m->AutoTunnelNAT.Result = mStatus_NoError;
6594 m->AutoTunnelNAT.clientContext = mDNSNULL;
6595 }
6596
6597 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
6598 #if MDNSRESPONDER_BTMM_SUPPORT
6599 ProcessConndConfigChanges(); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
6600 #endif
6601 }
6602 #endif // APPLE_OSX_mDNSResponder
6603
6604 CheckSuppressUnusableQuestions(m);
6605
6606 #endif /* NO_SECURITYFRAMEWORK */
6607 }
6608
6609 mDNSexport void SetDomainSecrets(mDNS *m)
6610 {
6611 #if DEBUG
6612 // Don't get secrets for BTMM if running in debug mode
6613 if (!IsDebugSocketInUse())
6614 #endif
6615 SetDomainSecrets_internal(m);
6616 }
6617
6618 mDNSlocal void SetLocalDomains(void)
6619 {
6620 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6621 if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
6622
6623 CFArrayAppendValue(sa, CFSTR("local"));
6624 CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
6625 CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
6626 CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
6627 CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
6628 CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
6629
6630 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
6631 CFRelease(sa);
6632 }
6633
6634 mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
6635 {
6636
6637 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_PowerSettings);
6638 if (!dict)
6639 {
6640 LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
6641 }
6642 else
6643 {
6644 CFNumberRef number = CFDictionaryGetValue(dict, name);
6645 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
6646 *val = 0;
6647 CFRelease(dict);
6648 }
6649
6650 }
6651
6652 #if APPLE_OSX_mDNSResponder
6653
6654 static CFMutableDictionaryRef spsStatusDict = NULL;
6655 static const CFStringRef kMetricRef = CFSTR("Metric");
6656
6657 mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
6658 {
6659 mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
6660 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
6661 if (!num)
6662 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
6663 else
6664 {
6665 CFDictionarySetValue(dict, key, num);
6666 CFRelease(num);
6667 }
6668 }
6669
6670 mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
6671 {
6672 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6673 if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
6674
6675 char buffer[1024];
6676 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
6677 CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
6678 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
6679 CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
6680 CFRelease(spsname);
6681
6682 if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
6683 if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
6684 if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
6685 if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
6686
6687 mDNSu32 tmp = SPSMetric(ptr);
6688 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
6689 if (!num)
6690 LogMsg("SPSCreateDict: Could not create CFNumber");
6691 else
6692 {
6693 CFDictionarySetValue(dict, kMetricRef, num);
6694 CFRelease(num);
6695 }
6696
6697 if (ptr[0] >= 12)
6698 {
6699 memcpy(buffer, ptr + 13, ptr[0] - 12);
6700 buffer[ptr[0] - 12] = 0;
6701 spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
6702 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
6703 else
6704 {
6705 CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
6706 CFRelease(spsname);
6707 }
6708 }
6709
6710 return dict;
6711 }
6712
6713 mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
6714 {
6715 (void)context;
6716 return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
6717 (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
6718 NULL);
6719 }
6720
6721 mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
6722 {
6723 NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
6724 debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
6725
6726 mDNS_Lock(m);
6727 mDNS_UpdateAllowSleep(m);
6728 mDNS_Unlock(m);
6729
6730 if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names
6731
6732 if (!spsStatusDict)
6733 {
6734 spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6735 if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
6736 }
6737
6738 CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
6739 if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
6740
6741 CFMutableArrayRef array = NULL;
6742
6743 if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
6744 {
6745 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6746 if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
6747 CFDictionarySetValue(spsStatusDict, ifname, array);
6748 CFRelease(array); // let go of our reference, now that the dict has one
6749 }
6750 else
6751 if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
6752
6753 if (!answer) // special call that means the question has been stopped (because the interface is going away)
6754 CFArrayRemoveAllValues(array);
6755 else
6756 {
6757 CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
6758 if (!dict) { CFRelease(ifname); return; }
6759
6760 if (AddRecord)
6761 {
6762 if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
6763 {
6764 int i=0;
6765 for (i=0; i<CFArrayGetCount(array); i++)
6766 if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
6767 break;
6768 CFArrayInsertValueAtIndex(array, i, dict);
6769 }
6770 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
6771 }
6772 else
6773 {
6774 CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
6775 if (i != -1) CFArrayRemoveValueAtIndex(array, i);
6776 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
6777 }
6778
6779 CFRelease(dict);
6780 }
6781
6782 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
6783
6784 CFRelease(ifname);
6785 }
6786
6787 mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
6788 {
6789 mDNSs32 val = -1;
6790 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
6791 if (!store)
6792 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6793 else
6794 {
6795 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
6796 if (dict)
6797 {
6798 CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
6799 if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
6800 CFRelease(dict);
6801 }
6802 CFRelease(store);
6803 }
6804 return val;
6805 }
6806
6807 mDNSlocal void SetSPS(mDNS *const m)
6808 {
6809
6810 // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
6811 mDNSu8 sps = (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware : 0;
6812
6813 // For devices that are not running NAT, but are set to never sleep, we may choose to act
6814 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
6815 //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
6816
6817 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
6818
6819 // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
6820 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
6821 // We rate such a device as metric 70 ("Incidentally Available Hardware")
6822 if (SPMetricMarginalPower <= 60 && !sps) sps = mDNSSleepProxyMetric_IncidentalHardware;
6823
6824 // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
6825 // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
6826 if (sps && OfferSleepProxyService && OfferSleepProxyService < 100) sps = OfferSleepProxyService;
6827
6828 #ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI
6829 // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active.
6830 if (IsAppleTV())
6831 {
6832 NetworkInterfaceInfo *intf = mDNSNULL;
6833 mDNSEthAddr bssid = zeroEthAddr;
6834 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
6835 {
6836 if (intf->InterfaceID == AWDLInterfaceID) continue;
6837 bssid = GetBSSID(intf->ifname);
6838 if (!mDNSSameEthAddress(&bssid, &zeroEthAddr))
6839 {
6840 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
6841 sps = 0;
6842 break;
6843 }
6844 }
6845 }
6846 #endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI
6847
6848 mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
6849 }
6850
6851 // The definitions below should eventually come from some externally-supplied header file.
6852 // However, since these definitions can't really be changed without breaking binary compatibility,
6853 // they should never change, so in practice it should not be a big problem to have them defined here.
6854
6855 enum
6856 { // commands from the daemon to the driver
6857 cmd_mDNSOffloadRR = 21, // give the mdns update buffer to the driver
6858 };
6859
6860 typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr;
6861
6862 typedef struct
6863 { // cmd_mDNSOffloadRR structure
6864 uint32_t command; // set to OffloadRR
6865 uint32_t rrBufferSize; // number of bytes of RR records
6866 uint32_t numUDPPorts; // number of SRV UDP ports
6867 uint32_t numTCPPorts; // number of SRV TCP ports
6868 uint32_t numRRRecords; // number of RR records
6869 uint32_t compression; // rrRecords - compression is base for compressed strings
6870 FatPtr rrRecords; // address of array of pointers to the rr records
6871 FatPtr udpPorts; // address of udp port list (SRV)
6872 FatPtr tcpPorts; // address of tcp port list (SRV)
6873 } mDNSOffloadCmd;
6874
6875 #include <IOKit/IOKitLib.h>
6876 #include <dns_util.h>
6877
6878 mDNSlocal mDNSu16 GetPortArray(int trans, mDNSIPPort *portarray)
6879 {
6880 mDNS *const m = &mDNSStorage;
6881 const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
6882 int count = 0;
6883
6884 AuthRecord *rr;
6885 for (rr = m->ResourceRecords; rr; rr=rr->next)
6886 {
6887 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c))
6888 {
6889 if (!portarray)
6890 count++;
6891 else
6892 {
6893 int i;
6894 for (i = 0; i < count; i++)
6895 if (mDNSSameIPPort(portarray[i], rr->resrec.rdata->u.srv.port))
6896 break;
6897
6898 // Add it into the port list only if it not already present in the list
6899 if (i >= count)
6900 portarray[count++] = rr->resrec.rdata->u.srv.port;
6901 }
6902 }
6903 }
6904
6905 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
6906 if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext)
6907 {
6908 LogSPS("GetPortArray Back to My Mac at %d", count);
6909 if (portarray) portarray[count] = IPSECPort;
6910 count++;
6911 }
6912 return(count);
6913 }
6914
6915 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6916 mDNSlocal mDNSBool SupportsTCPKeepAlive()
6917 {
6918 IOReturn ret = kIOReturnSuccess;
6919 CFTypeRef obj = NULL;
6920 mDNSBool supports = mDNSfalse;
6921
6922 ret = IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj);
6923 if ((kIOReturnSuccess == ret) && (obj != NULL))
6924 {
6925 supports = (obj == kCFBooleanTrue)? mDNStrue : mDNSfalse;
6926 CFRelease(obj);
6927 }
6928 LogSPS("%s: The hardware %s TCP Keep Alive", __func__, (supports ? "supports" : "does not support"));
6929 return supports;
6930 }
6931
6932 mDNSlocal mDNSBool OnBattery(void)
6933 {
6934 CFTypeRef powerInfo = IOPSCopyPowerSourcesInfo();
6935 CFTypeRef powerSrc = IOPSGetProvidingPowerSourceType(powerInfo);
6936 mDNSBool result = mDNSfalse;
6937
6938 if (powerInfo != NULL)
6939 {
6940 result = CFEqual(CFSTR(kIOPSBatteryPowerValue), powerSrc);
6941 CFRelease(powerInfo);
6942 }
6943 LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
6944 return result;
6945 }
6946
6947 #endif // !TARGET_OS_EMBEDDED
6948
6949 #define TfrRecordToNIC(RR) \
6950 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
6951
6952 mDNSlocal mDNSu32 CountProxyRecords(uint32_t *const numbytes, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
6953 {
6954 mDNS *const m = &mDNSStorage;
6955 *numbytes = 0;
6956 int count = 0;
6957
6958 AuthRecord *rr;
6959
6960 for (rr = m->ResourceRecords; rr; rr=rr->next)
6961 {
6962 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
6963 {
6964 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6965 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
6966 // Skip over all other records if we are registering TCP KeepAlive records only
6967 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
6968 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
6969 continue;
6970
6971 // Update the record before calculating the number of bytes required
6972 // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
6973 // attempt to update the record again.
6974 if (isKeepAliveRecord && (UpdateKeepaliveRData(m, rr, intf, mDNSfalse, mDNSNULL) != mStatus_NoError))
6975 LogSPS("CountProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m, rr));
6976
6977 // Offload only Valid Keepalive records
6978 if (isKeepAliveRecord && !mDNSValidKeepAliveRecord(rr))
6979 continue;
6980 #else
6981 (void) TCPKAOnly; // unused
6982 (void) supportsTCPKA; // unused
6983 (void) intf; // unused
6984 #endif // APPLE_OSX_mDNSResponder
6985 if (TfrRecordToNIC(rr))
6986 {
6987 *numbytes += DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate;
6988 LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
6989 count, DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate, *numbytes, ARDisplayString(m,rr));
6990 count++;
6991 }
6992 }
6993 }
6994 return(count);
6995 }
6996
6997 mDNSlocal void GetProxyRecords(DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
6998 {
6999 mDNS *const m = &mDNSStorage;
7000 mDNSu8 *p = msg->data;
7001 const mDNSu8 *const limit = p + *numbytes;
7002 InitializeDNSMessage(&msg->h, zeroID, zeroID);
7003
7004 int count = 0;
7005 AuthRecord *rr;
7006
7007 for (rr = m->ResourceRecords; rr; rr=rr->next)
7008 {
7009 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
7010 {
7011 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7012 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
7013
7014 // Skip over all other records if we are registering TCP KeepAlive records only
7015 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
7016 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
7017 continue;
7018
7019 // Offload only Valid Keepalive records
7020 if (isKeepAliveRecord && !mDNSValidKeepAliveRecord(rr))
7021 continue;
7022 #else
7023 (void) TCPKAOnly; // unused
7024 (void) supportsTCPKA; // unused
7025 #endif // APPLE_OSX_mDNSResponder
7026
7027 if (TfrRecordToNIC(rr))
7028 {
7029 records[count].sixtyfourbits = zeroOpaque64;
7030 records[count].ptr = p;
7031 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
7032 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it
7033 p = PutResourceRecordTTLWithLimit(msg, p, &msg->h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
7034 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state
7035 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
7036 count, records[count].ptr, p, p - (mDNSu8 *)records[count].ptr, p - msg->data, ARDisplayString(m,rr));
7037 count++;
7038 }
7039 }
7040 }
7041 *numbytes = p - msg->data;
7042 }
7043
7044 mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf)
7045 {
7046 if(!UseInternalSleepProxy)
7047 {
7048 LogMsg("SupportsInNICProxy: Internal Sleep Proxy is disabled");
7049 return mDNSfalse;
7050 }
7051 return CheckInterfaceSupport(intf, mDNS_IOREG_KEY);
7052 }
7053
7054 mDNSexport mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool *keepaliveOnly) // Called with the lock held
7055 {
7056 mStatus result = mStatus_UnknownErr;
7057 mDNSBool TCPKAOnly = mDNSfalse;
7058 mDNSBool supportsTCPKA = mDNSfalse;
7059 mDNSBool onbattery = mDNSfalse;
7060 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
7061
7062 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7063 onbattery = OnBattery();
7064 // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
7065 supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive());
7066
7067 // Only TCP Keepalive records are to be offloaded if
7068 // - The system is on battery
7069 // - OR wake for network access is not set but powernap is enabled
7070 TCPKAOnly = supportsTCPKA && ((mDNSStorage.SystemWakeOnLANEnabled == mDNS_WakeOnBattery) || onbattery);
7071 #else
7072 (void) onbattery; // unused;
7073 #endif
7074 if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", intf->ifname); return(mStatus_UnknownErr); }
7075
7076 io_name_t n1, n2;
7077 IOObjectGetClass(service, n1);
7078 io_object_t parent = IO_OBJECT_NULL;
7079
7080 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
7081 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
7082 else
7083 {
7084 CFTypeRef ref = mDNSNULL;
7085 if (IsAppleTV())
7086 {
7087 while (service)
7088 {
7089 ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
7090 if (!ref)
7091 {
7092 IOObjectRelease(service);
7093 service = parent;
7094 kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
7095 if (kr != KERN_SUCCESS)
7096 {
7097 IOObjectGetClass(service, n1);
7098 LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
7099 parent = IO_OBJECT_NULL;
7100 result = mStatus_BadStateErr;
7101 break;
7102 }
7103 }
7104 else
7105 {
7106 IOObjectGetClass(parent, n2);
7107 LogSPS("ActivateLocalProxy: Found %s Interface %s parent %s", mDNS_IOREG_KEY, intf->ifname, n2);
7108 break;
7109 }
7110 }
7111 }
7112 else
7113 {
7114 IOObjectGetClass(parent, n2);
7115 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf->ifname, n1, n2);
7116 ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
7117 }
7118
7119 if (!ref || parent == IO_OBJECT_NULL) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
7120 else
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 = GetPortArray(mDNSTransport_UDP, mDNSNULL);
7138 cmd.numTCPPorts = GetPortArray(mDNSTransport_TCP, mDNSNULL);
7139 cmd.numRRRecords = CountProxyRecords(&cmd.rrBufferSize, intf, 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 %d RR %p %d, UDP %p %d, TCP %p %d",
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) GetProxyRecords(msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA);
7154 if (cmd.udpPorts.ptr) cmd.numUDPPorts = GetPortArray(mDNSTransport_UDP, cmd.udpPorts.ptr);
7155 if (cmd.tcpPorts.ptr) cmd.numTCPPorts = GetPortArray(mDNSTransport_TCP, cmd.tcpPorts.ptr);
7156
7157 char outputData[2];
7158 size_t outputDataSize = sizeof(outputData);
7159 kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize);
7160 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr);
7161 if (kr == KERN_SUCCESS) result = mStatus_NoError;
7162
7163 if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts.ptr);
7164 if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts.ptr);
7165 if (cmd.rrRecords.ptr) freeL("mDNSOffloadCmd rrRecords", cmd.rrRecords.ptr);
7166 if (msg) freeL("mDNSOffloadCmd msg", msg);
7167 IOServiceClose(conObj);
7168 }
7169 }
7170 CFRelease(ref);
7171 }
7172 if (parent != IO_OBJECT_NULL) IOObjectRelease(parent);
7173 }
7174 if (service != IO_OBJECT_NULL) IOObjectRelease(service);
7175 *keepaliveOnly = TCPKAOnly;
7176 return result;
7177 }
7178
7179 #endif // APPLE_OSX_mDNSResponder
7180
7181 mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
7182 {
7183 mDNSs32 val = 0;
7184 mDNSu8 ret = (mDNSu8)mDNS_NoWake;
7185
7186 #if TARGET_OS_IOS
7187 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7188 return ret;
7189 #endif
7190
7191 if (DisableSleepProxyClient)
7192 {
7193 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7194 return ret;
7195 }
7196
7197 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
7198
7199 ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
7200
7201 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7202 // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
7203 // Further policy decisions on whether to offload the records is handled during sleep processing.
7204 if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive())
7205 ret = (mDNSu8)mDNS_WakeOnBattery;
7206 #endif // APPLE_OSX_mDNSResponder
7207
7208 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret);
7209 return ret;
7210 }
7211
7212 mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
7213 {
7214 mDNSs32 val = 0;
7215 // PrioritizeNetworkReachabilityOverSleep has been deprecated.
7216 // GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
7217 // Statically set the PrioritizeNetworkReachabilityOverSleep value to 1 for AppleTV
7218 if (IsAppleTV())
7219 val = 1;
7220 return val != 0 ? mDNStrue : mDNSfalse;
7221 }
7222
7223
7224 #if APPLE_OSX_mDNSResponder
7225 // When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
7226 // gets deregistered, so that older peers are forced to connect over direct UDP instead of
7227 // the RR relay.
7228 //
7229 // When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
7230 // service records are deregistered, so they do not appear in peers' Finder sidebars.
7231 // We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
7232 // depend on their associated SRV record and therefore will be deregistered together in a
7233 // single update with the SRV record.
7234 //
7235 // Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
7236 // its presence shouldn't delay sleep.
7237 //
7238 // Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
7239 // relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
7240 //
7241 // Also note that returning false here will not delay sleep past the maximum of 10 seconds.
7242 mDNSexport mDNSBool RecordReadyForSleep(AuthRecord *rr)
7243 {
7244 mDNS *const m = &mDNSStorage;
7245 if (!AuthRecord_uDNS(rr)) return mDNStrue;
7246
7247 if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
7248 {
7249 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7250 return mDNSfalse;
7251 }
7252
7253 if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result))
7254 {
7255 if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone
7256 && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel"))
7257 {
7258 DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
7259 if (info && info->AutoTunnel)
7260 {
7261 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7262 return mDNSfalse;
7263 }
7264 }
7265 }
7266
7267 return mDNStrue;
7268 }
7269
7270 // Caller must hold the lock
7271 mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
7272 {
7273 DomainAuthInfo *info;
7274 // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
7275 // deregister the record, and the MemFree callback won't re-register.
7276 m->AutoTunnelRelayAddr = zerov6Addr;
7277 for (info = m->AuthInfoList; info; info = info->next)
7278 if (info->AutoTunnel)
7279 UpdateAutoTunnel6Record(m, info);
7280 }
7281 #endif /* APPLE_OSX_mDNSResponder */
7282
7283 #if MDNSRESPONDER_BTMM_SUPPORT
7284 mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname)
7285 {
7286 struct ifaddrs *ifa;
7287 struct ifaddrs *ifaddrs;
7288 mDNSAddr addr;
7289
7290 if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;}
7291
7292 if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;}
7293
7294 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
7295 {
7296 if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
7297 continue;
7298 if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
7299 continue;
7300 if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
7301 {
7302 LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
7303 continue;
7304 }
7305 if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6))
7306 {
7307 LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr);
7308 break;
7309 }
7310 }
7311 freeifaddrs(ifaddrs);
7312 return ifa != NULL;
7313 }
7314
7315 mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf)
7316 {
7317 mDNSv6Addr retVal;
7318 struct addrinfo hints;
7319 struct addrinfo *res0;
7320
7321 memset(&hints, 0, sizeof(hints));
7322 hints.ai_family = AF_INET6;
7323 hints.ai_flags = AI_NUMERICHOST;
7324
7325 int err = getaddrinfo(buf, NULL, &hints, &res0);
7326 if (err)
7327 return zerov6Addr;
7328
7329 retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr;
7330
7331 freeaddrinfo(res0);
7332
7333 return retVal;
7334 }
7335
7336 mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict()
7337 {
7338 CFDictionaryRef connd = NULL;
7339 CFDictionaryRef BTMMDict = NULL;
7340
7341 connd = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BTMMConnectivity);
7342 if (!connd)
7343 {
7344 LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
7345 goto end;
7346 }
7347
7348 BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
7349 if (!BTMMDict)
7350 {
7351 LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
7352 goto end;
7353 }
7354
7355 // Non-dictionary is treated as non-existent dictionary
7356 if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
7357 {
7358 BTMMDict = NULL;
7359 LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
7360 goto end;
7361 }
7362
7363 CFRetain(BTMMDict);
7364
7365 end:
7366 if (connd) CFRelease(connd);
7367
7368 return BTMMDict;
7369 }
7370
7371 #define MAX_IPV6_TEXTUAL 40
7372
7373 mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey)
7374 {
7375 mDNSv6Addr retVal = zerov6Addr;
7376 CFTypeRef string = NULL;
7377 char ifname[IFNAMSIZ];
7378 char address[MAX_IPV6_TEXTUAL];
7379
7380 if (!BTMMDict)
7381 return zerov6Addr;
7382
7383 if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string))
7384 {
7385 LogInfo("ParseBackToMyMacAddr: interface key does not exist");
7386 return zerov6Addr;
7387 }
7388
7389 if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8))
7390 {
7391 LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
7392 return zerov6Addr;
7393 }
7394
7395 if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string))
7396 {
7397 LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
7398 return zerov6Addr;
7399 }
7400
7401 if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8))
7402 {
7403 LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
7404 return zerov6Addr;
7405 }
7406
7407 retVal = IPv6AddressFromString(address);
7408 LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal);
7409
7410 if (mDNSIPv6AddressIsZero(retVal))
7411 return zerov6Addr;
7412
7413 if (!IPv6AddressIsOnInterface(retVal, ifname))
7414 {
7415 LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname);
7416 return zerov6Addr;
7417 }
7418
7419 return retVal;
7420 }
7421
7422 mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict)
7423 {
7424 CFTypeRef zones = NULL;
7425
7426 if (!BTMMDict)
7427 return NULL;
7428
7429 if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones))
7430 {
7431 LogInfo("CopyBTMMZones: Zones key does not exist");
7432 return NULL;
7433 }
7434
7435 return zones;
7436 }
7437
7438 mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info)
7439 {
7440 mDNSv6Addr addr = zerov6Addr;
7441 char buffer[MAX_ESCAPED_DOMAIN_NAME];
7442 CFStringRef domain = NULL;
7443 CFTypeRef theZone = NULL;
7444
7445 if (!zones)
7446 return addr;
7447
7448 ConvertDomainNameToCString(&info->domain, buffer);
7449 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
7450 if (!domain)
7451 return addr;
7452
7453 if (CFDictionaryGetValueIfPresent(zones, domain, &theZone))
7454 addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address"));
7455
7456 CFRelease(domain);
7457
7458 return addr;
7459 }
7460
7461 mDNSlocal void SetupBackToMyMacInnerAddresses(CFDictionaryRef BTMMDict)
7462 {
7463 mDNS *const m = &mDNSStorage;
7464 DomainAuthInfo* info;
7465 CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
7466 mDNSv6Addr newAddr;
7467
7468 for (info = m->AuthInfoList; info; info = info->next)
7469 {
7470 if (!info->AutoTunnel)
7471 continue;
7472
7473 newAddr = ParseBackToMyMacZone(zones, info);
7474
7475 if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress))
7476 continue;
7477
7478 info->AutoTunnelInnerAddress = newAddr;
7479 DeregisterAutoTunnelHostRecord(m, info);
7480 UpdateAutoTunnelHostRecord(m, info);
7481 UpdateAutoTunnelDomainStatus(info);
7482 }
7483 }
7484
7485 // MUST be called holding the lock
7486 mDNSlocal void ProcessConndConfigChanges(void)
7487 {
7488 mDNS *const m = &mDNSStorage;
7489 CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
7490 if (!dict)
7491 LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
7492 mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
7493
7494 LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
7495
7496 SetupBackToMyMacInnerAddresses(dict);
7497
7498 if (dict) CFRelease(dict);
7499
7500 if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr))
7501 {
7502 m->AutoTunnelRelayAddr = relayAddr;
7503
7504 DomainAuthInfo* info;
7505 for (info = m->AuthInfoList; info; info = info->next)
7506 if (info->AutoTunnel)
7507 {
7508 DeregisterAutoTunnel6Record(m, info);
7509 UpdateAutoTunnel6Record(m, info);
7510 UpdateAutoTunnelDomainStatus(info);
7511 }
7512
7513 // Determine whether we need racoon to accept incoming connections
7514 UpdateAnonymousRacoonConfig(m);
7515 }
7516
7517 // If awacsd crashes or exits for some reason, restart it
7518 UpdateBTMMRelayConnection(m);
7519 }
7520 #endif // MDNSRESPONDER_BTMM_SUPPORT
7521
7522 mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
7523 {
7524 DNSServer *s;
7525 // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
7526 for (s = m->DNSServers; s; s = s->next)
7527 {
7528 if (s->addr.ip.v4.b[0] == 17)
7529 {
7530 LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s->domain.c, &s->addr);
7531 return mDNStrue;
7532 }
7533 }
7534 return mDNSfalse;
7535 }
7536
7537 // Called with KQueueLock & mDNS lock
7538 // SetNetworkChanged is allowed to shorten (but not extend) the pause while we wait for configuration changes to settle
7539 mDNSlocal void SetNetworkChanged(mDNSs32 delay)
7540 {
7541 mDNS *const m = &mDNSStorage;
7542 mDNS_CheckLock(m);
7543 if (!m->NetworkChanged || m->NetworkChanged - NonZeroTime(m->timenow + delay) > 0)
7544 {
7545 m->NetworkChanged = NonZeroTime(m->timenow + delay);
7546 LogInfo("SetNetworkChanged: Scheduling in %d ticks", delay);
7547 }
7548 else
7549 LogInfo("SetNetworkChanged: *NOT* increasing delay from %d to %d", m->NetworkChanged - m->timenow, delay);
7550 }
7551
7552 // Called with KQueueLock & mDNS lock
7553 mDNSlocal void SetKeyChainTimer(mDNSs32 delay)
7554 {
7555 mDNS *const m = &mDNSStorage;
7556 // If it's not set or it needs to happen sooner than when it's currently set
7557 if (!m->p->KeyChainTimer || m->p->KeyChainTimer - NonZeroTime(m->timenow + delay) > 0)
7558 {
7559 m->p->KeyChainTimer = NonZeroTime(m->timenow + delay);
7560 LogInfo("SetKeyChainTimer: %d", delay);
7561 }
7562 }
7563
7564 mDNSexport void mDNSMacOSXNetworkChanged(void)
7565 {
7566 mDNS *const m = &mDNSStorage;
7567 LogInfo("*** Network Configuration Change *** %d ticks late%s",
7568 m->NetworkChanged ? mDNS_TimeNow(m) - m->NetworkChanged : 0,
7569 m->NetworkChanged ? "" : " (no scheduled configuration change)");
7570 m->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
7571
7572 // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring
7573 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
7574 if (InfoSocket > 0)
7575 {
7576 mDNSBool tentative = mDNSfalse;
7577 struct ifaddrs *ifa = myGetIfAddrs(1);
7578 while (ifa)
7579 {
7580 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6)
7581 {
7582 struct in6_ifreq ifr6;
7583 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
7584 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
7585 ifr6.ifr_addr = *(struct sockaddr_in6 *)ifa->ifa_addr;
7586 // We need to check for IN6_IFF_TENTATIVE here, not IN6_IFF_NOTREADY, because
7587 // IN6_IFF_NOTREADY includes both IN6_IFF_TENTATIVE and IN6_IFF_DUPLICATED addresses.
7588 // We can expect that an IN6_IFF_TENTATIVE address will shortly become ready,
7589 // but an IN6_IFF_DUPLICATED address may not.
7590 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
7591 {
7592 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
7593 {
7594 LogInfo("*** Network Configuration Change *** IPv6 address %.16a TENTATIVE, will retry", &ifr6.ifr_addr.sin6_addr);
7595 tentative = mDNStrue;
7596 // no need to check other interfaces if we already found out that one interface is TENTATIVE
7597 break;
7598 }
7599 }
7600 }
7601 ifa = ifa->ifa_next;
7602 }
7603 close(InfoSocket);
7604 if (tentative)
7605 {
7606 mDNS_Lock(m);
7607 SetNetworkChanged(mDNSPlatformOneSecond / 2);
7608 mDNS_Unlock(m);
7609 return;
7610 }
7611 LogInfo("*** Network Configuration Change *** No IPv6 address TENTATIVE, will continue");
7612 }
7613
7614 mDNSs32 utc = mDNSPlatformUTC();
7615 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
7616 m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
7617 MarkAllInterfacesInactive(utc);
7618 UpdateInterfaceList(utc);
7619 ClearInactiveInterfaces(utc);
7620 SetupActiveInterfaces(utc);
7621 ReorderInterfaceList();
7622
7623 #if APPLE_OSX_mDNSResponder
7624 #if !TARGET_OS_EMBEDDED
7625 #if MDNSRESPONDER_BTMM_SUPPORT
7626 mDNS_Lock(m);
7627 ProcessConndConfigChanges();
7628 mDNS_Unlock(m);
7629 #endif
7630
7631 // Scan to find client tunnels whose questions have completed,
7632 // but whose local inner/outer addresses have changed since the tunnel was set up
7633 ClientTunnel *p;
7634 for (p = m->TunnelClients; p; p = p->next)
7635 if (p->q.ThisQInterval < 0)
7636 {
7637 DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname);
7638 if (!info)
7639 {
7640 LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c);
7641 AutoTunnelSetKeys(p, mDNSfalse);
7642 }
7643 else
7644 {
7645 mDNSv6Addr inner = info->AutoTunnelInnerAddress;
7646
7647 if (!mDNSIPPortIsZero(p->rmt_outer_port))
7648 {
7649 mDNSAddr tmpSrc = zeroAddr;
7650 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
7651 tmpDst.ip.v4 = p->rmt_outer;
7652 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
7653 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7654 !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
7655 {
7656 AutoTunnelSetKeys(p, mDNSfalse);
7657 p->loc_inner = inner;
7658 p->loc_outer = tmpSrc.ip.v4;
7659 AutoTunnelSetKeys(p, mDNStrue);
7660 }
7661 }
7662 else
7663 {
7664 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7665 !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
7666 {
7667 AutoTunnelSetKeys(p, mDNSfalse);
7668 p->loc_inner = inner;
7669 p->loc_outer6 = m->AutoTunnelRelayAddr;
7670 AutoTunnelSetKeys(p, mDNStrue);
7671 }
7672 }
7673 }
7674 }
7675 #endif //!TARGET_OS_EMBEDDED
7676
7677 SetSPS(m);
7678
7679 NetworkInterfaceInfoOSX *i;
7680 for (i = m->p->InterfaceList; i; i = i->next)
7681 {
7682 if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
7683 {
7684 if (i->BPF_fd >= 0 && CountProxyTargets(i, mDNSNULL, mDNSNULL) == 0)
7685 CloseBPF(i);
7686 }
7687 else // else, we're Sleep Proxy Server; open BPF fds
7688 {
7689 if (i->Exists && (i->Registered == i) && SPSInterface(i) && i->BPF_fd == -1)
7690 {
7691 LogMsg("%s mDNSMacOSXNetworkChanged: requesting BPF", i->ifinfo.ifname);
7692 i->BPF_fd = -2;
7693 mDNSRequestBPF();
7694 }
7695 }
7696 }
7697
7698 #endif // APPLE_OSX_mDNSResponder
7699
7700 uDNS_SetupDNSConfig(m);
7701 mDNS_ConfigChanged(m);
7702
7703 if (IsAppleNetwork(m) != mDNS_McastTracingEnabled)
7704 {
7705 mDNS_McastTracingEnabled = mDNS_McastTracingEnabled ? mDNSfalse : mDNStrue;
7706 LogInfo("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
7707 UpdateDebugState();
7708 }
7709
7710 }
7711
7712 // Copy the fourth slash-delimited element from either:
7713 // State:/Network/Interface/<bsdname>/IPv4
7714 // or
7715 // Setup:/Network/Service/<servicename>/Interface
7716 mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
7717 {
7718 CFArrayRef a;
7719 CFStringRef name = NULL;
7720
7721 a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
7722 if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
7723 if (a != NULL) CFRelease(a);
7724
7725 return name;
7726 }
7727
7728 // Whether a key from a network change notification corresponds to
7729 // an IP service that is explicitly configured for IPv4 Link Local
7730 mDNSlocal int ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
7731 {
7732 CFDictionaryRef dict = NULL;
7733 CFMutableArrayRef a;
7734 const void **keys = NULL, **vals = NULL;
7735 CFStringRef pattern = NULL;
7736 int i, ic, j, jc;
7737 int found = 0;
7738
7739 jc = CFArrayGetCount(inkeys);
7740 if (!jc) goto done;
7741
7742 a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7743 if (a == NULL) goto done;
7744
7745 // Setup:/Network/Service/[^/]+/Interface
7746 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
7747 if (pattern == NULL) goto done;
7748 CFArrayAppendValue(a, pattern);
7749 CFRelease(pattern);
7750
7751 // Setup:/Network/Service/[^/]+/IPv4
7752 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
7753 if (pattern == NULL) goto done;
7754 CFArrayAppendValue(a, pattern);
7755 CFRelease(pattern);
7756
7757 dict = SCDynamicStoreCopyMultiple(NULL, NULL, a);
7758 CFRelease(a);
7759
7760 if (!dict)
7761 {
7762 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
7763 goto done;
7764 }
7765
7766 ic = CFDictionaryGetCount(dict);
7767 vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7768 keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7769 CFDictionaryGetKeysAndValues(dict, keys, vals);
7770
7771 // For each key we were given...
7772 for (j = 0; j < jc; j++)
7773 {
7774 CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
7775 CFStringRef ifname = NULL;
7776
7777 char buf[256];
7778
7779 // It would be nice to use a regex here
7780 if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
7781
7782 if ((ifname = CopyNameFromKey(key)) == NULL) continue;
7783 if (mDNS_LoggingEnabled)
7784 {
7785 if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7786 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
7787 }
7788
7789 // Loop over the interfaces to find matching the ifname, and see if that one has kSCValNetIPv4ConfigMethodLinkLocal
7790 for (i = 0; i < ic; i++)
7791 {
7792 CFDictionaryRef ipv4dict;
7793 CFStringRef name;
7794 CFStringRef serviceid;
7795 CFStringRef configmethod;
7796
7797 if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
7798
7799 if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
7800
7801 if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
7802
7803 if (!CFEqual(ifname, name)) continue;
7804
7805 if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
7806 if (mDNS_LoggingEnabled)
7807 {
7808 if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7809 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
7810 }
7811
7812 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
7813 CFRelease(serviceid);
7814 if (pattern == NULL) continue;
7815
7816 ipv4dict = CFDictionaryGetValue(dict, pattern);
7817 CFRelease(pattern);
7818 if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
7819
7820 configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
7821 if (!configmethod) continue;
7822
7823 if (mDNS_LoggingEnabled)
7824 {
7825 if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7826 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
7827 }
7828
7829 if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found++; break; }
7830 }
7831
7832 CFRelease(ifname);
7833 }
7834
7835 done:
7836 if (vals != NULL) mDNSPlatformMemFree(vals);
7837 if (keys != NULL) mDNSPlatformMemFree(keys);
7838 if (dict != NULL) CFRelease(dict);
7839
7840 return found;
7841 }
7842
7843 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
7844 {
7845 (void)store; // Parameter not used
7846 mDNS *const m = (mDNS *const)context;
7847 KQueueLock();
7848 mDNS_Lock(m);
7849
7850 //mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
7851 const mDNSs32 delay = (mDNSPlatformOneSecond + 39) / 40; // 25 ms delay
7852
7853 const int c = CFArrayGetCount(changedKeys); // Count changes
7854 CFRange range = { 0, c };
7855 const int c_host = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
7856 const int c_comp = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
7857 const int c_udns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0);
7858 const int c_ddns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
7859 #if MDNSRESPONDER_BTMM_SUPPORT
7860 const int c_btmm = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac ) != 0);
7861 #else
7862 const int c_btmm = 0;
7863 #endif
7864 const int c_v4ll = ChangedKeysHaveIPv4LL(changedKeys);
7865 int c_fast = 0;
7866
7867 // Do immediate network changed processing for "p2p*" interfaces and
7868 // for interfaces with the IFEF_DIRECTLINK or IFEF_AWDL flag set or association with a CarPlay
7869 // hosted SSID.
7870 {
7871 CFArrayRef labels;
7872 CFIndex n;
7873 for (int i = 0; i < c; i++)
7874 {
7875 CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i);
7876
7877 // Only look at keys with prefix "State:/Network/Interface/"
7878 if (!CFStringHasPrefix(key, NetworkChangedKey_StateInterfacePrefix))
7879 continue;
7880
7881 // And suffix "IPv6" or "IPv4".
7882 if (!CFStringHasSuffix(key, kSCEntNetIPv6) && !CFStringHasSuffix(key, kSCEntNetIPv4))
7883 continue;
7884
7885 labels = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
7886 if (labels == NULL)
7887 break;
7888 n = CFArrayGetCount(labels);
7889
7890 // Interface changes will have keys of the form:
7891 // State:/Network/Interface/<interfaceName>/IPv6
7892 // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
7893 if (n == 5)
7894 {
7895 char buf[256];
7896
7897 // The 4th label (index = 3) should be the interface name.
7898 if (CFStringGetCString(CFArrayGetValueAtIndex(labels, 3), buf, sizeof(buf), kCFStringEncodingUTF8)
7899 && (strstr(buf, "p2p") || (getExtendedFlags(buf) & (IFEF_DIRECTLINK | IFEF_AWDL)) || IsCarPlaySSID(buf)))
7900 {
7901 LogInfo("NetworkChanged: interface %s qualifies for reduced change handling delay", buf);
7902 c_fast++;
7903 CFRelease(labels);
7904 break;
7905 }
7906 }
7907 CFRelease(labels);
7908 }
7909 }
7910
7911 //if (c && c - c_host - c_comp - c_udns - c_ddns - c_btmm - c_v4ll - c_fast == 0)
7912 // delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
7913
7914 if (mDNS_LoggingEnabled)
7915 {
7916 int i;
7917 for (i=0; i<c; i++)
7918 {
7919 char buf[256];
7920 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7921 LogInfo("*** Network Configuration Change *** SC key: %s", buf);
7922 }
7923 LogInfo("*** Network Configuration Change *** %d change%s %s%s%s%s%s%s%sdelay %d%s",
7924 c, c>1 ? "s" : "",
7925 c_host ? "(Local Hostname) " : "",
7926 c_comp ? "(Computer Name) " : "",
7927 c_udns ? "(DNS) " : "",
7928 c_ddns ? "(DynamicDNS) " : "",
7929 c_btmm ? "(BTMM) " : "",
7930 c_v4ll ? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
7931 c_fast ? "(P2P/IFEF_DIRECTLINK/IFEF_AWDL/IsCarPlaySSID) " : "",
7932 delay,
7933 (c_ddns || c_btmm) ? " + SetKeyChainTimer" : "");
7934 }
7935
7936 SetNetworkChanged(delay);
7937
7938 // Other software might pick up these changes to register or browse in WAB or BTMM domains,
7939 // so in order for secure updates to be made to the server, make sure to read the keychain and
7940 // setup the DomainAuthInfo before handing the network change.
7941 // If we don't, then we will first try to register services in the clear, then later setup the
7942 // DomainAuthInfo, which is incorrect.
7943 if (c_ddns || c_btmm)
7944 SetKeyChainTimer(delay);
7945
7946 // Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
7947
7948 mDNS_Unlock(m);
7949 KQueueUnlock("NetworkChanged");
7950 }
7951
7952 #if APPLE_OSX_mDNSResponder
7953 mDNSlocal void RefreshSPSStatus(const void *key, const void *value, void *context)
7954 {
7955 (void)context;
7956 char buf[IFNAMSIZ];
7957
7958 CFStringRef ifnameStr = (CFStringRef)key;
7959 CFArrayRef array = (CFArrayRef)value;
7960 if (!CFStringGetCString(ifnameStr, buf, sizeof(buf), kCFStringEncodingUTF8))
7961 buf[0] = 0;
7962
7963 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf, CFArrayGetCount(array));
7964 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, buf, value);
7965 }
7966 #endif
7967
7968 mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
7969 {
7970 mDNS *const m = (mDNS *const)info;
7971 (void)store;
7972
7973 KQueueLock(); // serialize with KQueueLoop()
7974
7975 LogInfo("DynamicStoreReconnected: Reconnected");
7976
7977 // State:/Network/MulticastDNS
7978 SetLocalDomains();
7979
7980 // State:/Network/DynamicDNS
7981 if (m->FQDN.c[0])
7982 mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
7983
7984 // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
7985 // as we receive network change notifications and thus not necessary. But we leave it here
7986 // so that if things are done differently in the future, this code still works.
7987
7988 // State:/Network/PrivateDNS
7989 if (privateDnsArray)
7990 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
7991
7992 #if APPLE_OSX_mDNSResponder
7993 // State:/Network/BackToMyMac
7994 UpdateAutoTunnelDomainStatuses(m);
7995
7996 // State:/Network/Interface/en0/SleepProxyServers
7997 if (spsStatusDict)
7998 CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
7999 #endif
8000 KQueueUnlock("DynamicStoreReconnected");
8001 }
8002
8003 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
8004 {
8005 mStatus err = -1;
8006 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
8007 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
8008 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8009 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
8010 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
8011 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8012
8013 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
8014 if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
8015
8016 CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
8017 CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
8018 CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
8019 CFArrayAppendValue(keys, NetworkChangedKey_Computername);
8020 CFArrayAppendValue(keys, NetworkChangedKey_DNS);
8021 CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
8022 CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings);
8023 #if MDNSRESPONDER_BTMM_SUPPORT
8024 CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
8025 CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
8026 #endif
8027 CFArrayAppendValue(patterns, pattern1);
8028 CFArrayAppendValue(patterns, pattern2);
8029 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
8030 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
8031 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
8032
8033 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8034 if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()))
8035 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8036 #else
8037 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
8038 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8039 CFRunLoopAddSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode);
8040 #endif
8041 SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected);
8042 m->p->Store = store;
8043 err = 0;
8044 goto exit;
8045
8046 error:
8047 if (store) CFRelease(store);
8048
8049 exit:
8050 if (patterns) CFRelease(patterns);
8051 if (pattern2) CFRelease(pattern2);
8052 if (pattern1) CFRelease(pattern1);
8053 if (keys) CFRelease(keys);
8054
8055 return(err);
8056 }
8057
8058 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8059
8060 mDNSlocal void mDNSSetPacketFilterRules(char * ifname, const ResourceRecord *const excludeRecord)
8061 {
8062 mDNS *const m = &mDNSStorage;
8063 AuthRecord *rr;
8064 pfArray_t portArray;
8065 pfArray_t protocolArray;
8066 uint32_t count = 0;
8067
8068 for (rr = m->ResourceRecords; rr; rr=rr->next)
8069 {
8070 if ((rr->resrec.rrtype == kDNSServiceType_SRV)
8071 && ((rr->ARType == AuthRecordAnyIncludeP2P) || (rr->ARType == AuthRecordAnyIncludeAWDLandP2P)))
8072 {
8073 const mDNSu8 *p;
8074
8075 if (count >= PFPortArraySize)
8076 {
8077 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize, ARDisplayString(m, rr));
8078 continue;
8079 }
8080
8081 if (excludeRecord && IdenticalResourceRecord(&rr->resrec, excludeRecord))
8082 {
8083 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m, rr));
8084 continue;
8085 }
8086
8087 LogMsg("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr));
8088
8089 portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger;
8090
8091 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
8092 p = rr->resrec.name->c;
8093
8094 // Skip to App Protocol
8095 if (p[0])
8096 p += 1 + p[0];
8097
8098 // Skip to Transport Protocol
8099 if (p[0])
8100 p += 1 + p[0];
8101
8102 if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp"))
8103 {
8104 protocolArray[count] = IPPROTO_TCP;
8105 }
8106 else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp"))
8107 {
8108 protocolArray[count] = IPPROTO_UDP;
8109 }
8110 else
8111 {
8112 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
8113 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m, rr));
8114 return;
8115 }
8116 count++;
8117 }
8118 }
8119 mDNSPacketFilterControl(PF_SET_RULES, ifname, count, portArray, protocolArray);
8120 }
8121
8122 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
8123 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8124 {
8125 mDNS *const m = &mDNSStorage;
8126
8127 NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
8128 while (intf)
8129 {
8130 if (strncmp(intf->ifname, "p2p", 3) == 0)
8131 {
8132 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname);
8133 mDNSSetPacketFilterRules(intf->ifname, excludeRecord);
8134 break;
8135 }
8136 intf = GetFirstActiveInterface(intf->next);
8137 }
8138 }
8139
8140 #else // !TARGET_OS_EMBEDDED
8141
8142 // Currently no packet filter setup required on embedded platforms.
8143 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8144 {
8145 (void) excludeRecord; // unused
8146 }
8147
8148 #endif // !TARGET_OS_EMBEDDED
8149
8150 // AWDL should no longer generate KEV_DL_MASTER_ELECTED events, so just log a message if we receive one.
8151 mDNSlocal void newMasterElected(struct net_event_data * ptr)
8152 {
8153 char ifname[IFNAMSIZ];
8154 mDNSu32 interfaceIndex;
8155
8156 snprintf(ifname, IFNAMSIZ, "%s%d", ptr->if_name, ptr->if_unit);
8157 interfaceIndex = if_nametoindex(ifname);
8158
8159 if (!interfaceIndex)
8160 {
8161 LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname);
8162 return;
8163 }
8164
8165 LogInfo("newMasterElected: KEV_DL_MASTER_ELECTED received on ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
8166 }
8167
8168 // An ssth array of all zeroes indicates the peer has no services registered.
8169 mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op)
8170 {
8171 int i;
8172 int *intp = (int *) op->ssth;
8173
8174 // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
8175 // it's not, print an error message and return false so that
8176 // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
8177 // is received.
8178 if (MAX_SSTH_SIZE % sizeof(int))
8179 {
8180 LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE);
8181 return mDNSfalse;
8182 }
8183
8184 for (i = 0; i < (int)(MAX_SSTH_SIZE / sizeof(int)); i++, intp++)
8185 {
8186 if (*intp)
8187 return mDNSfalse;
8188 }
8189 return mDNStrue;
8190 }
8191
8192 // Mark records from this peer for deletion from the cache.
8193 mDNSlocal void removeCachedPeerRecords(mDNSu32 ifindex, mDNSAddr *ap, bool purgeNow)
8194 {
8195 mDNS *const m = &mDNSStorage;
8196 mDNSu32 slot;
8197 CacheGroup *cg;
8198 CacheRecord *cr;
8199 NetworkInterfaceInfoOSX *infoOSX;
8200 mDNSInterfaceID InterfaceID;
8201
8202 // Using mDNSPlatformInterfaceIDfromInterfaceIndex() would lead to recursive
8203 // locking issues, see: <rdar://problem/21332983>
8204 infoOSX = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
8205 if (!infoOSX)
8206 {
8207 LogInfo("removeCachedPeerRecords: interface %d not yet active", ifindex);
8208 return;
8209 }
8210 InterfaceID = infoOSX->ifinfo.InterfaceID;
8211
8212 FORALL_CACHERECORDS(slot, cg, cr)
8213 {
8214 if ((InterfaceID == cr->resrec.InterfaceID) && mDNSSameAddress(ap, & cr->sourceAddress))
8215 {
8216 LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
8217 DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c);
8218
8219 if (purgeNow)
8220 mDNS_PurgeCacheResourceRecord(m, cr);
8221 else
8222 mDNS_Reconfirm_internal(m, cr, 0); // use default minimum reconfirm time
8223 }
8224 }
8225 }
8226
8227 // Handle KEV_DL_NODE_PRESENCE event.
8228 mDNSlocal void nodePresence(struct kev_dl_node_presence * p)
8229 {
8230 struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info;
8231
8232 LogInfo("nodePresence: IPv6 address: %.16a, SUI %d", p->sin6_node_address.sin6_addr.s6_addr, op->SUI);
8233
8234 // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
8235 // all zeroes when a node is present and has no services registered.
8236 if (allZeroSSTH(op))
8237 {
8238 mDNSAddr peerAddr;
8239
8240 peerAddr.type = mDNSAddrType_IPv6;
8241 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8242
8243 LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer");
8244 removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, false);
8245 }
8246 }
8247
8248 // Handle KEV_DL_NODE_ABSENCE event.
8249 mDNSlocal void nodeAbsence(struct kev_dl_node_absence * p)
8250 {
8251 mDNSAddr peerAddr;
8252
8253 peerAddr.type = mDNSAddrType_IPv6;
8254 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8255
8256 LogInfo("nodeAbsence: immediately purge cached records from %.16a", p->sin6_node_address.sin6_addr.s6_addr);
8257 removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, true);
8258 }
8259
8260 mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context, __unused mDNSBool encounteredEOF)
8261 {
8262 mDNS *const m = (mDNS *const)context;
8263
8264 mDNS_Lock(m);
8265
8266 struct { struct kern_event_msg k; char extra[256]; } msg;
8267 int bytes = recv(s1, &msg, sizeof(msg), 0);
8268 if (bytes < 0)
8269 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
8270 else
8271 {
8272 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
8273 bytes, msg.k.total_size,
8274 msg.k.vendor_code, msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?",
8275 msg.k.kev_class, msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
8276 msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?",
8277 msg.k.id, msg.k.event_code,
8278 msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" :
8279 msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" :
8280 msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" :
8281 msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" :
8282 msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" :
8283 msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" :
8284 msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" :
8285 msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" :
8286 msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" :
8287 msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" :
8288 msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" :
8289 msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" :
8290 msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" :
8291 msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" :
8292 msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" :
8293 msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
8294 msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" :
8295 msg.k.event_code == KEV_DL_IF_IDLE_ROUTE_REFCNT ? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
8296 msg.k.event_code == KEV_DL_IFCAP_CHANGED ? "KEV_DL_IFCAP_CHANGED" :
8297 msg.k.event_code == KEV_DL_LINK_QUALITY_METRIC_CHANGED ? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" :
8298 msg.k.event_code == KEV_DL_NODE_PRESENCE ? "KEV_DL_NODE_PRESENCE" :
8299 msg.k.event_code == KEV_DL_NODE_ABSENCE ? "KEV_DL_NODE_ABSENCE" :
8300 msg.k.event_code == KEV_DL_MASTER_ELECTED ? "KEV_DL_MASTER_ELECTED" :
8301 "?");
8302
8303 if (msg.k.event_code == KEV_DL_NODE_PRESENCE)
8304 nodePresence((struct kev_dl_node_presence *) &msg.k.event_data);
8305
8306 if (msg.k.event_code == KEV_DL_NODE_ABSENCE)
8307 nodeAbsence((struct kev_dl_node_absence *) &msg.k.event_data);
8308
8309 if (msg.k.event_code == KEV_DL_MASTER_ELECTED)
8310 newMasterElected((struct net_event_data *) &msg.k.event_data);
8311
8312 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
8313 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
8314 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
8315 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
8316 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
8317
8318 if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
8319 SetNetworkChanged(mDNSPlatformOneSecond * 2);
8320
8321 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8322
8323 // For p2p interfaces, need to open the advertised service port in the firewall.
8324 if (msg.k.event_code == KEV_DL_IF_ATTACHED)
8325 {
8326 struct net_event_data * p;
8327 p = (struct net_event_data *) &msg.k.event_data;
8328
8329 if (strncmp(p->if_name, "p2p", 3) == 0)
8330 {
8331 char ifname[IFNAMSIZ];
8332 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8333
8334 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8335
8336 mDNSSetPacketFilterRules(ifname, NULL);
8337 }
8338 }
8339
8340 // For p2p interfaces, need to clear the firewall rules on interface detach
8341 if (msg.k.event_code == KEV_DL_IF_DETACHED)
8342 {
8343 struct net_event_data * p;
8344 p = (struct net_event_data *) &msg.k.event_data;
8345
8346 if (strncmp(p->if_name, "p2p", 3) == 0)
8347 {
8348 pfArray_t portArray, protocolArray; // not initialized since count is 0 for PF_CLEAR_RULES
8349 char ifname[IFNAMSIZ];
8350 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8351
8352 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8353
8354 mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
8355 }
8356 }
8357 #endif // !TARGET_OS_EMBEDDED
8358
8359 }
8360
8361 mDNS_Unlock(m);
8362 }
8363
8364 mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
8365 {
8366 m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
8367 if (m->p->SysEventNotifier < 0)
8368 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); }
8369
8370 struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
8371 int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
8372 if (err < 0)
8373 {
8374 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno));
8375 close(m->p->SysEventNotifier);
8376 m->p->SysEventNotifier = -1;
8377 return(mStatus_UnknownErr);
8378 }
8379
8380 m->p->SysEventKQueue.KQcallback = SysEventCallBack;
8381 m->p->SysEventKQueue.KQcontext = m;
8382 m->p->SysEventKQueue.KQtask = "System Event Notifier";
8383 KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
8384
8385 return(mStatus_NoError);
8386 }
8387
8388 #ifndef NO_SECURITYFRAMEWORK
8389 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
8390 {
8391 LogInfo("*** Keychain Changed ***");
8392 mDNS *const m = (mDNS *const)context;
8393 SecKeychainRef skc;
8394 OSStatus err = SecKeychainCopyDefault(&skc);
8395 if (!err)
8396 {
8397 if (info->keychain == skc)
8398 {
8399 // 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
8400 mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
8401 if (!relevant)
8402 {
8403 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
8404 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
8405 SecKeychainAttributeList *a = NULL;
8406 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
8407 if (!err)
8408 {
8409 relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
8410 (a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))));
8411 #if MDNSRESPONDER_BTMM_SUPPORT
8412 if (!relevant && (a->attr[1].length >= mDNSPlatformStrLen(btmmprefix)) && !strncasecmp(a->attr[1].data, btmmprefix, mDNSPlatformStrLen(btmmprefix)))
8413 {
8414 relevant = mDNStrue;
8415 }
8416 #endif
8417 SecKeychainItemFreeAttributesAndData(a, NULL);
8418 }
8419 }
8420 if (relevant)
8421 {
8422 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
8423 keychainEvent,
8424 keychainEvent == kSecAddEvent ? "kSecAddEvent" :
8425 keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
8426 keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
8427 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
8428 KQueueLock();
8429 mDNS_Lock(m);
8430
8431 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
8432 // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
8433 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
8434 //
8435 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
8436 // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
8437 // a one second delay is ok, as we'll still converge to correctness, and there's no race
8438 // condition between the RegistrationDomain and the DomainAuthInfo.
8439 //
8440 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
8441 // the timer here, as it will not get set by NetworkChanged().
8442 SetKeyChainTimer(mDNSPlatformOneSecond);
8443
8444 mDNS_Unlock(m);
8445 KQueueUnlock("KeychainChanged");
8446 }
8447 }
8448 CFRelease(skc);
8449 }
8450
8451 return 0;
8452 }
8453 #endif
8454
8455 mDNSlocal void PowerOn(mDNS *const m)
8456 {
8457 mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
8458
8459 if (m->p->WakeAtUTC)
8460 {
8461 long utc = mDNSPlatformUTC();
8462 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
8463 if (m->p->WakeAtUTC - utc > 30)
8464 {
8465 LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
8466 }
8467 else if (utc - m->p->WakeAtUTC > 30)
8468 {
8469 LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
8470 }
8471 else if (IsAppleTV())
8472 {
8473 LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC);
8474 }
8475 else
8476 {
8477 LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m->p->WakeAtUTC - utc);
8478 m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond;
8479 }
8480 }
8481
8482 // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
8483 // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
8484 // We will clear this assertion as soon as we think the mainenance activities are done.
8485 mDNSPlatformPreventSleep(DARK_WAKE_TIME, "mDNSResponder:maintenance");
8486
8487 }
8488
8489 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
8490 {
8491 mDNS *const m = (mDNS *const)refcon;
8492 KQueueLock();
8493 (void)service; // Parameter not used
8494 debugf("PowerChanged %X %lX", messageType, messageArgument);
8495
8496 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8497 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8498
8499 switch(messageType)
8500 {
8501 case kIOMessageCanSystemPowerOff: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
8502 case kIOMessageSystemWillPowerOff: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
8503 mDNSCoreMachineSleep(m, true);
8504 if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged();
8505 break;
8506 case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
8507 case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep"); break; // E0000270
8508 case kIOMessageSystemWillSleep: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
8509 mDNSCoreMachineSleep(m, true);
8510 break;
8511 case kIOMessageSystemWillNotSleep: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
8512 case kIOMessageSystemHasPoweredOn: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
8513 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
8514 if (m->SleepState)
8515 {
8516 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
8517 PowerOn(m);
8518 }
8519 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
8520 // the System Configuration Framework "network changed" event that we expect
8521 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
8522 mDNS_Lock(m);
8523 SetNetworkChanged(mDNSPlatformOneSecond * 2);
8524 mDNS_Unlock(m);
8525
8526 break;
8527 case kIOMessageSystemWillRestart: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
8528 case kIOMessageSystemWillPowerOn: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
8529
8530 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
8531 if (m->SleepState != SleepState_Sleeping)
8532 {
8533 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
8534 m->SleepState = SleepState_Sleeping;
8535 mDNSMacOSXNetworkChanged();
8536 }
8537 PowerOn(m);
8538 break;
8539 default: LogSPS("PowerChanged unknown message %X", messageType); break;
8540 }
8541
8542 if (messageType == kIOMessageSystemWillSleep)
8543 m->p->SleepCookie = (long)messageArgument;
8544 else if (messageType == kIOMessageCanSystemSleep)
8545 IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
8546
8547 KQueueUnlock("PowerChanged Sleep/Wake");
8548 }
8549
8550 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
8551 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
8552 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
8553 mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
8554 {
8555 mDNS *const m = (mDNS *const)refcon;
8556 KQueueLock();
8557 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
8558 connection, token, eventDescriptor,
8559 eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "",
8560 eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "",
8561 eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "",
8562 eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
8563 eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : "");
8564
8565 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8566 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8567
8568 if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
8569 {
8570 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
8571 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
8572 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
8573 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
8574 if (m->SleepLimit)
8575 {
8576 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8577 IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie);
8578 m->SleepLimit = 0;
8579 }
8580 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8581 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
8582 if (m->SleepState != SleepState_Awake)
8583 {
8584 PowerOn(m);
8585 // If the network notifications have already come before we got the wakeup, we ignored them and
8586 // in case we get no more, we need to trigger one.
8587 mDNS_Lock(m);
8588 SetNetworkChanged(mDNSPlatformOneSecond * 2);
8589 mDNS_Unlock(m);
8590 }
8591 IOPMConnectionAcknowledgeEvent(connection, token);
8592 }
8593 else
8594 {
8595 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
8596 // we should hear nothing more until we're told that the CPU has started executing again.
8597 if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
8598 //sleep(5);
8599 //mDNSMacOSXNetworkChanged(m);
8600 mDNSCoreMachineSleep(m, true);
8601 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
8602 m->p->SleepCookie = token;
8603 }
8604
8605 KQueueUnlock("SnowLeopardPowerChanged Sleep/Wake");
8606 }
8607 #endif
8608
8609 #if COMPILER_LIKES_PRAGMA_MARK
8610 #pragma mark -
8611 #pragma mark - /etc/hosts support
8612 #endif
8613
8614 // Implementation Notes
8615 //
8616 // As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
8617 // 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
8618 // them into a hash table. The implementation need to be able to do the following things efficiently
8619 //
8620 // 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
8621 // 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
8622 // 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
8623 // need to be able set the RRSet of a resource record to the first one in the list and also update when
8624 // one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
8625 // not a duplicate
8626 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
8627 //
8628 // CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
8629 // "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
8630 // of the core layer which does all of the above very efficiently
8631
8632 #define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
8633
8634 mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
8635 {
8636 (void)m; // unused
8637 (void)rr;
8638 (void)result;
8639 if (result == mStatus_MemFree)
8640 {
8641 LogInfo("FreeEtcHosts: %s", ARDisplayString(m, rr));
8642 freeL("etchosts", rr);
8643 }
8644 }
8645
8646 // Returns true on success and false on failure
8647 mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(const domainname *domain, const struct sockaddr *sa, const domainname *cname, char *ifname, AuthHash *auth)
8648 {
8649 AuthRecord *rr;
8650 mDNSu32 namehash;
8651 AuthGroup *ag;
8652 mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly;
8653 mDNSu16 rrtype;
8654
8655 if (!domain)
8656 {
8657 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
8658 return mDNSfalse;
8659 }
8660 if (!sa && !cname)
8661 {
8662 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
8663 return mDNSfalse;
8664 }
8665
8666 if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
8667 {
8668 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa->sa_family);
8669 return mDNSfalse;
8670 }
8671
8672
8673 if (ifname)
8674 {
8675 mDNSu32 ifindex = if_nametoindex(ifname);
8676 if (!ifindex)
8677 {
8678 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain->c, ifname);
8679 return mDNSfalse;
8680 }
8681 InterfaceID = (mDNSInterfaceID)(uintptr_t)ifindex;
8682 }
8683
8684 if (sa)
8685 rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA);
8686 else
8687 rrtype = kDNSType_CNAME;
8688
8689 // Check for duplicates. See whether we parsed an entry before like this ?
8690 namehash = DomainNameHashValue(domain);
8691 ag = AuthGroupForName(auth, namehash, domain);
8692 if (ag)
8693 {
8694 rr = ag->members;
8695 while (rr)
8696 {
8697 if (rr->resrec.rrtype == rrtype)
8698 {
8699 if (rrtype == kDNSType_A)
8700 {
8701 mDNSv4Addr ip;
8702 ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
8703 if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip))
8704 {
8705 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c);
8706 return mDNSfalse;
8707 }
8708 }
8709 else if (rrtype == kDNSType_AAAA)
8710 {
8711 mDNSv6Addr ip6;
8712 ip6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
8713 ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
8714 ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
8715 ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
8716 if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6))
8717 {
8718 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c);
8719 return mDNSfalse;
8720 }
8721 }
8722 else if (rrtype == kDNSType_CNAME)
8723 {
8724 if (SameDomainName(&rr->resrec.rdata->u.name, cname))
8725 {
8726 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname->c, domain->c);
8727 return mDNSfalse;
8728 }
8729 }
8730 }
8731 rr = rr->next;
8732 }
8733 }
8734 rr= mallocL("etchosts", sizeof(*rr));
8735 if (rr == NULL) return mDNSfalse;
8736 mDNSPlatformMemZero(rr, sizeof(*rr));
8737 mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
8738 AssignDomainName(&rr->namestorage, domain);
8739
8740 if (sa)
8741 {
8742 rr->resrec.rdlength = sa->sa_family == AF_INET ? sizeof(mDNSv4Addr) : sizeof(mDNSv6Addr);
8743 if (sa->sa_family == AF_INET)
8744 rr->resrec.rdata->u.ipv4.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
8745 else
8746 {
8747 rr->resrec.rdata->u.ipv6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
8748 rr->resrec.rdata->u.ipv6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
8749 rr->resrec.rdata->u.ipv6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
8750 rr->resrec.rdata->u.ipv6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
8751 }
8752 }
8753 else
8754 {
8755 rr->resrec.rdlength = DomainNameLength(cname);
8756 rr->resrec.rdata->u.name.c[0] = 0;
8757 AssignDomainName(&rr->resrec.rdata->u.name, cname);
8758 }
8759 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
8760 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
8761 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(&mDNSStorage, rr));
8762 InsertAuthRecord(&mDNSStorage, auth, rr);
8763 return mDNStrue;
8764 }
8765
8766 mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **name)
8767 {
8768 int i;
8769
8770 *name = NULL;
8771 for (i = start; i < length; i++)
8772 {
8773 if (buffer[i] == '#')
8774 return -1;
8775 if (buffer[i] != ' ' && buffer[i] != ',' && buffer[i] != '\t')
8776 {
8777 *name = &buffer[i];
8778
8779 // Found the start of a name, find the end and null terminate
8780 for (i++; i < length; i++)
8781 {
8782 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
8783 {
8784 buffer[i] = 0;
8785 break;
8786 }
8787 }
8788 return i;
8789 }
8790 }
8791 return -1;
8792 }
8793
8794 mDNSlocal void mDNSMacOSXParseEtcHostsLine(char *buffer, ssize_t length, AuthHash *auth)
8795 {
8796 int i;
8797 int ifStart = 0;
8798 char *ifname = NULL;
8799 domainname name1d;
8800 domainname name2d;
8801 char *name1;
8802 char *name2;
8803 int aliasIndex;
8804
8805 //Ignore leading whitespaces and tabs
8806 while (*buffer == ' ' || *buffer == '\t')
8807 {
8808 buffer++;
8809 length--;
8810 }
8811
8812 // Find the end of the address string
8813 for (i = 0; i < length; i++)
8814 {
8815 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t' || buffer[i] == '%')
8816 {
8817 if (buffer[i] == '%')
8818 ifStart = i + 1;
8819 buffer[i] = 0;
8820 break;
8821 }
8822 }
8823
8824 // Convert the address string to an address
8825 struct addrinfo hints;
8826 bzero(&hints, sizeof(hints));
8827 hints.ai_flags = AI_NUMERICHOST;
8828 struct addrinfo *gairesults = NULL;
8829 if (getaddrinfo(buffer, NULL, &hints, &gairesults) != 0)
8830 {
8831 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
8832 return;
8833 }
8834
8835 if (ifStart)
8836 {
8837 // Parse the interface
8838 ifname = &buffer[ifStart];
8839 for (i = ifStart + 1; i < length; i++)
8840 {
8841 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
8842 {
8843 buffer[i] = 0;
8844 break;
8845 }
8846 }
8847 }
8848
8849 i = EtcHostsParseOneName(i + 1, length, buffer, &name1);
8850 if (i == length)
8851 {
8852 // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
8853 if (!MakeDomainNameFromDNSNameString(&name1d, name1))
8854 {
8855 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
8856 freeaddrinfo(gairesults);
8857 return;
8858 }
8859 mDNSMacOSXCreateEtcHostsEntry(&name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
8860 }
8861 else if (i != -1)
8862 {
8863 domainname first;
8864 // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
8865 // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
8866 // doing the right thing.
8867
8868 if (!MakeDomainNameFromDNSNameString(&first, name1))
8869 {
8870 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
8871 freeaddrinfo(gairesults);
8872 return;
8873 }
8874 mDNSMacOSXCreateEtcHostsEntry(&first, gairesults->ai_addr, mDNSNULL, ifname, auth);
8875
8876 // /etc/hosts alias discussion:
8877 //
8878 // If the /etc/hosts has an entry like this
8879 //
8880 // ip_address cname [aliases...]
8881 // 1.2.3.4 sun star bright
8882 //
8883 // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
8884 // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
8885 //
8886 // To achieve this, we need to add the entry like this:
8887 //
8888 // sun A 1.2.3.4
8889 // star CNAME sun
8890 // bright CNAME sun
8891 //
8892 // We store the first name we parsed in "first" and add the address (A/AAAA) record.
8893 // Then we parse additional names adding CNAME records till we reach the end.
8894
8895 aliasIndex = 0;
8896 while (i < length)
8897 {
8898 // Continue to parse additional aliases until we reach end of the line and
8899 // for each "alias" parsed, add a CNAME record where "alias" points to the first "name".
8900 // See also /etc/hosts alias discussion above
8901
8902 i = EtcHostsParseOneName(i + 1, length, buffer, &name2);
8903
8904 if (name2)
8905 {
8906 if ((aliasIndex) && (*buffer == *name2))
8907 break; // break out of the loop if we wrap around
8908
8909 if (!MakeDomainNameFromDNSNameString(&name2d, name2))
8910 {
8911 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2);
8912 freeaddrinfo(gairesults);
8913 return;
8914 }
8915 // Ignore if it points to itself
8916 if (!SameDomainName(&first, &name2d))
8917 {
8918 if (!mDNSMacOSXCreateEtcHostsEntry(&name2d, mDNSNULL, &first, ifname, auth))
8919 {
8920 freeaddrinfo(gairesults);
8921 return;
8922 }
8923 }
8924 else
8925 {
8926 LogInfo("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names first %##s, name2 %##s", first.c, name2d.c);
8927 }
8928 aliasIndex++;
8929 }
8930 else if (!aliasIndex)
8931 {
8932 // We have never parsed any aliases. This case happens if there
8933 // is just one name and some extra white spaces at the end.
8934 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c);
8935 break;
8936 }
8937 }
8938 }
8939 freeaddrinfo(gairesults);
8940 }
8941
8942 mDNSlocal void mDNSMacOSXParseEtcHosts(int fd, AuthHash *auth)
8943 {
8944 mDNSBool good;
8945 char buf[ETCHOSTS_BUFSIZE];
8946 ssize_t len;
8947 FILE *fp;
8948
8949 if (fd == -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
8950
8951 fp = fopen("/etc/hosts", "r");
8952 if (!fp) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
8953
8954 while (1)
8955 {
8956 good = (fgets(buf, ETCHOSTS_BUFSIZE, fp) != NULL);
8957 if (!good) break;
8958
8959 // skip comment and empty lines
8960 if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n')
8961 continue;
8962
8963 len = strlen(buf);
8964 if (!len) break; // sanity check
8965 //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
8966 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
8967 {
8968 buf[len - 1] = '\0';
8969 len = len - 1;
8970 }
8971 // fgets always null terminates and hence even if we have no
8972 // newline at the end, it is null terminated. The callee
8973 // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
8974 // buf[length] is zero and hence we decrement len to reflect that.
8975 if (len)
8976 {
8977 //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
8978 //here we need to check for just \r but taking extra caution.
8979 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
8980 {
8981 buf[len - 1] = '\0';
8982 len = len - 1;
8983 }
8984 }
8985 if (!len) //Sanity Check: len should never be zero
8986 {
8987 LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
8988 continue;
8989 }
8990 mDNSMacOSXParseEtcHostsLine(buf, len, auth);
8991 }
8992 fclose(fp);
8993 }
8994
8995 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m);
8996
8997 mDNSlocal int mDNSMacOSXGetEtcHostsFD(void)
8998 {
8999 mDNS *const m = &mDNSStorage;
9000 #ifdef __DISPATCH_GROUP__
9001 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9002 static dispatch_queue_t etcq = 0;
9003 static dispatch_source_t etcsrc = 0;
9004 static dispatch_source_t hostssrc = 0;
9005
9006 // First time through? just schedule ourselves on the main queue and we'll do the work later
9007 if (!etcq)
9008 {
9009 etcq = dispatch_get_main_queue();
9010 if (etcq)
9011 {
9012 // Do this work on the queue, not here - solves potential synchronization issues
9013 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9014 }
9015 return -1;
9016 }
9017
9018 if (hostssrc) return dispatch_source_get_handle(hostssrc);
9019 #endif
9020
9021 int fd = open("/etc/hosts", O_RDONLY);
9022
9023 #ifdef __DISPATCH_GROUP__
9024 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9025 if (fd == -1)
9026 {
9027 // If the open failed and we're already watching /etc, we're done
9028 if (etcsrc) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd; }
9029
9030 // we aren't watching /etc, we should be
9031 fd = open("/etc", O_RDONLY);
9032 if (fd == -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
9033 etcsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME, etcq);
9034 if (etcsrc == NULL)
9035 {
9036 close(fd);
9037 return -1;
9038 }
9039 dispatch_source_set_event_handler(etcsrc,
9040 ^{
9041 u_int32_t flags = dispatch_source_get_data(etcsrc);
9042 LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags);
9043 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9044 {
9045 dispatch_source_cancel(etcsrc);
9046 dispatch_release(etcsrc);
9047 etcsrc = NULL;
9048 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9049 return;
9050 }
9051 if ((flags & DISPATCH_VNODE_WRITE) != 0 && hostssrc == NULL)
9052 {
9053 mDNSMacOSXUpdateEtcHosts(m);
9054 }
9055 });
9056 dispatch_source_set_cancel_handler(etcsrc, ^{close(fd);});
9057 dispatch_resume(etcsrc);
9058
9059 // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
9060 fd = open("/etc/hosts", O_RDONLY | O_EVTONLY);
9061 if (fd == -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
9062 }
9063
9064 // create a dispatch source to watch for changes to hosts file
9065 hostssrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd,
9066 (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME |
9067 DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_LINK | DISPATCH_VNODE_REVOKE), etcq);
9068 if (hostssrc == NULL)
9069 {
9070 close(fd);
9071 return -1;
9072 }
9073 dispatch_source_set_event_handler(hostssrc,
9074 ^{
9075 u_int32_t flags = dispatch_source_get_data(hostssrc);
9076 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags);
9077 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9078 {
9079 dispatch_source_cancel(hostssrc);
9080 dispatch_release(hostssrc);
9081 hostssrc = NULL;
9082 // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
9083 // the block immediately, we try to open the file and the file may not exist and may
9084 // fail to get a notification in the future. When the file does not exist and
9085 // we start to monitor the directory, on "dispatch_resume" of that source, there
9086 // is no guarantee that the file creation will be notified always because when
9087 // the dispatch_resume returns, the kevent manager may not have registered the
9088 // kevent yet but the file may have been created
9089 usleep(1000000);
9090 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9091 return;
9092 }
9093 if ((flags & DISPATCH_VNODE_WRITE) != 0)
9094 {
9095 mDNSMacOSXUpdateEtcHosts(m);
9096 }
9097 });
9098 dispatch_source_set_cancel_handler(hostssrc, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd); close(fd);});
9099 dispatch_resume(hostssrc);
9100
9101 // Cleanup /etc source, no need to watch it if we already have /etc/hosts
9102 if (etcsrc)
9103 {
9104 dispatch_source_cancel(etcsrc);
9105 dispatch_release(etcsrc);
9106 etcsrc = NULL;
9107 }
9108
9109 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
9110 return hostssrc ? (int)dispatch_source_get_handle(hostssrc) : -1;
9111 #else
9112 (void)m;
9113 return fd;
9114 #endif
9115 }
9116
9117 // When /etc/hosts is modified, flush all the cache records as there may be local
9118 // authoritative answers now
9119 mDNSlocal void FlushAllCacheRecords(mDNS *const m)
9120 {
9121 CacheRecord *cr;
9122 mDNSu32 slot;
9123 CacheGroup *cg;
9124
9125 FORALL_CACHERECORDS(slot, cg, cr)
9126 {
9127 // Skip multicast.
9128 if (cr->resrec.InterfaceID) continue;
9129
9130 // If a resource record can answer A or AAAA, they need to be flushed so that we will
9131 // never used to deliver an ADD or RMV
9132 if (RRTypeAnswersQuestionType(&cr->resrec, kDNSType_A) ||
9133 RRTypeAnswersQuestionType(&cr->resrec, kDNSType_AAAA))
9134 {
9135 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr));
9136 mDNS_PurgeCacheResourceRecord(m, cr);
9137 }
9138 }
9139 }
9140
9141 // Add new entries to the core. If justCheck is set, this function does not add, just returns true
9142 mDNSlocal mDNSBool EtcHostsAddNewEntries(AuthHash *newhosts, mDNSBool justCheck)
9143 {
9144 mDNS *const m = &mDNSStorage;
9145 AuthGroup *ag;
9146 mDNSu32 slot;
9147 AuthRecord *rr, *primary, *rrnext;
9148 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9149 for (ag = newhosts->rrauth_hash[slot]; ag; ag = ag->next)
9150 {
9151 primary = NULL;
9152 for (rr = ag->members; rr; rr = rrnext)
9153 {
9154 rrnext = rr->next;
9155 AuthGroup *ag1;
9156 AuthRecord *rr1;
9157 mDNSBool found = mDNSfalse;
9158 ag1 = AuthGroupForRecord(&m->rrauth, &rr->resrec);
9159 if (ag1 && ag1->members)
9160 {
9161 if (!primary) primary = ag1->members;
9162 rr1 = ag1->members;
9163 while (rr1)
9164 {
9165 // We are not using InterfaceID in checking for duplicates. This means,
9166 // if there are two addresses for a given name e.g., fe80::1%en0 and
9167 // fe80::1%en1, we only add the first one. It is not clear whether
9168 // this is a common case. To fix this, we also need to modify
9169 // mDNS_Register_internal in how it handles duplicates. If it becomes a
9170 // common case, we will fix it then.
9171 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9172 {
9173 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
9174 found = mDNStrue;
9175 break;
9176 }
9177 rr1 = rr1->next;
9178 }
9179 }
9180 if (!found)
9181 {
9182 if (justCheck)
9183 {
9184 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m, rr));
9185 return mDNStrue;
9186 }
9187 RemoveAuthRecord(m, newhosts, rr);
9188 // if there is no primary, point to self
9189 rr->RRSet = (primary ? primary : rr);
9190 rr->next = NULL;
9191 LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m, rr));
9192 if (mDNS_Register_internal(m, rr) != mStatus_NoError)
9193 LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr));
9194 }
9195 }
9196 }
9197 return mDNSfalse;
9198 }
9199
9200 // Delete entries from the core that are no longer needed. If justCheck is set, this function
9201 // does not delete, just returns true
9202 mDNSlocal mDNSBool EtcHostsDeleteOldEntries(AuthHash *newhosts, mDNSBool justCheck)
9203 {
9204 mDNS *const m = &mDNSStorage;
9205 AuthGroup *ag;
9206 mDNSu32 slot;
9207 AuthRecord *rr, *rrnext;
9208 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9209 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
9210 for (rr = ag->members; rr; rr = rrnext)
9211 {
9212 mDNSBool found = mDNSfalse;
9213 AuthGroup *ag1;
9214 AuthRecord *rr1;
9215 rrnext = rr->next;
9216 if (rr->RecordCallback != FreeEtcHosts) continue;
9217 ag1 = AuthGroupForRecord(newhosts, &rr->resrec);
9218 if (ag1)
9219 {
9220 rr1 = ag1->members;
9221 while (rr1)
9222 {
9223 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9224 {
9225 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m, rr));
9226 found = mDNStrue;
9227 break;
9228 }
9229 rr1 = rr1->next;
9230 }
9231 }
9232 // there is no corresponding record in newhosts for the same name. This means
9233 // we should delete this from the core.
9234 if (!found)
9235 {
9236 if (justCheck)
9237 {
9238 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m, rr));
9239 return mDNStrue;
9240 }
9241 // if primary is going away, make sure that the rest of the records
9242 // point to the new primary
9243 if (rr == ag->members)
9244 {
9245 AuthRecord *new_primary = rr->next;
9246 AuthRecord *r = new_primary;
9247 while (r)
9248 {
9249 if (r->RRSet == rr)
9250 {
9251 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m, r));
9252 r->RRSet = new_primary;
9253 }
9254 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m, r), r->resrec.name);
9255 r = r->next;
9256 }
9257 }
9258 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m, rr));
9259 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
9260 }
9261 }
9262 return mDNSfalse;
9263 }
9264
9265 mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context)
9266 {
9267 AuthHash *newhosts = (AuthHash *)context;
9268
9269 mDNS_CheckLock(m);
9270
9271 //Delete old entries from the core if they are not present in the newhosts
9272 EtcHostsDeleteOldEntries(newhosts, mDNSfalse);
9273 // Add the new entries to the core if not already present in the core
9274 EtcHostsAddNewEntries(newhosts, mDNSfalse);
9275 }
9276
9277 mDNSlocal void FreeNewHosts(AuthHash *newhosts)
9278 {
9279 mDNSu32 slot;
9280 AuthGroup *ag, *agnext;
9281 AuthRecord *rr, *rrnext;
9282
9283 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9284 for (ag = newhosts->rrauth_hash[slot]; ag; ag = agnext)
9285 {
9286 agnext = ag->next;
9287 for (rr = ag->members; rr; rr = rrnext)
9288 {
9289 rrnext = rr->next;
9290 freeL("etchosts", rr);
9291 }
9292 freeL("AuthGroups", ag);
9293 }
9294 }
9295
9296 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
9297 {
9298 AuthHash newhosts;
9299
9300 // As we will be modifying the core, we can only have one thread running at
9301 // any point in time.
9302 KQueueLock();
9303
9304 mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
9305
9306 // Get the file desecriptor (will trigger us to start watching for changes)
9307 int fd = mDNSMacOSXGetEtcHostsFD();
9308 if (fd != -1)
9309 {
9310 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd);
9311 mDNSMacOSXParseEtcHosts(fd, &newhosts);
9312 }
9313 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
9314
9315 // Optimization: Detect whether /etc/hosts changed or not.
9316 //
9317 // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
9318 // newhosts is already registered with core. If we find at least one entry that is not
9319 // registered with core, then it means we have work to do.
9320 //
9321 // 2. Next, we check to see if any of the entries that are registered with core is not present
9322 // in newhosts. If we find at least one entry that is not present, it means we have work to
9323 // do.
9324 //
9325 // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
9326 // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
9327 // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
9328 // in the future and this code does not have to change.
9329 mDNS_Lock(m);
9330 // Add the new entries to the core if not already present in the core
9331 if (!EtcHostsAddNewEntries(&newhosts, mDNStrue))
9332 {
9333 // No new entries to add, check to see if we need to delete any old entries from the
9334 // core if they are not present in the newhosts
9335 if (!EtcHostsDeleteOldEntries(&newhosts, mDNStrue))
9336 {
9337 LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
9338 FreeNewHosts(&newhosts);
9339 mDNS_Unlock(m);
9340 KQueueUnlock("/etc/hosts changed");
9341 return;
9342 }
9343 }
9344
9345 // This will flush the cache, stop and start the query so that the queries
9346 // can look at the /etc/hosts again
9347 //
9348 // Notes:
9349 //
9350 // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
9351 // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
9352 // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
9353 // delivers these events in the right order and then calls us back to delete them.
9354 //
9355 // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
9356 // is a common function that looks at all local auth records and delivers a RMV including
9357 // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
9358 // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
9359 // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
9360 // is called back where we do the Registration of the record. This results in RMV followed by ADD which
9361 // looks normal.
9362 mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts);
9363 FreeNewHosts(&newhosts);
9364 mDNS_Unlock(m);
9365 KQueueUnlock("/etc/hosts changed");
9366 }
9367
9368 #if COMPILER_LIKES_PRAGMA_MARK
9369 #pragma mark -
9370 #pragma mark - Initialization & Teardown
9371 #endif
9372
9373 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
9374 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
9375 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
9376 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
9377
9378 // Major version 13 is 10.9.x
9379 mDNSexport void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
9380 {
9381 int major = 0, minor = 0;
9382 char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
9383 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
9384 if (vers)
9385 {
9386 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
9387 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
9388 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
9389 if (cfprodname)
9390 CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
9391 if (cfprodvers)
9392 CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
9393 if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
9394 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
9395 CFRelease(vers);
9396 }
9397 if (!major)
9398 {
9399 major = 13;
9400 LogMsg("Note: No Major Build Version number found; assuming 13");
9401 }
9402 if (HINFO_SWstring)
9403 mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion));
9404 //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
9405
9406 // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
9407 if ((prodname[0] & 0xDF) == 'M')
9408 OSXVers = major;
9409 else
9410 iOSVers = major;
9411 }
9412
9413 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
9414 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
9415 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
9416 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
9417 {
9418 int err = -1;
9419 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
9420 if (s < 3)
9421 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
9422 else
9423 {
9424 struct sockaddr_in s5353;
9425 s5353.sin_family = AF_INET;
9426 s5353.sin_port = MulticastDNSPort.NotAnInteger;
9427 s5353.sin_addr.s_addr = 0;
9428 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
9429 close(s);
9430 }
9431
9432 if (err) LogMsg("No unicast UDP responses");
9433 else debugf("Unicast UDP responses okay");
9434 return(err == 0);
9435 }
9436
9437 mDNSlocal void CreatePTRRecord(const domainname *domain)
9438 {
9439 AuthRecord *rr;
9440 const domainname *pname = (domainname *)"\x9" "localhost";
9441
9442 rr= mallocL("localhosts", sizeof(*rr));
9443 if (rr == NULL) return;
9444 mDNSPlatformMemZero(rr, sizeof(*rr));
9445
9446 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
9447 AssignDomainName(&rr->namestorage, domain);
9448
9449 rr->resrec.rdlength = DomainNameLength(pname);
9450 rr->resrec.rdata->u.name.c[0] = 0;
9451 AssignDomainName(&rr->resrec.rdata->u.name, pname);
9452
9453 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
9454 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
9455 mDNS_Register(&mDNSStorage, rr);
9456 }
9457
9458 // Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
9459 // on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
9460 // fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
9461 // a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
9462 //
9463 // Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
9464 // intentionally to avoid adding to the complexity of code handling /etc/hosts.
9465 mDNSlocal void SetupLocalHostRecords(void)
9466 {
9467 domainname name;
9468
9469 MakeDomainNameFromDNSNameString(&name, "1.0.0.127.in-addr.arpa.");
9470 CreatePTRRecord(&name);
9471
9472 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.");
9473 CreatePTRRecord(&name);
9474 }
9475
9476 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
9477 mDNSlocal void setSameDomainLabelPointer(void);
9478 #endif
9479
9480 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
9481 // 1) query for b._dns-sd._udp.local on LocalOnly interface
9482 // (.local manually generated via explicit callback)
9483 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
9484 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
9485 // 4) result above should generate a callback from question in (1). result added to global list
9486 // 5) global list delivered to client via GetSearchDomainList()
9487 // 6) client calls to enumerate domains now go over LocalOnly interface
9488 // (!!!KRS may add outgoing interface in addition)
9489
9490 #if TARGET_OS_IPHONE
9491 mDNSlocal mDNSBool IsAppleInternalBuild(void)
9492 {
9493 return (os_variant_has_internal_diagnostics("com.apple.mDNSResponder") ? mDNStrue : mDNSfalse);
9494 }
9495
9496 mDNSlocal mStatus RegisterLocalOnlyAddressRecord(const domainname *const name, mDNSu16 type, const void *rdata, mDNSu16 rdlength)
9497 {
9498 switch(type)
9499 {
9500 case kDNSType_A:
9501 if (rdlength != 4) return (mStatus_BadParamErr);
9502 break;
9503
9504 case kDNSType_AAAA:
9505 if (rdlength != 16) return (mStatus_BadParamErr);
9506 break;
9507
9508 default:
9509 return (mStatus_BadParamErr);
9510 }
9511
9512 AuthRecord *rr = mallocL("etchosts", sizeof(*rr));
9513 if (!rr) return (mStatus_NoMemoryErr);
9514 mDNSPlatformMemZero(rr, sizeof(*rr));
9515
9516 mDNS_SetupResourceRecord(rr, NULL, mDNSInterface_LocalOnly, type, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
9517 AssignDomainName(&rr->namestorage, name);
9518 mDNSPlatformMemCopy(rr->resrec.rdata->u.data, rdata, rdlength);
9519
9520 const mStatus err = mDNS_Register_internal(&mDNSStorage, rr);
9521 if (err)
9522 {
9523 LogMsg("RegisterLocalOnlyAddressRecord: mDNS_Register error %d registering %s", err, ARDisplayString(&mDNSStorage, rr));
9524 freeL("etchosts", rr);
9525 }
9526 return (err);
9527 }
9528
9529 mDNSlocal void RegisterLocalOnlyARecord(const domainname *const name, const mDNSv4Addr *const addr)
9530 {
9531 RegisterLocalOnlyAddressRecord(name, kDNSType_A, addr->b, (mDNSu16)sizeof(mDNSv4Addr));
9532 }
9533
9534 mDNSlocal void RegisterLocalOnlyAAAARecord(const domainname *const name, const mDNSv6Addr *const addr)
9535 {
9536 RegisterLocalOnlyAddressRecord(name, kDNSType_AAAA, addr->b, (mDNSu16)sizeof(mDNSv6Addr));
9537 }
9538 #endif
9539
9540 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
9541 {
9542 mStatus err;
9543
9544 char HINFO_SWstring[256] = "";
9545 mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
9546
9547 #if APPLE_OSX_mDNSResponder
9548 setSameDomainLabelPointer();
9549 #endif
9550
9551 err = mDNSHelperInit();
9552 if (err)
9553 return err;
9554
9555 // Store mDNSResponder Platform
9556 if (OSXVers)
9557 {
9558 m->mDNS_plat = platform_OSX;
9559 }
9560 else if (iOSVers)
9561 {
9562 if (IsAppleTV())
9563 m->mDNS_plat = platform_Atv;
9564 else
9565 m->mDNS_plat = platform_iOS;
9566 }
9567 else
9568 {
9569 m->mDNS_plat = platform_NonApple;
9570 }
9571
9572 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
9573 // 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.
9574 int i;
9575 for (i=0; i<100; i++)
9576 {
9577 domainlabel testlabel;
9578 testlabel.c[0] = 0;
9579 GetUserSpecifiedLocalHostName(&testlabel);
9580 if (testlabel.c[0]) break;
9581 usleep(50000);
9582 }
9583
9584 m->hostlabel.c[0] = 0;
9585
9586 int get_model[2] = { CTL_HW, HW_MODEL };
9587 size_t len_model = sizeof(HINFO_HWstring_buffer);
9588
9589 // Normal Apple model names are of the form "iPhone2,1", and
9590 // internal code names are strings containing no commas, e.g. "N88AP".
9591 // We used to ignore internal code names, but Apple now uses these internal code names
9592 // even in released shipping products, so we no longer ignore strings containing no commas.
9593 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
9594 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
9595 HINFO_HWstring = HINFO_HWstring_buffer;
9596
9597 // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
9598 // For names of the form "N88AP" containg no comma, we use the entire string.
9599 HINFO_HWstring_prefixlen = strchr(HINFO_HWstring_buffer, ',') ? strcspn(HINFO_HWstring, "0123456789") : strlen(HINFO_HWstring);
9600
9601 if (mDNSPlatformInit_CanReceiveUnicast())
9602 m->CanReceiveUnicastOn5353 = mDNStrue;
9603
9604 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
9605 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
9606 if (hlen + slen < 254)
9607 {
9608 m->HIHardware.c[0] = hlen;
9609 m->HISoftware.c[0] = slen;
9610 mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
9611 mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
9612 }
9613
9614 m->p->permanentsockets.port = MulticastDNSPort;
9615 m->p->permanentsockets.m = m;
9616 m->p->permanentsockets.sktv4 = -1;
9617 m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack;
9618 m->p->permanentsockets.kqsv4.KQcontext = &m->p->permanentsockets;
9619 m->p->permanentsockets.kqsv4.KQtask = "IPv4 UDP packet reception";
9620 m->p->permanentsockets.sktv6 = -1;
9621 m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
9622 m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
9623 m->p->permanentsockets.kqsv6.KQtask = "IPv6 UDP packet reception";
9624
9625 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
9626 if (err) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET) failed error %d errno %d (%s)", err, errno, strerror(errno));
9627 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
9628 if (err) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET6) failed error %d errno %d (%s)", err, errno, strerror(errno));
9629
9630 struct sockaddr_in s4;
9631 socklen_t n4 = sizeof(s4);
9632 if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0)
9633 LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
9634 else
9635 m->UnicastPort4.NotAnInteger = s4.sin_port;
9636
9637 if (m->p->permanentsockets.sktv6 >= 0)
9638 {
9639 struct sockaddr_in6 s6;
9640 socklen_t n6 = sizeof(s6);
9641 if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
9642 else m->UnicastPort6.NotAnInteger = s6.sin6_port;
9643 }
9644
9645 m->p->InterfaceList = mDNSNULL;
9646 m->p->userhostlabel.c[0] = 0;
9647 m->p->usernicelabel.c[0] = 0;
9648 m->p->prevoldnicelabel.c[0] = 0;
9649 m->p->prevnewnicelabel.c[0] = 0;
9650 m->p->prevoldhostlabel.c[0] = 0;
9651 m->p->prevnewhostlabel.c[0] = 0;
9652 m->p->NotifyUser = 0;
9653 m->p->KeyChainTimer = 0;
9654 m->p->WakeAtUTC = 0;
9655 m->p->RequestReSleep = 0;
9656 // Assume that everything is good to begin with. If something is not working,
9657 // we will detect that when we start sending questions.
9658 m->p->v4answers = 1;
9659 m->p->v6answers = 1;
9660 m->p->DNSTrigger = 0;
9661 m->p->LastConfigGeneration = 0;
9662
9663 m->AutoTunnelRelayAddr = zerov6Addr;
9664
9665 NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
9666 NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
9667 NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
9668 NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
9669 NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
9670 NetworkChangedKey_StateInterfacePrefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, CFSTR(""), NULL);
9671 if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS || !NetworkChangedKey_StateInterfacePrefix)
9672 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
9673
9674 err = WatchForNetworkChanges(m);
9675 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
9676
9677 err = WatchForSysEvents(m);
9678 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
9679
9680 mDNSs32 utc = mDNSPlatformUTC();
9681 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
9682 myGetIfAddrs(1);
9683 UpdateInterfaceList(utc);
9684 SetupActiveInterfaces(utc);
9685 ReorderInterfaceList();
9686
9687 // Explicitly ensure that our Keychain operations utilize the system domain.
9688 #ifndef NO_SECURITYFRAMEWORK
9689 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
9690 #endif
9691
9692 mDNS_Lock(m);
9693 SetDomainSecrets(m);
9694 SetLocalDomains();
9695 mDNS_Unlock(m);
9696
9697 #ifndef NO_SECURITYFRAMEWORK
9698 err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
9699 if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
9700 #endif
9701
9702 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
9703 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
9704 #else
9705 IOPMConnection c;
9706 IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
9707 if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
9708 else
9709 {
9710 iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
9711 if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
9712 else
9713 {
9714 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9715 IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue());
9716 LogInfo("IOPMConnectionSetDispatchQueue is now running");
9717 #else
9718 iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
9719 if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
9720 LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
9721 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9722 }
9723 }
9724 m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
9725 if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
9726 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
9727 {
9728 m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
9729 if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
9730 else
9731 {
9732 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9733 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
9734 #else
9735 CFRunLoopAddSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
9736 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9737 }
9738 }
9739
9740 #if APPLE_OSX_mDNSResponder
9741 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
9742 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
9743 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
9744 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
9745 if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9746 else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9747 else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9748 else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
9749 else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; }
9750 else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; }
9751 else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /* 4kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 13W */; }
9752 else if (!strncasecmp(HINFO_HWstring, "AirPort", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 12W */; }
9753 else if ( IsAppleTV() ) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 60 /* 1W */; SPMetricTotalPower = 63 /* 2W */; }
9754 else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
9755 else if (!strncasecmp(HINFO_HWstring, "PowerBook", 9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
9756 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
9757 HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
9758 #endif // APPLE_OSX_mDNSResponder
9759
9760 // Currently this is not defined. SSL code will eventually fix this. If it becomes
9761 // critical, we will define this to workaround the bug in SSL.
9762 #ifdef __SSL_NEEDS_SERIALIZATION__
9763 SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL);
9764 #else
9765 SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
9766 #endif
9767 if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
9768
9769 #if TARGET_OS_IPHONE
9770 // On device OSes (iOS, tvOS, watchOS, etc.), ignore /etc/hosts unless the OS is an internal build. When the /etc/hosts
9771 // file is ignored, LocalOnly auth records will be registered for localhost and broadcasthost addresses contained in the
9772 // standard /etc/hosts file:
9773 //
9774 // 127.0.0.1 localhost
9775 // 255.255.255.255 broadcasthost
9776 // ::1 localhost
9777
9778 if (!IsAppleInternalBuild())
9779 {
9780 const domainname *const localHostName = (const domainname *) "\x9" "localhost";
9781 const domainname *const broadcastHostName = (const domainname *) "\xd" "broadcasthost";
9782 const mDNSv4Addr localHostV4 = { { 127, 0, 0, 1 } };
9783 mDNSv6Addr localHostV6;
9784
9785 // Register localhost 127.0.0.1 A record.
9786
9787 RegisterLocalOnlyARecord(localHostName, &localHostV4);
9788
9789 // Register broadcasthost 255.255.255.255 A record.
9790
9791 RegisterLocalOnlyARecord(broadcastHostName, &onesIPv4Addr);
9792
9793 // Register localhost ::1 AAAA record.
9794
9795 mDNSPlatformMemZero(&localHostV6, sizeof(localHostV6));
9796 localHostV6.b[15] = 1;
9797 RegisterLocalOnlyAAAARecord(localHostName, &localHostV6);
9798 }
9799 else
9800 #endif
9801 {
9802 mDNSMacOSXUpdateEtcHosts(m);
9803 }
9804 SetupLocalHostRecords();
9805
9806 return(mStatus_NoError);
9807 }
9808
9809 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
9810 {
9811 #if MDNS_NO_DNSINFO
9812 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
9813 #endif
9814
9815 // Adding interfaces will use this flag, so set it now.
9816 m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
9817
9818 #if APPLE_OSX_mDNSResponder
9819 m->SPSBrowseCallback = UpdateSPSStatus;
9820 #endif // APPLE_OSX_mDNSResponder
9821
9822 mStatus result = mDNSPlatformInit_setup(m);
9823
9824 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
9825 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
9826 if (result == mStatus_NoError)
9827 {
9828 mDNSCoreInitComplete(m, mStatus_NoError);
9829 initializeD2DPlugins(m);
9830 }
9831 result = DNSSECCryptoInit(m);
9832 return(result);
9833 }
9834
9835 mDNSexport void mDNSPlatformClose(mDNS *const m)
9836 {
9837 if (m->p->PowerConnection)
9838 {
9839 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9840 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);
9841 #else
9842 CFRunLoopRemoveSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
9843 #endif
9844 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
9845 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
9846 IODeregisterForSystemPower(&m->p->PowerNotifier);
9847 IOServiceClose ( m->p->PowerConnection);
9848 IONotificationPortDestroy ( m->p->PowerPortRef);
9849 m->p->PowerConnection = 0;
9850 }
9851
9852 if (m->p->Store)
9853 {
9854 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9855 if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
9856 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
9857 #else
9858 CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode);
9859 CFRunLoopSourceInvalidate(m->p->StoreRLS);
9860 CFRelease(m->p->StoreRLS);
9861 m->p->StoreRLS = NULL;
9862 #endif
9863 CFRelease(m->p->Store);
9864 m->p->Store = NULL;
9865 }
9866
9867 if (m->p->PMRLS)
9868 {
9869 CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->PMRLS, kCFRunLoopDefaultMode);
9870 CFRunLoopSourceInvalidate(m->p->PMRLS);
9871 CFRelease(m->p->PMRLS);
9872 m->p->PMRLS = NULL;
9873 }
9874
9875 if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
9876
9877 terminateD2DPlugins();
9878
9879 mDNSs32 utc = mDNSPlatformUTC();
9880 MarkAllInterfacesInactive(utc);
9881 ClearInactiveInterfaces(utc);
9882 CloseSocketSet(&m->p->permanentsockets);
9883
9884 #if APPLE_OSX_mDNSResponder
9885 // clean up tunnels
9886 while (m->TunnelClients)
9887 {
9888 ClientTunnel *cur = m->TunnelClients;
9889 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
9890 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
9891 AutoTunnelSetKeys(cur, mDNSfalse);
9892 m->TunnelClients = cur->next;
9893 freeL("ClientTunnel", cur);
9894 }
9895
9896 if (AnonymousRacoonConfig)
9897 {
9898 AnonymousRacoonConfig = mDNSNULL;
9899 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel need not be done in mDNSResponder");
9900 }
9901 #endif // APPLE_OSX_mDNSResponder
9902 }
9903
9904 #if COMPILER_LIKES_PRAGMA_MARK
9905 #pragma mark -
9906 #pragma mark - General Platform Support Layer functions
9907 #endif
9908
9909 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
9910 {
9911 return(arc4random());
9912 }
9913
9914 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
9915 mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
9916
9917 mDNSexport mStatus mDNSPlatformTimeInit(void)
9918 {
9919 // Notes: Typical values for mach_timebase_info:
9920 // tbi.numer = 1000 million
9921 // tbi.denom = 33 million
9922 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
9923 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
9924 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
9925 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
9926 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
9927 //
9928 // Arithmetic notes:
9929 // tbi.denom is at least 1, and not more than 2^32-1.
9930 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
9931 // tbi.denom is at least 1, and not more than 2^32-1.
9932 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
9933 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
9934 // which is unlikely on any current or future Macintosh.
9935 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
9936 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
9937 struct mach_timebase_info tbi;
9938 kern_return_t result = mach_timebase_info(&tbi);
9939 if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
9940 return(result);
9941 }
9942
9943 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
9944 {
9945 if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
9946
9947 static uint64_t last_mach_absolute_time = 0;
9948 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
9949 uint64_t this_mach_absolute_time = mach_absolute_time();
9950 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
9951 {
9952 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
9953 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
9954 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
9955 last_mach_absolute_time = this_mach_absolute_time;
9956 // Note: This bug happens all the time on 10.3
9957 NotifyOfElusiveBug("mach_absolute_time went backwards!",
9958 "This error occurs from time to time, often on newly released hardware, "
9959 "and usually the exact cause is different in each instance.\r\r"
9960 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
9961 "and assign it to Radar Component “Kernel” Version “X”.");
9962 }
9963 last_mach_absolute_time = this_mach_absolute_time;
9964
9965 return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
9966 }
9967
9968 mDNSexport mDNSs32 mDNSPlatformUTC(void)
9969 {
9970 return time(NULL);
9971 }
9972
9973 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
9974 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
9975 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
9976 mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (const char *)src); }
9977 mDNSexport mDNSu32 mDNSPlatformStrLCopy( void *dst, const void *src, mDNSu32 dstlen) { return (strlcpy((char *)dst, (const char *)src, dstlen)); }
9978 mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((const char*)src)); }
9979 mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
9980 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
9981 mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); }
9982 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); }
9983 mDNSexport void mDNSPlatformQsort ( void *base, int nel, int width, int (*compar)(const void *, const void *))
9984 {
9985 return (qsort(base, nel, width, compar));
9986 }
9987 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
9988 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
9989 #endif
9990 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
9991
9992 mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason)
9993 {
9994 mDNS *const m = &mDNSStorage;
9995 if (allowSleep && m->p->IOPMAssertion)
9996 {
9997 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
9998 IOPMAssertionRelease(m->p->IOPMAssertion);
9999 m->p->IOPMAssertion = 0;
10000 }
10001 else if (!allowSleep)
10002 {
10003 #ifdef kIOPMAssertionTypeNoIdleSleep
10004 if (m->p->IOPMAssertion)
10005 {
10006 IOPMAssertionRelease(m->p->IOPMAssertion);
10007 m->p->IOPMAssertion = 0;
10008 }
10009
10010 CFStringRef assertionName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%d %s"), getprogname(), getpid(), reason ? reason : "");
10011 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, assertionName ? assertionName : CFSTR("mDNSResponder"), &m->p->IOPMAssertion);
10012 if (assertionName) CFRelease(assertionName);
10013 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__);
10014 #endif
10015 }
10016 }
10017
10018 mDNSexport void mDNSPlatformPreventSleep(mDNSu32 timeout, const char *reason)
10019 {
10020 mDNS *const m = &mDNSStorage;
10021 if (m->p->IOPMAssertion)
10022 {
10023 LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout, reason);
10024 return;
10025 }
10026 #ifdef kIOPMAssertionTypeNoIdleSleep
10027
10028 #if TARGET_OS_EMBEDDED
10029 if (!IsAppleTV())
10030 return; // No need for maintenance wakes on non-AppleTV embedded devices.
10031 #endif
10032
10033 double timeoutVal = (double)timeout;
10034 CFStringRef str = CFStringCreateWithCString(NULL, reason, kCFStringEncodingUTF8);
10035 CFNumberRef Timeout_num = CFNumberCreate(NULL, kCFNumberDoubleType, &timeoutVal);
10036 CFMutableDictionaryRef assertionProperties = CFDictionaryCreateMutable(NULL, 0,
10037 &kCFTypeDictionaryKeyCallBacks,
10038 &kCFTypeDictionaryValueCallBacks);
10039 if (IsAppleTV())
10040 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertPreventUserIdleSystemSleep);
10041 else
10042 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertMaintenanceActivity);
10043
10044 CFDictionarySetValue(assertionProperties, kIOPMAssertionTimeoutKey, Timeout_num);
10045 CFDictionarySetValue(assertionProperties, kIOPMAssertionNameKey, str);
10046
10047 IOPMAssertionCreateWithProperties(assertionProperties, (IOPMAssertionID *)&m->p->IOPMAssertion);
10048 CFRelease(str);
10049 CFRelease(Timeout_num);
10050 CFRelease(assertionProperties);
10051 LogSPS("Got an idle sleep assertion for %d seconds for %s", timeout, reason);
10052 #endif
10053 }
10054
10055 mDNSexport void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
10056 {
10057 mDNSu32 ifindex;
10058
10059 // Sanity check
10060 ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, InterfaceID, mDNStrue);
10061 if (ifindex <= 0)
10062 {
10063 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
10064 return;
10065 }
10066 mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration);
10067 }
10068
10069 mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
10070 {
10071 NetworkInterfaceInfoOSX *info;
10072
10073 if (InterfaceID == mDNSInterface_P2P)
10074 return mDNStrue;
10075
10076 // mDNSInterface_BLE not considered a D2D interface for the purpose of this
10077 // routine, since it's not implemented via a D2D plugin.
10078 if (InterfaceID == mDNSInterface_BLE)
10079 return mDNSfalse;
10080
10081 if ( (InterfaceID == mDNSInterface_Any)
10082 || (InterfaceID == mDNSInterfaceMark)
10083 || (InterfaceID == mDNSInterface_LocalOnly)
10084 || (InterfaceID == mDNSInterface_Unicast))
10085 return mDNSfalse;
10086
10087 // Compare to cached AWDL interface ID.
10088 if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
10089 return mDNStrue;
10090
10091 info = IfindexToInterfaceInfoOSX(InterfaceID);
10092 if (info == NULL)
10093 {
10094 // this log message can print when operations are stopped on an interface that has gone away
10095 LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID);
10096 return mDNSfalse;
10097 }
10098
10099 return (mDNSBool) info->D2DInterface;
10100 }
10101
10102 // Filter records send over P2P (D2D) type interfaces
10103 // Note that the terms P2P and D2D are used synonymously in the current code and comments.
10104 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
10105 {
10106 // For an explicit match to a valid interface ID, return true.
10107 if (rr->resrec.InterfaceID == InterfaceID)
10108 return mDNStrue;
10109
10110 // Only filtering records for D2D type interfaces, return true for all other interface types.
10111 if (!mDNSPlatformInterfaceIsD2D(InterfaceID))
10112 return mDNStrue;
10113
10114 // If it's an AWDL interface the record must be explicitly marked to include AWDL.
10115 if (InterfaceID == AWDLInterfaceID)
10116 {
10117 if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10118 return mDNStrue;
10119 else
10120 return mDNSfalse;
10121 }
10122
10123 // Send record if it is explicitly marked to include all other P2P type interfaces.
10124 if (rr->ARType == AuthRecordAnyIncludeP2P || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10125 return mDNStrue;
10126
10127 // Don't send the record over this interface.
10128 return mDNSfalse;
10129 }
10130
10131 // Filter questions send over P2P (D2D) type interfaces.
10132 mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
10133 {
10134 // For an explicit match to a valid interface ID, return true.
10135 if (q->InterfaceID == intf->InterfaceID)
10136 return mDNStrue;
10137
10138 // Only filtering questions for D2D type interfaces
10139 if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
10140 return mDNStrue;
10141
10142 // If it's an AWDL interface the question must be explicitly marked to include AWDL.
10143 if (intf->InterfaceID == AWDLInterfaceID)
10144 {
10145 if (q->flags & kDNSServiceFlagsIncludeAWDL)
10146 return mDNStrue;
10147 else
10148 return mDNSfalse;
10149 }
10150
10151 // Sent question if it is explicitly marked to include all other P2P type interfaces.
10152 if (q->flags & kDNSServiceFlagsIncludeP2P)
10153 return mDNStrue;
10154
10155 // Don't send the question over this interface.
10156 return mDNSfalse;
10157 }
10158
10159 // Returns true unless record was received over the AWDL interface and
10160 // the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
10161 // with the kDNSServiceFlagsIncludeAWDL flag set.
10162 mDNSexport mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
10163 {
10164 if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID))
10165 return mDNStrue;
10166
10167 if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL))
10168 return mDNSfalse;
10169
10170 return mDNStrue;
10171 }
10172
10173 // formating time to RFC 4034 format
10174 mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
10175 {
10176 struct tm tmTime;
10177 time_t t = (time_t)te;
10178 // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
10179 // gmtime_r first and then use strftime
10180 gmtime_r(&t, &tmTime);
10181 strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
10182 }
10183
10184 mDNSexport mDNSs32 mDNSPlatformGetPID()
10185 {
10186 return getpid();
10187 }
10188
10189 // Schedule a function asynchronously on the main queue
10190 mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func)
10191 {
10192 // KQueueLock/Unlock is used for two purposes
10193 //
10194 // 1. We can't be running along with the KQueue thread and hence acquiring the lock
10195 // serializes the access to the "core"
10196 //
10197 // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
10198 // up and calls udsserver_idle which schedules the messages across the uds socket.
10199 // If "func" delivers something to the uds socket from the dispatch thread, it will
10200 // not be delivered immediately if not for the Unlock.
10201 dispatch_async(dispatch_get_main_queue(), ^{
10202 KQueueLock();
10203 func(m, context);
10204 KQueueUnlock("mDNSPlatformDispatchAsync");
10205 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10206 // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
10207 // to handle any message that "func" might deliver.
10208 TriggerEventCompletion();
10209 #endif
10210 });
10211 }
10212
10213 // definitions for device-info record construction
10214 #define DEVINFO_MODEL "model="
10215 #define DEVINFO_MODEL_LEN sizeof_string(DEVINFO_MODEL)
10216
10217 #define OSX_VER "osxvers="
10218 #define OSX_VER_LEN sizeof_string(OSX_VER)
10219 #define VER_NUM_LEN 2 // 2 digits of version number added to base string
10220
10221 #define MODEL_COLOR "ecolor="
10222 #define MODEL_COLOR_LEN sizeof_string(MODEL_COLOR)
10223 #define MODEL_RGB_VALUE_LEN sizeof_string("255,255,255") // 'r,g,b'
10224
10225 // Bytes available in TXT record for model name after subtracting space for other
10226 // fixed size strings and their length bytes.
10227 #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))
10228
10229 mDNSlocal mDNSu8 getModelIconColors(char *color)
10230 {
10231 mDNSPlatformMemZero(color, MODEL_RGB_VALUE_LEN + 1);
10232
10233 #if !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10234 mDNSu8 red = 0;
10235 mDNSu8 green = 0;
10236 mDNSu8 blue = 0;
10237
10238 IOReturn rGetDeviceColor = IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey,
10239 &red, &green, &blue);
10240 if (kIOReturnSuccess == rGetDeviceColor)
10241 {
10242 // IOKit was able to get enclosure color for the current device.
10243 return snprintf(color, MODEL_RGB_VALUE_LEN + 1, "%d,%d,%d", red, green, blue);
10244 }
10245 #endif // !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10246
10247 return 0;
10248 }
10249
10250
10251 // Initialize device-info TXT record contents and return total length of record data.
10252 mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
10253 {
10254 mDNSu8 *bufferStart = ptr;
10255 mDNSu8 len = m->HIHardware.c[0] < MAX_MODEL_NAME_LEN ? m->HIHardware.c[0] : MAX_MODEL_NAME_LEN;
10256
10257 *ptr = DEVINFO_MODEL_LEN + len; // total length of DEVINFO_MODEL string plus the hardware name string
10258 ptr++;
10259 mDNSPlatformMemCopy(ptr, DEVINFO_MODEL, DEVINFO_MODEL_LEN);
10260 ptr += DEVINFO_MODEL_LEN;
10261 mDNSPlatformMemCopy(ptr, m->HIHardware.c + 1, len);
10262 ptr += len;
10263
10264 // only include this string for OSX
10265 if (OSXVers)
10266 {
10267 char ver_num[VER_NUM_LEN + 1]; // version digits + null written by snprintf
10268 *ptr = OSX_VER_LEN + VER_NUM_LEN; // length byte
10269 ptr++;
10270 mDNSPlatformMemCopy(ptr, OSX_VER, OSX_VER_LEN);
10271 ptr += OSX_VER_LEN;
10272 // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
10273 // WARNING: This code assumes that OSXVers is always exactly two digits
10274 snprintf(ver_num, VER_NUM_LEN + 1, "%d", OSXVers);
10275 mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN);
10276 ptr += VER_NUM_LEN;
10277
10278 char rgb[MODEL_RGB_VALUE_LEN + 1]; // RGB value + null written by snprintf
10279 len = getModelIconColors(rgb);
10280 if (len)
10281 {
10282 *ptr = MODEL_COLOR_LEN + len; // length byte
10283 ptr++;
10284
10285 mDNSPlatformMemCopy(ptr, MODEL_COLOR, MODEL_COLOR_LEN);
10286 ptr += MODEL_COLOR_LEN;
10287
10288 mDNSPlatformMemCopy(ptr, rgb, len);
10289 ptr += len;
10290 }
10291 }
10292
10293 return (ptr - bufferStart);
10294 }
10295
10296 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
10297
10298 // Use the scalar version of SameDomainLabel() by default
10299 mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
10300 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
10301 mDNSlocal mDNSBool (*SameDomainLabelPointer)(const mDNSu8 *a, const mDNSu8 *b) = scalarSameDomainLabel;
10302
10303 #include <System/machine/cpu_capabilities.h>
10304 #define _cpu_capabilities ((uint32_t*) _COMM_PAGE_CPU_CAPABILITIES)[0]
10305
10306 #if TARGET_OS_EMBEDDED
10307
10308 #include <arm_neon.h>
10309
10310 // Cache line aligned table that returns 32 for the upper case letters.
10311 // This will take up 4 cache lines.
10312 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table[256] = {
10313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10317 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
10318 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
10319 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10327 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
10329 };
10330
10331 // Neon version
10332 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10333 {
10334 const int len = *a++;
10335
10336 if (len > MAX_DOMAIN_LABEL)
10337 {
10338 fprintf(stderr, "v: Malformed label (too long)\n");
10339 return(mDNSfalse);
10340 }
10341
10342 if (len != *b++)
10343 {
10344 return(mDNSfalse);
10345 }
10346
10347 uint32_t len_count = len;
10348
10349 uint8x16_t vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
10350
10351 uint8x16_t v32 = vdupq_n_u8(32);
10352 uint8x16_t v37 = vdupq_n_u8(37);
10353 uint8x16_t v101 = vdupq_n_u8(101);
10354 #if !defined __arm64__
10355 uint32x4_t vtemp32;
10356 uint32x2_t vtemp32d;
10357 uint32_t sum;
10358 #endif
10359
10360 while(len_count > 15)
10361 {
10362 vA = vld1q_u8(a);
10363 vB = vld1q_u8(b);
10364 a += 16;
10365 b += 16;
10366
10367 //Make vA to lowercase if there is any uppercase.
10368 vARotated = vaddq_u8(vA, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10369 vMaskA = vcgtq_s8(vARotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10370 vMaskA = vandq_u8(vMaskA, v32); //Prepare 32 for the elements with uppercase letters.
10371 vA = vaddq_u8(vA, vMaskA); //Add 32 only to the uppercase letters to make them lowercase letters.
10372
10373 //Make vB to lowercase if there is any uppercase.
10374 vBRotated = vaddq_u8(vB, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10375 vMaskB = vcgtq_s8(vBRotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10376 vMaskB = vandq_u8(vMaskB, v32); //Prepare 32 for the elements with uppercase letters.
10377 vB = vaddq_u8(vB, vMaskB); //Add 32 only to the uppercase letters to make them lowercase letters.
10378
10379 //Compare vA & vB
10380 vA = vceqq_u8(vA, vB);
10381
10382 #if defined __arm64__
10383 //View 8-bit element as 32-bit => a3 a2 a1 a0
10384 //If min of 4 32-bit values in vA is 0xffffffff, then it means we have 0xff for all 16.
10385 if(vminvq_u32(vA) != 0xffffffffU)
10386 {
10387 return(mDNSfalse);
10388
10389 }
10390 #else
10391 //See if any element was not same.
10392 //View 8-bit element as 16-bit => a7 a6 a5 a4 a3 a2 a1 a0
10393 //(a7+a6) (a5+a4) (a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
10394 vtemp32 = vpaddlq_u16(vA);
10395 vtemp32d = vpadd_u32(vget_low_u32(vtemp32), vget_high_u32(vtemp32));
10396 vtemp32d = vpadd_u32(vtemp32d, vtemp32d);
10397 sum = vget_lane_u32(vtemp32d, 0);
10398
10399 //0x0001fffe + 0x0001fffe + 0x0001fffe + 0x0001fffe = 0x0007fff8U when all same.
10400 if(sum != 0x0007fff8U)
10401 {
10402 return(mDNSfalse);
10403 }
10404 #endif
10405
10406 len_count -= 16;
10407 }
10408
10409 uint8x8_t vAd, vBd, vARotatedd, vBRotatedd, vMaskAd, vMaskBd;
10410
10411 uint8x8_t v32d = vdup_n_u8(32);
10412 uint8x8_t v37d = vdup_n_u8(37);
10413 uint8x8_t v101d = vdup_n_u8(101);
10414
10415 while(len_count > 7)
10416 {
10417 vAd = vld1_u8(a);
10418 vBd = vld1_u8(b);
10419 a += 8;
10420 b += 8;
10421
10422 //Make vA to lowercase if there is any uppercase.
10423 vARotatedd = vadd_u8(vAd, v37d); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10424 vMaskAd = vcgt_s8(vARotatedd, v101d); //Check if anything is greater than '101' which means we have uppercase letters.
10425 vMaskAd = vand_u8(vMaskAd, v32d); //Prepare 32 for the elements with uppercase letters.
10426 vAd = vadd_u8(vAd, vMaskAd); //Add 32 only to the uppercase letters to make them lowercase letters.
10427
10428 //Make vB to lowercase if there is any uppercase.
10429 vBRotatedd = vadd_u8(vBd, v37d); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10430 vMaskBd = vcgt_s8(vBRotatedd, v101d); //Check if anything is greater than '101' which means we have uppercase letters.
10431 vMaskBd = vand_u8(vMaskBd, v32d); //Prepare 32 for the elements with uppercase letters.
10432 vBd = vadd_u8(vBd, vMaskBd); //Add 32 only to the uppercase letters to make them lowercase letters.
10433
10434 //Compare vA & vB
10435 vAd = vceq_u8(vAd, vBd);
10436
10437 #if defined __arm64__
10438 //View 8-bit element as 32-bit => a1 a0
10439 //If min of 2 32-bit values in vAd is 0xffffffff, then it means we have 0xff for all 16.
10440 if(vminv_u32(vAd) != 0xffffffffU)
10441 {
10442 return(mDNSfalse);
10443
10444 }
10445 #else
10446 //See if any element was not same.
10447 //View 8-bit element as 16-bit => a3 a2 a1 a0
10448 //(a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
10449 vtemp32d = vpaddl_u16(vAd);
10450 vtemp32d = vpadd_u32(vtemp32d, vtemp32d);
10451 sum = vget_lane_u32(vtemp32d, 0);
10452
10453 //0x0001fffe + 0x0001fffe = 0x0003fffc when all same.
10454 if(sum != 0x0003fffcU)
10455 {
10456 return(mDNSfalse);
10457 }
10458 #endif
10459
10460 len_count -= 8;
10461 }
10462
10463 while(len_count > 0)
10464 {
10465 mDNSu8 ac = *a++;
10466 mDNSu8 bc = *b++;
10467
10468 ac += upper_to_lower_case_table[ac];
10469 bc += upper_to_lower_case_table[bc];
10470
10471 if (ac != bc)
10472 {
10473 return(mDNSfalse);
10474 }
10475
10476 len_count -= 1;
10477 }
10478 return(mDNStrue);
10479 }
10480
10481 // Use vectorized implementation if it is supported on this platform.
10482 mDNSlocal void setSameDomainLabelPointer(void)
10483 {
10484 if(_cpu_capabilities & kHasNeon)
10485 {
10486 // Use Neon Code
10487 SameDomainLabelPointer = vectorSameDomainLabel;
10488 LogMsg("setSameDomainLabelPointer: using vector code");
10489 }
10490 else
10491 LogMsg("setSameDomainLabelPointer: using scalar code");
10492 }
10493
10494 #else // TARGET_OS_EMBEDDED
10495
10496 #include <smmintrin.h>
10497
10498 // Cache line aligned table that returns 32 for the upper case letters.
10499 // This will take up 4 cache lines.
10500 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table[256] = {
10501 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10502 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10503 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10504 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10505 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
10506 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
10507 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10508 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10510 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10511 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10512 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10513 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10514 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10515 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10516 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
10517 };
10518
10519 // SSE2 version
10520 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10521 {
10522 const int len = *a++;
10523
10524 if (len > MAX_DOMAIN_LABEL)
10525 {
10526 fprintf(stderr, "v: Malformed label (too long)\n");
10527 return(mDNSfalse);
10528 }
10529
10530 if (len != *b++)
10531 {
10532 return(mDNSfalse);
10533 }
10534
10535 uint32_t len_count = len;
10536
10537 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 };
10538 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 };
10539 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 };
10540 __m128i v37 = _mm_load_si128((__m128i*)c_37);
10541 __m128i v101 = _mm_load_si128((__m128i*)c_101);
10542 __m128i v32 = _mm_load_si128((__m128i*)c_32);
10543
10544 uint32_t is_equal;
10545 __m128i vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
10546
10547 //AVX code that uses higher bandwidth (more elements per vector) was removed
10548 //to speed up the processing on the small sizes.
10549 //When I had them, the performance of 1 ~ 8 characters were slower by about 10% ~ 30%.
10550 while(len_count > 15)
10551 {
10552 vA = _mm_loadu_si128((__m128i*)a);
10553 vB = _mm_loadu_si128((__m128i*)b);
10554 a += 16;
10555 b += 16;
10556
10557 //Make vA to lowercase if there is any uppercase.
10558 vARotated = _mm_add_epi8(vA, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10559 vMaskA = _mm_cmpgt_epi8(vARotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10560 vMaskA = _mm_and_si128(vMaskA, v32); //Prepare 32 for the elements with uppercase letters.
10561 vA = _mm_add_epi8(vA, vMaskA); //Add 32 only to the uppercase letters to make them lowercase letters.
10562
10563 //Make vB to lowercase if there is any uppercase.
10564 vBRotated = _mm_add_epi8(vB, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10565 vMaskB = _mm_cmpgt_epi8(vBRotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10566 vMaskB = _mm_and_si128(vMaskB, v32); //Prepare 32 for the elements with uppercase letters.
10567 vB = _mm_add_epi8(vB, vMaskB); //Add 32 only to the uppercase letters to make them lowercase letters.
10568
10569 //Compare vA & vB
10570 vA = _mm_cmpeq_epi8(vA, vB);
10571
10572 //Return if any different.
10573 is_equal = _mm_movemask_epi8(vA);
10574 is_equal = is_equal & 0xffff;
10575 if(is_equal != 0xffff)
10576 {
10577 return(mDNSfalse);
10578 }
10579
10580 len_count -= 16;
10581 }
10582
10583 while(len_count > 0)
10584 {
10585 mDNSu8 ac = *a++;
10586 mDNSu8 bc = *b++;
10587
10588 //Table will return 32 for upper case letters only.
10589 //0 will be returned for all others.
10590 ac += upper_to_lower_case_table[ac];
10591 bc += upper_to_lower_case_table[bc];
10592
10593 //Return if a & b are different.
10594 if (ac != bc)
10595 {
10596 return(mDNSfalse);
10597 }
10598
10599 len_count -= 1;
10600 }
10601 return(mDNStrue);
10602 }
10603
10604 // Use vectorized implementation if it is supported on this platform.
10605 mDNSlocal void setSameDomainLabelPointer(void)
10606 {
10607 if(_cpu_capabilities & kHasSSE4_1)
10608 {
10609 // Use SSE Code
10610 SameDomainLabelPointer = vectorSameDomainLabel;
10611 LogMsg("setSameDomainLabelPointer: using vector code");
10612 }
10613 else
10614 LogMsg("setSameDomainLabelPointer: using scalar code");
10615 }
10616
10617 #endif // TARGET_OS_EMBEDDED
10618
10619 // Original SameDomainLabel() implementation.
10620 mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10621 {
10622 int i;
10623 const int len = *a++;
10624
10625 if (len > MAX_DOMAIN_LABEL)
10626 { debugf("Malformed label (too long)"); return(mDNSfalse); }
10627
10628 if (len != *b++) return(mDNSfalse);
10629 for (i=0; i<len; i++)
10630 {
10631 mDNSu8 ac = *a++;
10632 mDNSu8 bc = *b++;
10633 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
10634 if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
10635 if (ac != bc) return(mDNSfalse);
10636 }
10637 return(mDNStrue);
10638 }
10639
10640 mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10641 {
10642 return (*SameDomainLabelPointer)(a, b);
10643 }
10644
10645 #endif // APPLE_OSX_mDNSResponder
10646
10647
10648 #ifdef UNIT_TEST
10649 #include "../unittests/mdns_macosx_ut.c"
10650 #endif
10651