]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mDNSMacOSX.c
mDNSResponder-878.260.1.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 mDNSlocal 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_flags & MSG_CTRUNC)
857 {
858 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
859 return(-1);
860 }
861 *fromlen = msg.msg_namelen;
862
863 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
864 {
865 if (numLogMessages++ < 100)
866 {
867 LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %ld msg.msg_controllen %lu < sizeof(struct cmsghdr) %lu",
868 s, (long)n, (unsigned long)msg.msg_controllen, (unsigned long)sizeof(struct cmsghdr));
869 }
870 goto exit;
871 }
872 // Parse each option out of the ancillary data.
873 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
874 {
875 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
876 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
877 {
878 dstaddr->type = mDNSAddrType_IPv4;
879 dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
880 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
881 }
882 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
883 {
884 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
885 if (sdl->sdl_nlen < IF_NAMESIZE)
886 {
887 mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
888 ifname[sdl->sdl_nlen] = 0;
889 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
890 }
891 }
892 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
893 *ttl = *(u_char*)CMSG_DATA(cmPtr);
894 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
895 {
896 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
897 dstaddr->type = mDNSAddrType_IPv6;
898 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
899 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
900 }
901 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
902 *ttl = *(int*)CMSG_DATA(cmPtr);
903 }
904
905 exit:
906 return(n);
907 }
908
909 // What is this for, and why does it use xor instead of a simple quality check? -- SC
910 mDNSlocal mDNSInterfaceID FindMyInterface(const mDNSAddr *addr)
911 {
912 NetworkInterfaceInfo *intf;
913
914 if (addr->type == mDNSAddrType_IPv4)
915 {
916 for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
917 {
918 if (intf->ip.type == addr->type && intf->McastTxRx)
919 {
920 if ((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) == 0)
921 {
922 return(intf->InterfaceID);
923 }
924 }
925 }
926 }
927
928 if (addr->type == mDNSAddrType_IPv6)
929 {
930 for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
931 {
932 if (intf->ip.type == addr->type && intf->McastTxRx)
933 {
934 if (((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) == 0) &&
935 ((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) == 0) &&
936 ((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) == 0) &&
937 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) == 0)))
938 {
939 return(intf->InterfaceID);
940 }
941 }
942 }
943 }
944 return(mDNSInterface_Any);
945 }
946
947 mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool encounteredEOF)
948 {
949 KQSocketSet *const ss = (KQSocketSet *)context;
950 mDNS *const m = ss->m;
951 int err = 0, count = 0, closed = 0;
952
953 if (filter != EVFILT_READ)
954 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
955
956 if (s1 != ss->sktv4 && s1 != ss->sktv6)
957 {
958 LogMsg("myKQSocketCallBack: native socket %d", s1);
959 LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6);
960 }
961
962 if (encounteredEOF)
963 {
964 LogMsg("myKQSocketCallBack: socket %d is no longer readable (EOF)", s1);
965 if (s1 == ss->sktv4)
966 {
967 ss->sktv4EOF = mDNStrue;
968 KQueueSet(ss->sktv4, EV_DELETE, EVFILT_READ, &ss->kqsv4);
969 }
970 else if (s1 == ss->sktv6)
971 {
972 ss->sktv6EOF = mDNStrue;
973 KQueueSet(ss->sktv6, EV_DELETE, EVFILT_READ, &ss->kqsv6);
974 }
975 return;
976 }
977
978 while (!closed)
979 {
980 mDNSAddr senderAddr, destAddr = zeroAddr;
981 mDNSIPPort senderPort;
982 struct sockaddr_storage from;
983 size_t fromlen = sizeof(from);
984 char packetifname[IF_NAMESIZE] = "";
985 mDNSu8 ttl;
986 err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
987 if (err < 0) break;
988
989 if ((destAddr.type == mDNSAddrType_IPv4 && (destAddr.ip.v4.b[0] & 0xF0) == 0xE0) ||
990 (destAddr.type == mDNSAddrType_IPv6 && (destAddr.ip.v6.b[0] == 0xFF))) m->p->num_mcasts++;
991
992 count++;
993 if (from.ss_family == AF_INET)
994 {
995 struct sockaddr_in *s = (struct sockaddr_in*)&from;
996 senderAddr.type = mDNSAddrType_IPv4;
997 senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
998 senderPort.NotAnInteger = s->sin_port;
999 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1000 }
1001 else if (from.ss_family == AF_INET6)
1002 {
1003 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
1004 senderAddr.type = mDNSAddrType_IPv6;
1005 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
1006 senderPort.NotAnInteger = sin6->sin6_port;
1007 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1008 }
1009 else
1010 {
1011 LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
1012 return;
1013 }
1014
1015 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1016 mDNSInterfaceID InterfaceID = mDNSNULL;
1017 NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
1018 while (intf)
1019 {
1020 if (intf->Exists && !strcmp(intf->ifinfo.ifname, packetifname))
1021 break;
1022 intf = intf->next;
1023 }
1024
1025 // When going to sleep we deregister all our interfaces, but if the machine
1026 // takes a few seconds to sleep we may continue to receive multicasts
1027 // during that time, which would confuse mDNSCoreReceive, because as far
1028 // as it's concerned, we should have no active interfaces any more.
1029 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1030 if (intf)
1031 InterfaceID = intf->ifinfo.InterfaceID;
1032 else if (mDNSAddrIsDNSMulticast(&destAddr))
1033 continue;
1034
1035 if (!InterfaceID)
1036 {
1037 InterfaceID = FindMyInterface(&destAddr);
1038 }
1039
1040 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1041 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
1042
1043 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
1044 // loop when that happens, or we may try to read from an invalid FD. We do this by
1045 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
1046 // if it closes the socketset.
1047 ss->closeFlag = &closed;
1048
1049 if (ss->proxy)
1050 {
1051 m->p->UDPProxyCallback(&m->p->UDPProxy, &m->imsg.m, (unsigned char*)&m->imsg + err, &senderAddr,
1052 senderPort, &destAddr, ss->port, InterfaceID, NULL);
1053 }
1054 else
1055 {
1056 mDNSCoreReceive(m, &m->imsg.m, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
1057 }
1058
1059 // if we didn't close, we can safely dereference the socketset, and should to
1060 // reset the closeFlag, since it points to something on the stack
1061 if (!closed) ss->closeFlag = mDNSNULL;
1062 }
1063
1064 // If a client application's sockets are marked as defunct
1065 // sockets we have delegated to it with SO_DELEGATED will also go defunct.
1066 // We get an ENOTCONN error for defunct sockets and should just close the socket in that case.
1067 if (err < 0 && errno == ENOTCONN)
1068 {
1069 LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
1070 close(s1);
1071 return;
1072 }
1073
1074 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
1075 {
1076 // Something is busted here.
1077 // kqueue says there is a packet, but myrecvfrom says there is not.
1078 // Try calling select() to get another opinion.
1079 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1080 // All of this is racy, as data may have arrived after the call to select()
1081 static unsigned int numLogMessages = 0;
1082 const int save_errno = errno;
1083 int so_error = -1;
1084 int so_nread = -1;
1085 int fionread = -1;
1086 socklen_t solen = sizeof(int);
1087 fd_set readfds;
1088 struct timeval timeout;
1089 int selectresult;
1090 FD_ZERO(&readfds);
1091 FD_SET(s1, &readfds);
1092 timeout.tv_sec = 0;
1093 timeout.tv_usec = 0;
1094 selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
1095 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
1096 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
1097 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
1098 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
1099 if (ioctl(s1, FIONREAD, &fionread) == -1)
1100 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
1101 if (numLogMessages++ < 100)
1102 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1103 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
1104 if (numLogMessages > 5)
1105 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1106 "Congratulations, you've reproduced an elusive bug.\r"
1107 "Please send email to radar-3387020@group.apple.com.)\r"
1108 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1109
1110 sleep(1); // After logging this error, rate limit so we don't flood syslog
1111 }
1112 }
1113
1114 mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
1115 {
1116 mDNSBool c = !sock->connected;
1117 sock->connected = mDNStrue;
1118 sock->callback(sock, sock->context, c, sock->err);
1119 // Note: the callback may call CloseConnection here, which frees the context structure!
1120 }
1121
1122 #ifndef NO_SECURITYFRAMEWORK
1123
1124 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
1125 {
1126 int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1127 if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1128 if (ret >= 0) { *dataLength = ret; return(noErr); }
1129 *dataLength = 0;
1130 if (errno == EAGAIN ) return(errSSLWouldBlock);
1131 if (errno == ENOENT ) return(errSSLClosedGraceful);
1132 if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
1133 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
1134 return(errSSLClosedAbort);
1135 }
1136
1137 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
1138 {
1139 int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1140 if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1141 if (ret > 0) { *dataLength = ret; return(noErr); }
1142 *dataLength = 0;
1143 if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
1144 if ( errno == EAGAIN ) return(errSSLWouldBlock);
1145 if ( errno == ECONNRESET) return(errSSLClosedAbort);
1146 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
1147 return(errSSLClosedAbort);
1148 }
1149
1150 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConnectionType ctype)
1151 {
1152 char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
1153
1154 sock->tlsContext = SSLCreateContext(kCFAllocatorDefault, pside, ctype);
1155 if (!sock->tlsContext)
1156 {
1157 LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
1158 return(mStatus_UnknownErr);
1159 }
1160
1161 mStatus err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
1162 if (err)
1163 {
1164 LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err);
1165 goto fail;
1166 }
1167
1168 err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
1169 if (err)
1170 {
1171 LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err);
1172 goto fail;
1173 }
1174
1175 // Set the default ciphersuite configuration
1176 err = SSLSetSessionConfig(sock->tlsContext, CFSTR("default"));
1177 if (err)
1178 {
1179 LogMsg("ERROR: tlsSetupSock: SSLSetSessionConfig failed with error code: %d", err);
1180 goto fail;
1181 }
1182
1183 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
1184 // (error not in OSStatus space) is okay.
1185 if (!sock->hostname.c[0])
1186 {
1187 LogMsg("ERROR: tlsSetupSock: hostname NULL");
1188 err = -1;
1189 goto fail;
1190 }
1191
1192 ConvertDomainNameToCString(&sock->hostname, domname_cstr);
1193 err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
1194 if (err)
1195 {
1196 LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err);
1197 goto fail;
1198 }
1199
1200 return(err);
1201
1202 fail:
1203 if (sock->tlsContext)
1204 CFRelease(sock->tlsContext);
1205 return(err);
1206 }
1207
1208 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1209 mDNSlocal void doSSLHandshake(TCPSocket *sock)
1210 {
1211 mStatus err = SSLHandshake(sock->tlsContext);
1212
1213 //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
1214 //defined, KQueueLock is a noop. Hence we need to serialize here
1215 //
1216 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
1217 //We need the rest of the logic also. Otherwise, we can enable the READ
1218 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
1219 //ConnFailed which means we are going to free the tcpInfo. While it
1220 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
1221 //and potentially call doTCPCallback with error which can close the fd and free the
1222 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
1223 //is already freed.
1224
1225 dispatch_async(dispatch_get_main_queue(), ^{
1226
1227 LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1228
1229 if (sock->handshake == handshake_to_be_closed)
1230 {
1231 LogInfo("SSLHandshake completed after close");
1232 mDNSPlatformTCPCloseConnection(sock);
1233 }
1234 else
1235 {
1236 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1237 else LogMsg("doSSLHandshake: sock->fd is -1");
1238
1239 if (err == errSSLWouldBlock)
1240 sock->handshake = handshake_required;
1241 else
1242 {
1243 if (err)
1244 {
1245 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1246 CFRelease(sock->tlsContext);
1247 sock->tlsContext = NULL;
1248 }
1249
1250 sock->err = err ? mStatus_ConnFailed : 0;
1251 sock->handshake = handshake_completed;
1252
1253 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1254 doTcpSocketCallback(sock);
1255 }
1256 }
1257
1258 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1259 return;
1260 });
1261 }
1262 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1263 mDNSlocal void *doSSLHandshake(TCPSocket *sock)
1264 {
1265 // Warning: Touching sock without the kqueue lock!
1266 // We're protected because sock->handshake == handshake_in_progress
1267 mStatus err = SSLHandshake(sock->tlsContext);
1268
1269 KQueueLock();
1270 debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1271
1272 if (sock->handshake == handshake_to_be_closed)
1273 {
1274 LogInfo("SSLHandshake completed after close");
1275 mDNSPlatformTCPCloseConnection(sock);
1276 }
1277 else
1278 {
1279 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1280 else LogMsg("doSSLHandshake: sock->fd is -1");
1281
1282 if (err == errSSLWouldBlock)
1283 sock->handshake = handshake_required;
1284 else
1285 {
1286 if (err)
1287 {
1288 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1289 CFRelease(sock->tlsContext);
1290 sock->tlsContext = NULL;
1291 }
1292
1293 sock->err = err ? mStatus_ConnFailed : 0;
1294 sock->handshake = handshake_completed;
1295
1296 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1297 doTcpSocketCallback(sock);
1298 }
1299 }
1300
1301 debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1302 KQueueUnlock("doSSLHandshake");
1303 return NULL;
1304 }
1305 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1306
1307 mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
1308 {
1309 debugf("spawnSSLHandshake %p: entry", sock);
1310
1311 if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
1312 sock->handshake = handshake_in_progress;
1313 KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
1314
1315 // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
1316 // to limit the number of threads used for SSLHandshake
1317 dispatch_async(SSLqueue, ^{doSSLHandshake(sock);});
1318
1319 debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
1320 }
1321
1322 #endif /* NO_SECURITYFRAMEWORK */
1323
1324 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context, __unused mDNSBool encounteredEOF)
1325 {
1326 TCPSocket *sock = context;
1327 sock->err = mStatus_NoError;
1328
1329 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1330 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1331 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1332 if (filter == EVFILT_WRITE)
1333 KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
1334
1335 if (sock->flags & kTCPSocketFlags_UseTLS)
1336 {
1337 #ifndef NO_SECURITYFRAMEWORK
1338 if (!sock->setup)
1339 {
1340 sock->setup = mDNStrue;
1341 sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
1342 if (sock->err)
1343 {
1344 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
1345 return;
1346 }
1347 }
1348 if (sock->handshake == handshake_required)
1349 {
1350 spawnSSLHandshake(sock);
1351 return;
1352 }
1353 else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
1354 {
1355 return;
1356 }
1357 else if (sock->handshake != handshake_completed)
1358 {
1359 if (!sock->err)
1360 sock->err = mStatus_UnknownErr;
1361 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
1362 }
1363 #else /* NO_SECURITYFRAMEWORK */
1364 sock->err = mStatus_UnsupportedErr;
1365 #endif /* NO_SECURITYFRAMEWORK */
1366 }
1367
1368 doTcpSocketCallback(sock);
1369 }
1370
1371 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1372 mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef)
1373 {
1374 dispatch_queue_t queue = dispatch_get_main_queue();
1375 dispatch_source_t source;
1376 if (flags == EV_DELETE)
1377 {
1378 if (filter == EVFILT_READ)
1379 {
1380 dispatch_source_cancel(entryRef->readSource);
1381 dispatch_release(entryRef->readSource);
1382 entryRef->readSource = mDNSNULL;
1383 debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource);
1384 }
1385 else if (filter == EVFILT_WRITE)
1386 {
1387 dispatch_source_cancel(entryRef->writeSource);
1388 dispatch_release(entryRef->writeSource);
1389 entryRef->writeSource = mDNSNULL;
1390 debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource);
1391 }
1392 else
1393 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
1394 return 0;
1395 }
1396 if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
1397
1398 if (filter == EVFILT_READ)
1399 {
1400 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
1401 }
1402 else if (filter == EVFILT_WRITE)
1403 {
1404 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
1405 }
1406 else
1407 {
1408 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
1409 return -1;
1410 }
1411 if (!source) return -1;
1412 dispatch_source_set_event_handler(source, ^{
1413
1414 mDNSs32 stime = mDNSPlatformRawTime();
1415 entryRef->KQcallback(fd, filter, entryRef->KQcontext);
1416 mDNSs32 etime = mDNSPlatformRawTime();
1417 if (etime - stime >= WatchDogReportingThreshold)
1418 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime);
1419
1420 // Trigger the event delivery to the application. Even though we trigger the
1421 // event completion after handling every event source, these all will hopefully
1422 // get merged
1423 TriggerEventCompletion();
1424
1425 });
1426 dispatch_source_set_cancel_handler(source, ^{
1427 if (entryRef->fdClosed)
1428 {
1429 //LogMsg("CancelHandler: closing fd %d", fd);
1430 close(fd);
1431 }
1432 });
1433 dispatch_resume(source);
1434 if (filter == EVFILT_READ)
1435 entryRef->readSource = source;
1436 else
1437 entryRef->writeSource = source;
1438
1439 return 0;
1440 }
1441
1442 mDNSexport void KQueueLock()
1443 {
1444 }
1445 mDNSexport void KQueueUnlock(const char const *task)
1446 {
1447 (void)task; //unused
1448 }
1449 #else
1450 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
1451 {
1452 struct kevent new_event;
1453 EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
1454 return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
1455 }
1456
1457 mDNSexport void KQueueLock()
1458 {
1459 mDNS *const m = &mDNSStorage;
1460 pthread_mutex_lock(&m->p->BigMutex);
1461 m->p->BigMutexStartTime = mDNSPlatformRawTime();
1462 }
1463
1464 mDNSexport void KQueueUnlock(const char* task)
1465 {
1466 mDNS *const m = &mDNSStorage;
1467 mDNSs32 end = mDNSPlatformRawTime();
1468 (void)task;
1469 if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
1470 LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
1471
1472 pthread_mutex_unlock(&m->p->BigMutex);
1473
1474 char wake = 1;
1475 if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
1476 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
1477 }
1478 #endif
1479
1480 mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
1481 {
1482 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1483 (void) fd; //unused
1484 if (kq->readSource)
1485 {
1486 dispatch_source_cancel(kq->readSource);
1487 kq->readSource = mDNSNULL;
1488 }
1489 if (kq->writeSource)
1490 {
1491 dispatch_source_cancel(kq->writeSource);
1492 kq->writeSource = mDNSNULL;
1493 }
1494 // Close happens in the cancellation handler
1495 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
1496 kq->fdClosed = mDNStrue;
1497 #else
1498 (void)kq; //unused
1499 close(fd);
1500 #endif
1501 }
1502
1503 mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
1504 {
1505 KQSocketSet *cp = &sock->ss;
1506 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
1507 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
1508 const int on = 1; // "on" for setsockopt
1509 mStatus err;
1510
1511 int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
1512 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
1513
1514 // for TCP sockets, the traffic class is set once and not changed
1515 setTrafficClass(skt, useBackgroundTrafficClass);
1516
1517 if (sa_family == AF_INET)
1518 {
1519 // Bind it
1520 struct sockaddr_in addr;
1521 mDNSPlatformMemZero(&addr, sizeof(addr));
1522 addr.sin_family = AF_INET;
1523 addr.sin_port = port->NotAnInteger;
1524 err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
1525 if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); close(skt); return err; }
1526
1527 // Receive interface identifiers
1528 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
1529 if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); close(skt); return err; }
1530
1531 mDNSPlatformMemZero(&addr, sizeof(addr));
1532 socklen_t len = sizeof(addr);
1533 err = getsockname(skt, (struct sockaddr*) &addr, &len);
1534 if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); close(skt); return err; }
1535
1536 port->NotAnInteger = addr.sin_port;
1537 }
1538 else
1539 {
1540 // Bind it
1541 struct sockaddr_in6 addr6;
1542 mDNSPlatformMemZero(&addr6, sizeof(addr6));
1543 addr6.sin6_family = AF_INET6;
1544 addr6.sin6_port = port->NotAnInteger;
1545 err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
1546 if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); close(skt); return err; }
1547
1548 // We want to receive destination addresses and receive interface identifiers
1549 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
1550 if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); close(skt); return err; }
1551
1552 mDNSPlatformMemZero(&addr6, sizeof(addr6));
1553 socklen_t len = sizeof(addr6);
1554 err = getsockname(skt, (struct sockaddr *) &addr6, &len);
1555 if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); close(skt); return err; }
1556
1557 port->NotAnInteger = addr6.sin6_port;
1558
1559 }
1560 *s = skt;
1561 k->KQcallback = tcpKQSocketCallback;
1562 k->KQcontext = sock;
1563 k->KQtask = "mDNSPlatformTCPSocket";
1564 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1565 k->readSource = mDNSNULL;
1566 k->writeSource = mDNSNULL;
1567 k->fdClosed = mDNSfalse;
1568 #endif
1569 return mStatus_NoError;
1570 }
1571
1572 mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
1573 {
1574 mStatus err;
1575
1576 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
1577 if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
1578
1579 mDNSPlatformMemZero(sock, sizeof(TCPSocket));
1580
1581 sock->ss.m = &mDNSStorage;
1582 sock->ss.sktv4 = -1;
1583 sock->ss.sktv6 = -1;
1584 err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
1585
1586 if (!err)
1587 {
1588 err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass);
1589 if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
1590 }
1591 if (err)
1592 {
1593 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
1594 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
1595 return(mDNSNULL);
1596 }
1597 // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
1598 sock->fd = sock->ss.sktv4;
1599 sock->callback = mDNSNULL;
1600 sock->flags = flags;
1601 sock->context = mDNSNULL;
1602 sock->setup = mDNSfalse;
1603 sock->connected = mDNSfalse;
1604 sock->handshake = handshake_required;
1605 sock->m = &mDNSStorage;
1606 sock->err = mStatus_NoError;
1607
1608 return sock;
1609 }
1610
1611 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
1612 {
1613 KQSocketSet *cp = &sock->ss;
1614 int *s = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
1615 KQueueEntry *k = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
1616 mStatus err = mStatus_NoError;
1617 struct sockaddr_storage ss;
1618
1619 sock->callback = callback;
1620 sock->context = context;
1621 sock->setup = mDNSfalse;
1622 sock->connected = mDNSfalse;
1623 sock->handshake = handshake_required;
1624 sock->err = mStatus_NoError;
1625
1626 if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
1627
1628 if (dst->type == mDNSAddrType_IPv4)
1629 {
1630 struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
1631 mDNSPlatformMemZero(saddr, sizeof(*saddr));
1632 saddr->sin_family = AF_INET;
1633 saddr->sin_port = dstport.NotAnInteger;
1634 saddr->sin_len = sizeof(*saddr);
1635 saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1636 }
1637 else
1638 {
1639 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss;
1640 mDNSPlatformMemZero(saddr6, sizeof(*saddr6));
1641 saddr6->sin6_family = AF_INET6;
1642 saddr6->sin6_port = dstport.NotAnInteger;
1643 saddr6->sin6_len = sizeof(*saddr6);
1644 saddr6->sin6_addr = *(struct in6_addr *)&dst->ip.v6;
1645 }
1646
1647 // Watch for connect complete (write is ready)
1648 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1649 if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
1650 {
1651 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1652 return errno;
1653 }
1654
1655 // Watch for incoming data
1656 if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
1657 {
1658 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1659 return errno;
1660 }
1661
1662 if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
1663 {
1664 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
1665 return mStatus_UnknownErr;
1666 }
1667
1668 // We bind to the interface and all subsequent packets including the SYN will be sent out
1669 // on this interface
1670 //
1671 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
1672 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
1673 if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
1674 {
1675 NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(InterfaceID);
1676 if (dst->type == mDNSAddrType_IPv4)
1677 {
1678 #ifdef IP_BOUND_IF
1679 if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1680 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
1681 #else
1682 (void)InterfaceID; // Unused
1683 (void)info; // Unused
1684 #endif
1685 }
1686 else
1687 {
1688 #ifdef IPV6_BOUND_IF
1689 if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1690 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
1691 #else
1692 (void)InterfaceID; // Unused
1693 (void)info; // Unused
1694 #endif
1695 }
1696 }
1697
1698 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
1699 // from which we can infer the destination address family. Hence we need to remember that here.
1700 // Instead of remembering the address family, we remember the right fd.
1701 sock->fd = *s;
1702 sock->kqEntry = k;
1703 // initiate connection wth peer
1704 if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
1705 {
1706 if (errno == EINPROGRESS) return mStatus_ConnPending;
1707 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
1708 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
1709 else
1710 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
1711 return mStatus_ConnFailed;
1712 }
1713
1714 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1715 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1716 return err;
1717 }
1718
1719 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1720 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
1721 {
1722 mStatus err = mStatus_NoError;
1723
1724 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
1725 if (!sock) return(mDNSNULL);
1726
1727 mDNSPlatformMemZero(sock, sizeof(*sock));
1728 sock->fd = fd;
1729 sock->flags = flags;
1730
1731 if (flags & kTCPSocketFlags_UseTLS)
1732 {
1733 #ifndef NO_SECURITYFRAMEWORK
1734 if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
1735
1736 err = tlsSetupSock(sock, kSSLServerSide, kSSLStreamType);
1737 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
1738
1739 err = SSLSetCertificate(sock->tlsContext, ServerCerts);
1740 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
1741 #else
1742 err = mStatus_UnsupportedErr;
1743 #endif /* NO_SECURITYFRAMEWORK */
1744 }
1745 #ifndef NO_SECURITYFRAMEWORK
1746 exit:
1747 #endif
1748
1749 if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
1750 return(sock);
1751 }
1752
1753 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
1754 {
1755 mDNSu16 port;
1756
1757 port = -1;
1758 if (sock)
1759 {
1760 port = sock->ss.port.NotAnInteger;
1761 }
1762 return port;
1763 }
1764
1765 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
1766 {
1767 if (ss->sktv4 != -1)
1768 {
1769 mDNSPlatformCloseFD(&ss->kqsv4, ss->sktv4);
1770 ss->sktv4 = -1;
1771 }
1772 if (ss->sktv6 != -1)
1773 {
1774 mDNSPlatformCloseFD(&ss->kqsv6, ss->sktv6);
1775 ss->sktv6 = -1;
1776 }
1777 if (ss->closeFlag) *ss->closeFlag = 1;
1778 }
1779
1780 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
1781 {
1782 if (sock)
1783 {
1784 #ifndef NO_SECURITYFRAMEWORK
1785 if (sock->tlsContext)
1786 {
1787 if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
1788 {
1789 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
1790 // When we come back from SSLHandshake, we will notice that a close was here and
1791 // call this function again which will do the cleanup then.
1792 sock->handshake = handshake_to_be_closed;
1793 return;
1794 }
1795
1796 SSLClose(sock->tlsContext);
1797 CFRelease(sock->tlsContext);
1798 sock->tlsContext = NULL;
1799 }
1800 #endif /* NO_SECURITYFRAMEWORK */
1801 if (sock->ss.sktv4 != -1)
1802 shutdown(sock->ss.sktv4, 2);
1803 if (sock->ss.sktv6 != -1)
1804 shutdown(sock->ss.sktv6, 2);
1805 CloseSocketSet(&sock->ss);
1806 sock->fd = -1;
1807
1808 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
1809 }
1810 }
1811
1812 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
1813 {
1814 ssize_t nread = 0;
1815 *closed = mDNSfalse;
1816
1817 if (sock->flags & kTCPSocketFlags_UseTLS)
1818 {
1819 #ifndef NO_SECURITYFRAMEWORK
1820 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
1821 else if (sock->handshake == handshake_in_progress) return 0;
1822 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
1823
1824 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
1825 mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t *)&nread);
1826 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
1827 if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
1828 else if (err && err != errSSLWouldBlock)
1829 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
1830 #else
1831 nread = -1;
1832 *closed = mDNStrue;
1833 #endif /* NO_SECURITYFRAMEWORK */
1834 }
1835 else
1836 {
1837 static int CLOSEDcount = 0;
1838 static int EAGAINcount = 0;
1839 nread = recv(sock->fd, buf, buflen, 0);
1840
1841 if (nread > 0)
1842 {
1843 CLOSEDcount = 0;
1844 EAGAINcount = 0;
1845 } // On success, clear our error counters
1846 else if (nread == 0)
1847 {
1848 *closed = mDNStrue;
1849 if ((++CLOSEDcount % 1000) == 0)
1850 {
1851 LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount);
1852 assert(CLOSEDcount < 1000);
1853 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
1854 // crash mDNSResponder using assert() and restart fresh. See advantages below:
1855 // 1.Better User Experience
1856 // 2.CrashLogs frequency can be monitored
1857 // 3.StackTrace can be used for more info
1858 }
1859 }
1860 // else nread is negative -- see what kind of error we got
1861 else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
1862 else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
1863 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
1864 {
1865 nread = 0;
1866 if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
1867 }
1868 }
1869
1870 return nread;
1871 }
1872
1873 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
1874 {
1875 int nsent;
1876
1877 if (sock->flags & kTCPSocketFlags_UseTLS)
1878 {
1879 #ifndef NO_SECURITYFRAMEWORK
1880 size_t processed;
1881 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
1882 if (sock->handshake == handshake_in_progress) return 0;
1883 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
1884
1885 mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
1886
1887 if (!err) nsent = (int) processed;
1888 else if (err == errSSLWouldBlock) nsent = 0;
1889 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
1890 #else
1891 nsent = -1;
1892 #endif /* NO_SECURITYFRAMEWORK */
1893 }
1894 else
1895 {
1896 nsent = send(sock->fd, msg, len, 0);
1897 if (nsent < 0)
1898 {
1899 if (errno == EAGAIN) nsent = 0;
1900 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
1901 }
1902 }
1903
1904 return nsent;
1905 }
1906
1907 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
1908 {
1909 return sock->fd;
1910 }
1911
1912 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1913 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1914 mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
1915 {
1916 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
1917 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
1918 const int on = 1;
1919 const int twofivefive = 255;
1920 mStatus err = mStatus_NoError;
1921 char *errstr = mDNSNULL;
1922 const int mtu = 0;
1923 int saved_errno;
1924
1925 cp->closeFlag = mDNSNULL;
1926
1927 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
1928 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
1929
1930 // set default traffic class
1931 setTrafficClass(skt, mDNSfalse);
1932
1933 #ifdef SO_RECV_ANYIF
1934 // Enable inbound packets on IFEF_AWDL interface.
1935 // Only done for multicast sockets, since we don't expect unicast socket operations
1936 // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
1937 if (mDNSSameIPPort(port, MulticastDNSPort))
1938 {
1939 err = setsockopt(skt, SOL_SOCKET, SO_RECV_ANYIF, &on, sizeof(on));
1940 if (err < 0) { errstr = "setsockopt - SO_RECV_ANYIF"; goto fail; }
1941 }
1942 #endif // SO_RECV_ANYIF
1943
1944 // ... with a shared UDP port, if it's for multicast receiving
1945 if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort))
1946 {
1947 err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
1948 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
1949 }
1950
1951 // Don't want to wake from sleep for inbound packets on the mDNS sockets
1952 if (mDNSSameIPPort(port, MulticastDNSPort))
1953 {
1954 int nowake = 1;
1955 if (setsockopt(skt, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
1956 LogInfo("SetupSocket: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
1957 }
1958
1959 if (sa_family == AF_INET)
1960 {
1961 // We want to receive destination addresses
1962 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
1963 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
1964
1965 // We want to receive interface identifiers
1966 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
1967 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
1968
1969 // We want to receive packet TTL value so we can check it
1970 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
1971 if (err < 0) { errstr = "setsockopt - IP_RECVTTL"; goto fail; }
1972
1973 // Send unicast packets with TTL 255
1974 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
1975 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
1976
1977 // And multicast packets with TTL 255 too
1978 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
1979 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
1980
1981 // And start listening for packets
1982 struct sockaddr_in listening_sockaddr;
1983 listening_sockaddr.sin_family = AF_INET;
1984 listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
1985 listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0;
1986 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
1987 if (err) { errstr = "bind"; goto fail; }
1988 if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
1989 }
1990 else if (sa_family == AF_INET6)
1991 {
1992 // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
1993 if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; close(skt); return mStatus_NoError; }
1994
1995 // We want to receive destination addresses and receive interface identifiers
1996 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
1997 if (err < 0) { errstr = "setsockopt - IPV6_RECVPKTINFO"; goto fail; }
1998
1999 // We want to receive packet hop count value so we can check it
2000 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
2001 if (err < 0) { errstr = "setsockopt - IPV6_RECVHOPLIMIT"; goto fail; }
2002
2003 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
2004 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
2005 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
2006 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
2007
2008 // Send unicast packets with TTL 255
2009 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
2010 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
2011
2012 // And multicast packets with TTL 255 too
2013 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
2014 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
2015
2016 // Want to receive our own packets
2017 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
2018 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
2019
2020 // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
2021 err = setsockopt(skt, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &mtu, sizeof(mtu));
2022 if (err < 0) // Since it is an optimization if we fail just log the err, no need to close the skt
2023 LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
2024 skt, err, errno, strerror(errno));
2025
2026 // And start listening for packets
2027 struct sockaddr_in6 listening_sockaddr6;
2028 mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
2029 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
2030 listening_sockaddr6.sin6_family = AF_INET6;
2031 listening_sockaddr6.sin6_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
2032 listening_sockaddr6.sin6_flowinfo = 0;
2033 listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
2034 listening_sockaddr6.sin6_scope_id = 0;
2035 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
2036 if (err) { errstr = "bind"; goto fail; }
2037 if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
2038 }
2039
2040 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
2041 fcntl(skt, F_SETFD, 1); // set close-on-exec
2042 *s = skt;
2043 k->KQcallback = myKQSocketCallBack;
2044 k->KQcontext = cp;
2045 k->KQtask = "UDP packet reception";
2046 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2047 k->readSource = mDNSNULL;
2048 k->writeSource = mDNSNULL;
2049 k->fdClosed = mDNSfalse;
2050 #endif
2051 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
2052
2053 return(mStatus_NoError);
2054
2055 fail:
2056 saved_errno = errno;
2057 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
2058 if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
2059 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, saved_errno, strerror(saved_errno));
2060
2061 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
2062 if (!strcmp(errstr, "bind") && saved_errno == EADDRINUSE)
2063 {
2064 err = EADDRINUSE;
2065 if (mDNSSameIPPort(port, MulticastDNSPort))
2066 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
2067 "Congratulations, you've reproduced an elusive bug.\r"
2068 "Please contact the current assignee of <rdar://problem/3814904>.\r"
2069 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2070 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2071 }
2072
2073 mDNSPlatformCloseFD(k, skt);
2074 return(err);
2075 }
2076
2077 mDNSexport UDPSocket *mDNSPlatformUDPSocket(const mDNSIPPort requestedport)
2078 {
2079 mStatus err;
2080 mDNSIPPort port = requestedport;
2081 mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
2082 int i = 10000; // Try at most 10000 times to get a unique random port
2083 UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
2084 if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
2085 mDNSPlatformMemZero(p, sizeof(UDPSocket));
2086 p->ss.port = zeroIPPort;
2087 p->ss.m = &mDNSStorage;
2088 p->ss.sktv4 = -1;
2089 p->ss.sktv6 = -1;
2090 p->ss.proxy = mDNSfalse;
2091
2092 do
2093 {
2094 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
2095 if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
2096 err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
2097 if (!err)
2098 {
2099 err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
2100 if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
2101 }
2102 i--;
2103 } while (err == EADDRINUSE && randomizePort && i);
2104
2105 if (err)
2106 {
2107 // In customer builds we don't want to log failures with port 5351, because this is a known issue
2108 // of failing to bind to this port when Internet Sharing has already bound to it
2109 // We also don't want to log about port 5350, due to a known bug when some other
2110 // process is bound to it.
2111 if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
2112 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2113 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2114 freeL("UDPSocket", p);
2115 return(mDNSNULL);
2116 }
2117 return(p);
2118 }
2119
2120 #ifdef UNIT_TEST
2121 UNITTEST_UDPCLOSE
2122 #else
2123 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
2124 {
2125 CloseSocketSet(&sock->ss);
2126 freeL("UDPSocket", sock);
2127 }
2128 #endif
2129
2130 mDNSexport mDNSBool mDNSPlatformUDPSocketEncounteredEOF(const UDPSocket *sock)
2131 {
2132 return (sock->ss.sktv4EOF || sock->ss.sktv6EOF);
2133 }
2134
2135 #if COMPILER_LIKES_PRAGMA_MARK
2136 #pragma mark -
2137 #pragma mark - BPF Raw packet sending/receiving
2138 #endif
2139
2140 #if APPLE_OSX_mDNSResponder
2141
2142 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
2143 {
2144 if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2145 NetworkInterfaceInfoOSX *info;
2146
2147 info = IfindexToInterfaceInfoOSX(InterfaceID);
2148 if (info == NULL)
2149 {
2150 LogMsg("mDNSPlatformSendRawPacket: Invalid interface index %p", InterfaceID);
2151 return;
2152 }
2153 if (info->BPF_fd < 0)
2154 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
2155 else
2156 {
2157 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
2158 if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
2159 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
2160 }
2161 }
2162
2163 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
2164 {
2165 if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
2166 NetworkInterfaceInfoOSX *info;
2167 info = IfindexToInterfaceInfoOSX(InterfaceID);
2168 if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; }
2169 // Manually inject an entry into our local ARP cache.
2170 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
2171 if (!mDNS_AddressIsLocalSubnet(&mDNSStorage, InterfaceID, tpa))
2172 LogSPS("Don't need address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
2173 else
2174 {
2175 int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b);
2176 if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
2177 else LogSPS("Set local address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
2178 }
2179 }
2180
2181 mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
2182 {
2183 LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
2184 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2185 // close will happen in the cancel handler
2186 dispatch_source_cancel(i->BPF_source);
2187 #else
2188
2189 // Note: MUST NOT close() the underlying native BSD sockets.
2190 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
2191 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
2192 CFRunLoopRemoveSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode);
2193 CFRelease(i->BPF_rls);
2194 CFSocketInvalidate(i->BPF_cfs);
2195 CFRelease(i->BPF_cfs);
2196 #endif
2197 i->BPF_fd = -1;
2198 if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
2199 }
2200
2201 mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
2202 {
2203 KQueueLock();
2204
2205 // 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
2206 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
2207 if (info->BPF_fd < 0) goto exit;
2208
2209 ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
2210 const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
2211 const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
2212 debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
2213
2214 if (n<0)
2215 {
2216 /* <rdar://problem/10287386>
2217 * sometimes there can be a race condition btw when the bpf socket
2218 * gets data and the callback get scheduled and when we call BIOCSETF (which
2219 * clears the socket). this can cause the read to hang for a really long time
2220 * and effectively prevent us from responding to requests for long periods of time.
2221 * to prevent this make the socket non blocking and just bail if we dont get anything
2222 */
2223 if (errno == EAGAIN)
2224 {
2225 LogMsg("bpf_callback got EAGAIN bailing");
2226 goto exit;
2227 }
2228 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
2229 CloseBPF(info);
2230 goto exit;
2231 }
2232
2233 while (ptr < end)
2234 {
2235 const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr;
2236 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
2237 info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen,
2238 ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
2239 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
2240 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
2241 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
2242 mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
2243 ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
2244 }
2245 exit:
2246 KQueueUnlock("bpf_callback");
2247 }
2248 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2249 mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
2250 {
2251 bpf_callback_common(info);
2252 }
2253 #else
2254 mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
2255 {
2256 (void)cfs;
2257 (void)CallBackType;
2258 (void)address;
2259 (void)data;
2260 bpf_callback_common((NetworkInterfaceInfoOSX *)context);
2261 }
2262 #endif
2263
2264 mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
2265 {
2266 LogMsg("mDNSPlatformSendKeepalive called\n");
2267 mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win);
2268 }
2269
2270 mDNSexport mStatus mDNSPlatformClearSPSData(void)
2271 {
2272 CFStringRef spsAddressKey = NULL;
2273 CFStringRef ownerOPTRecKey = NULL;
2274 SCDynamicStoreRef addrStore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SPSAddresses"), NULL, NULL);
2275 SCDynamicStoreRef optStore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SPSOPTRecord"), NULL, NULL);
2276
2277 spsAddressKey = SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyAddress"));
2278 if (spsAddressKey != NULL)
2279 {
2280 CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, spsAddressKey);
2281 if (keyList != NULL)
2282 {
2283 if (SCDynamicStoreSetMultiple(addrStore, NULL, keyList, NULL) == false)
2284 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr( spsAddressKey, kCFStringEncodingASCII), SCErrorString(SCError()));
2285 }
2286 if (keyList) CFRelease(keyList);
2287 }
2288 ownerOPTRecKey= SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyOPTRecord"));
2289 if(ownerOPTRecKey != NULL)
2290 {
2291 CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, ownerOPTRecKey);
2292 if (keyList != NULL)
2293 {
2294 if (SCDynamicStoreSetMultiple(optStore, NULL, keyList, NULL) == false)
2295 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr(ownerOPTRecKey, kCFStringEncodingASCII), SCErrorString(SCError()));
2296 }
2297 if (keyList) CFRelease(keyList);
2298 }
2299
2300 if (addrStore) CFRelease(addrStore);
2301 if (optStore) CFRelease(optStore);
2302 if (spsAddressKey) CFRelease(spsAddressKey);
2303 if (ownerOPTRecKey) CFRelease(ownerOPTRecKey);
2304 return KERN_SUCCESS;
2305 }
2306
2307 mDNSlocal int getMACAddress(int family, v6addr_t raddr, v6addr_t gaddr, int *gfamily, ethaddr_t eth)
2308 {
2309 struct
2310 {
2311 struct rt_msghdr m_rtm;
2312 char m_space[512];
2313 } m_rtmsg;
2314
2315 struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
2316 char *cp = m_rtmsg.m_space;
2317 int seq = 6367, sock, rlen, i;
2318 struct sockaddr_in *sin = NULL;
2319 struct sockaddr_in6 *sin6 = NULL;
2320 struct sockaddr_dl *sdl = NULL;
2321 struct sockaddr_storage sins;
2322 struct sockaddr_dl sdl_m;
2323
2324 #define NEXTADDR(w, s, len) \
2325 if (rtm->rtm_addrs & (w)) \
2326 { \
2327 bcopy((char *)s, cp, len); \
2328 cp += len; \
2329 }
2330
2331 bzero(&sins, sizeof(struct sockaddr_storage));
2332 bzero(&sdl_m, sizeof(struct sockaddr_dl));
2333 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
2334
2335 sock = socket(PF_ROUTE, SOCK_RAW, 0);
2336 if (sock < 0)
2337 {
2338 const int socket_errno = errno;
2339 LogMsg("getMACAddress: Can not open the socket - %s", strerror(socket_errno));
2340 return socket_errno;
2341 }
2342
2343 rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY;
2344 rtm->rtm_type = RTM_GET;
2345 rtm->rtm_flags = 0;
2346 rtm->rtm_version = RTM_VERSION;
2347 rtm->rtm_seq = ++seq;
2348
2349 sdl_m.sdl_len = sizeof(sdl_m);
2350 sdl_m.sdl_family = AF_LINK;
2351 if (family == AF_INET)
2352 {
2353 sin = (struct sockaddr_in*)&sins;
2354 sin->sin_family = AF_INET;
2355 sin->sin_len = sizeof(struct sockaddr_in);
2356 memcpy(&sin->sin_addr, raddr, sizeof(struct in_addr));
2357 NEXTADDR(RTA_DST, sin, sin->sin_len);
2358 }
2359 else if (family == AF_INET6)
2360 {
2361 sin6 = (struct sockaddr_in6 *)&sins;
2362 sin6->sin6_len = sizeof(struct sockaddr_in6);
2363 sin6->sin6_family = AF_INET6;
2364 memcpy(&sin6->sin6_addr, raddr, sizeof(struct in6_addr));
2365 NEXTADDR(RTA_DST, sin6, sin6->sin6_len);
2366 }
2367 NEXTADDR(RTA_GATEWAY, &sdl_m, sdl_m.sdl_len);
2368 rtm->rtm_msglen = rlen = cp - (char *)&m_rtmsg;
2369
2370 if (write(sock, (char *)&m_rtmsg, rlen) < 0)
2371 {
2372 const int write_errno = errno;
2373 LogMsg("getMACAddress: writing to routing socket: %s", strerror(write_errno));
2374 close(sock);
2375 return write_errno;
2376 }
2377
2378 do
2379 {
2380 rlen = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
2381 }
2382 while (rlen > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid()));
2383
2384 if (rlen < 0)
2385 LogMsg("getMACAddress: Read from routing socket failed");
2386
2387 if (family == AF_INET)
2388 {
2389 sin = (struct sockaddr_in *) (rtm + 1);
2390 sdl = (struct sockaddr_dl *) (sin->sin_len + (char *) sin);
2391 }
2392 else if (family == AF_INET6)
2393 {
2394 sin6 = (struct sockaddr_in6 *) (rtm +1);
2395 sdl = (struct sockaddr_dl *) (sin6->sin6_len + (char *) sin6);
2396 }
2397
2398 if (!sdl)
2399 {
2400 LogMsg("getMACAddress: sdl is NULL for family %d", family);
2401 close(sock);
2402 return -1;
2403 }
2404
2405 // If the address is not on the local net, we get the IP address of the gateway.
2406 // We would have to repeat the process to get the MAC address of the gateway
2407 *gfamily = sdl->sdl_family;
2408 if (sdl->sdl_family == AF_INET)
2409 {
2410 if (sin)
2411 {
2412 struct sockaddr_in *new_sin = (struct sockaddr_in *)(sin->sin_len +(char*) sin);
2413 memcpy(gaddr, &new_sin->sin_addr, sizeof(struct in_addr));
2414 }
2415 else
2416 {
2417 LogMsg("getMACAddress: sin is NULL");
2418 }
2419 close(sock);
2420 return -1;
2421 }
2422 else if (sdl->sdl_family == AF_INET6)
2423 {
2424 if (sin6)
2425 {
2426 struct sockaddr_in6 *new_sin6 = (struct sockaddr_in6 *)(sin6->sin6_len +(char*) sin6);
2427 memcpy(gaddr, &new_sin6->sin6_addr, sizeof(struct in6_addr));
2428 }
2429 else
2430 {
2431 LogMsg("getMACAddress: sin6 is NULL");
2432 }
2433 close(sock);
2434 return -1;
2435 }
2436
2437 unsigned char *ptr = (unsigned char *)LLADDR(sdl);
2438 for (i = 0; i < ETHER_ADDR_LEN; i++)
2439 (eth)[i] = *(ptr +i);
2440
2441 close(sock);
2442
2443 return KERN_SUCCESS;
2444 }
2445
2446 mDNSlocal int GetRemoteMacinternal(int family, v6addr_t raddr, ethaddr_t eth)
2447 {
2448 int ret = 0;
2449 v6addr_t gateway;
2450 int gfamily = 0;
2451 int count = 0;
2452
2453 do
2454 {
2455 ret = getMACAddress(family, raddr, gateway, &gfamily, eth);
2456 if (ret == -1)
2457 {
2458 memcpy(raddr, gateway, (gfamily == AF_INET) ? 4 : 16);
2459 family = gfamily;
2460 count++;
2461 }
2462 }
2463 while ((ret == -1) && (count < 5));
2464 return ret;
2465 }
2466
2467 mDNSlocal int StoreSPSMACAddressinternal(int family, v6addr_t spsaddr, const char *ifname)
2468 {
2469 ethaddr_t eth;
2470 char spsip[INET6_ADDRSTRLEN];
2471 int ret = 0;
2472 CFStringRef sckey = NULL;
2473 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL, NULL);
2474 SCDynamicStoreRef ipstore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL, NULL);
2475 CFMutableDictionaryRef dict = NULL;
2476 CFStringRef entityname = NULL;
2477 CFDictionaryRef ipdict = NULL;
2478 CFArrayRef addrs = NULL;
2479
2480 if ((store == NULL) || (ipstore == NULL))
2481 {
2482 LogMsg("StoreSPSMACAddressinternal: Unable to accesss SC Dynamic Store");
2483 ret = -1;
2484 goto fin;
2485 }
2486
2487 // Get the MAC address of the Sleep Proxy Server
2488 memset(eth, 0, sizeof(eth));
2489 ret = GetRemoteMacinternal(family, spsaddr, eth);
2490 if (ret != 0)
2491 {
2492 LogMsg("StoreSPSMACAddressinternal: Failed to determine the MAC address");
2493 goto fin;
2494 }
2495
2496 // Create/Update the dynamic store entry for the specified interface
2497 sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyAddress");
2498 dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2499 if (!dict)
2500 {
2501 LogMsg("StoreSPSMACAddressinternal: SPSCreateDict() Could not create CFDictionary dict");
2502 ret = -1;
2503 goto fin;
2504 }
2505
2506 CFStringRef macaddr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
2507 CFDictionarySetValue(dict, CFSTR("MACAddress"), macaddr);
2508 if (NULL != macaddr)
2509 CFRelease(macaddr);
2510
2511 if( NULL == inet_ntop(family, (void *)spsaddr, spsip, sizeof(spsip)))
2512 {
2513 LogMsg("StoreSPSMACAddressinternal: inet_ntop failed: %s", strerror(errno));
2514 ret = -1;
2515 goto fin;
2516 }
2517
2518 CFStringRef ipaddr = CFStringCreateWithCString(NULL, spsip, kCFStringEncodingUTF8);
2519 CFDictionarySetValue(dict, CFSTR("IPAddress"), ipaddr);
2520 if (NULL != ipaddr)
2521 CFRelease(ipaddr);
2522
2523 // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup
2524 if ((entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/IPv6"), ifname)) != NULL)
2525 {
2526 if ((ipdict = SCDynamicStoreCopyValue(ipstore, entityname)) != NULL)
2527 {
2528 if((addrs = CFDictionaryGetValue(ipdict, CFSTR("Addresses"))) != NULL)
2529 {
2530 addrs = CFRetain(addrs);
2531 CFDictionarySetValue(dict, CFSTR("RegisteredAddresses"), addrs);
2532 }
2533 }
2534 }
2535 SCDynamicStoreSetValue(store, sckey, dict);
2536
2537 fin:
2538 if (store) CFRelease(store);
2539 if (ipstore) CFRelease(ipstore);
2540 if (sckey) CFRelease(sckey);
2541 if (dict) CFRelease(dict);
2542 if (ipdict) CFRelease(ipdict);
2543 if (entityname) CFRelease(entityname);
2544 if (addrs) CFRelease(addrs);
2545
2546 return ret;
2547 }
2548
2549 mDNSlocal void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname)
2550 {
2551 struct
2552 {
2553 v6addr_t saddr;
2554 } addr;
2555 int err = 0;
2556
2557 mDNSPlatformMemCopy(addr.saddr, spsaddr, sizeof(v6addr_t));
2558
2559 err = StoreSPSMACAddressinternal(family, (uint8_t *)addr.saddr, ifname);
2560 if (err != 0)
2561 LogMsg("mDNSStoreSPSMACAddress : failed");
2562 }
2563
2564 mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
2565 {
2566 int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2567
2568 LogInfo("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname);
2569 mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname);
2570
2571 return KERN_SUCCESS;
2572 }
2573
2574
2575 mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage* msg, int length)
2576 {
2577 int ret = 0;
2578 CFStringRef sckey = NULL;
2579 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreOwnerOPTRecord"), NULL, NULL);
2580 CFMutableDictionaryRef dict = NULL;
2581
2582 if (store == NULL)
2583 {
2584 LogMsg("mDNSPlatformStoreOwnerOptRecord: Unable to accesss SC Dynamic Store");
2585 ret = -1;
2586 goto fin;
2587 }
2588
2589 // Create/Update the dynamic store entry for the specified interface
2590 sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyOPTRecord");
2591 dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2592 if (!dict)
2593 {
2594 LogMsg("mDNSPlatformStoreOwnerOptRecord: Could not create CFDictionary dictionary to store OPT Record");
2595 ret =-1;
2596 goto fin;
2597 }
2598
2599 CFDataRef optRec = NULL;
2600 optRec = CFDataCreate(NULL, (const uint8_t *)msg, (CFIndex)length);
2601 CFDictionarySetValue(dict, CFSTR("OwnerOPTRecord"), optRec);
2602 if (NULL != optRec) CFRelease(optRec);
2603
2604 SCDynamicStoreSetValue(store, sckey, dict);
2605
2606 fin:
2607 if (NULL != store) CFRelease(store);
2608 if (NULL != sckey) CFRelease(sckey);
2609 if (NULL != dict) CFRelease(dict);
2610 return ret;
2611 }
2612
2613 mDNSlocal void mDNSGet_RemoteMAC(int family, v6addr_t raddr)
2614 {
2615 ethaddr_t eth;
2616 IPAddressMACMapping *addrMapping;
2617 int kr = KERN_FAILURE;
2618 struct
2619 {
2620 v6addr_t addr;
2621 } dst;
2622
2623 bzero(eth, sizeof(ethaddr_t));
2624 mDNSPlatformMemCopy(dst.addr, raddr, sizeof(v6addr_t));
2625
2626 kr = GetRemoteMacinternal(family, (uint8_t *)dst.addr, eth);
2627
2628 // If the call to get the remote MAC address succeeds, allocate and copy
2629 // the values and schedule a task to update the MAC address in the TCP Keepalive record.
2630 if (kr == 0)
2631 {
2632 addrMapping = mDNSPlatformMemAllocate(sizeof(IPAddressMACMapping));
2633 snprintf(addrMapping->ethaddr, sizeof(addrMapping->ethaddr), "%02x:%02x:%02x:%02x:%02x:%02x",
2634 eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
2635 if (family == AF_INET)
2636 {
2637 addrMapping->ipaddr.type = mDNSAddrType_IPv4;
2638 mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, raddr, sizeof(v6addr_t));
2639 }
2640 else
2641 {
2642 addrMapping->ipaddr.type = mDNSAddrType_IPv6;
2643 mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v6.b, raddr, sizeof(v6addr_t));
2644 }
2645 UpdateRMAC(&mDNSStorage, addrMapping);
2646 }
2647 }
2648
2649 mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr)
2650 {
2651 int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2652
2653 LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC");
2654 mDNSGet_RemoteMAC(family, raddr->ip.v6.b);
2655
2656 return KERN_SUCCESS;
2657 }
2658
2659 mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
2660 {
2661 mDNSs32 intfid;
2662 mDNSs32 error = 0;
2663 int family = (laddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2664
2665 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);
2666 if (error != KERN_SUCCESS)
2667 {
2668 LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error);
2669 return error;
2670 }
2671 mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, intfid);
2672 return error;
2673 }
2674
2675 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2676
2677 mDNSlocal int CountProxyTargets(NetworkInterfaceInfoOSX *x, int *p4, int *p6)
2678 {
2679 int numv4 = 0, numv6 = 0;
2680 AuthRecord *rr;
2681
2682 for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
2683 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2684 {
2685 if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
2686 numv4++;
2687 }
2688
2689 for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
2690 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2691 {
2692 if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
2693 numv6++;
2694 }
2695
2696 if (p4) *p4 = numv4;
2697 if (p6) *p6 = numv6;
2698 return(numv4 + numv6);
2699 }
2700
2701 mDNSexport void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)
2702 {
2703 mDNS *const m = &mDNSStorage;
2704 NetworkInterfaceInfoOSX *x;
2705
2706 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
2707 for (x = m->p->InterfaceList; x; x = x->next) if ((x->ifinfo.InterfaceID == InterfaceID) && (x->BPF_fd >= 0)) break;
2708
2709 if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
2710
2711 #define MAX_BPF_ADDRS 250
2712 int numv4 = 0, numv6 = 0;
2713
2714 if (CountProxyTargets(x, &numv4, &numv6) > MAX_BPF_ADDRS)
2715 {
2716 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
2717 if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
2718 numv6 = MAX_BPF_ADDRS - numv4;
2719 }
2720
2721 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
2722
2723 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
2724 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
2725 static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
2726 {
2727 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13)
2728
2729 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
2730 BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP
2731
2732 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
2733
2734 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
2735 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
2736 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
2737 BPF_STMT(BPF_RET + BPF_K, 86), // 7 Return 86-byte ND
2738
2739 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
2740 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
2741 };
2742
2743 // Special filter program to use when there are no address proxy records
2744 static struct bpf_insn nullfilter[] =
2745 {
2746 BPF_STMT(BPF_RET | BPF_K, 0) // 0 Match no packets and return size 0
2747 };
2748
2749 struct bpf_program prog;
2750 if (!numv4 && !numv6)
2751 {
2752 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
2753 if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
2754
2755 // Cancel any previous ND group memberships we had
2756 if (x->BPF_mcfd >= 0)
2757 {
2758 close(x->BPF_mcfd);
2759 x->BPF_mcfd = -1;
2760 }
2761
2762 // Schedule check to see if we can close this BPF_fd now
2763 if (!m->NetworkChanged) m->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
2764 if (x->BPF_fd < 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
2765 prog.bf_len = 1;
2766 prog.bf_insns = nullfilter;
2767 }
2768 else
2769 {
2770 struct bpf_insn *pc = &filter[9];
2771 struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0"
2772 struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks
2773 struct bpf_insn *ret4 = fail + 1;
2774 struct bpf_insn *ret6 = ret4 + 4;
2775
2776 static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing
2777
2778 static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
2779
2780 static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20)
2781 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)
2782 static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length
2783 static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
2784
2785 static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
2786
2787 BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail
2788 BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check
2789
2790 // BPF Byte-Order Note
2791 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
2792 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
2793 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
2794 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
2795 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
2796 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
2797 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
2798 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
2799 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
2800 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
2801
2802 // IPSEC capture size notes:
2803 // 8 bytes UDP header
2804 // 4 bytes Non-ESP Marker
2805 // 28 bytes IKE Header
2806 // --
2807 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
2808
2809 AuthRecord *rr;
2810 for (rr = m->ResourceRecords; rr; rr=rr->next)
2811 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2812 {
2813 mDNSv4Addr a = rr->AddressProxy.ip.v4;
2814 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2815 BPF_SetOffset(pc, jt, ret4);
2816 pc->jf = 0;
2817 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];
2818 pc++;
2819 }
2820 *pc++ = rf;
2821
2822 if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
2823 *pc++ = g6; // chk6 points here
2824
2825 // First cancel any previous ND group memberships we had, then create a fresh socket
2826 if (x->BPF_mcfd >= 0) close(x->BPF_mcfd);
2827 x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0);
2828
2829 for (rr = m->ResourceRecords; rr; rr=rr->next)
2830 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2831 {
2832 const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
2833 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2834 BPF_SetOffset(pc, jt, ret6);
2835 pc->jf = 0;
2836 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];
2837 pc++;
2838
2839 struct ipv6_mreq i6mr;
2840 i6mr.ipv6mr_interface = x->scope_id;
2841 i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix;
2842 i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD];
2843 i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE];
2844 i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF];
2845
2846 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
2847 mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
2848 if (err < 0 && (errno != EADDRNOTAVAIL))
2849 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2850
2851 err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
2852 if (err < 0 && (errno != EADDRINUSE)) // Joining same group twice can give "Address already in use" error -- no need to report that
2853 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2854
2855 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
2856 }
2857
2858 if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
2859 *pc++ = rf; // fail points here
2860
2861 if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
2862 *pc++ = r4a; // ret4 points here
2863 *pc++ = r4b;
2864 *pc++ = r4c;
2865 *pc++ = r4d;
2866
2867 if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
2868 *pc++ = r6a; // ret6 points here
2869 #if 0
2870 // For debugging BPF filter program
2871 unsigned int q;
2872 for (q=0; q<prog.bf_len; q++)
2873 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);
2874 #endif
2875 prog.bf_len = (u_int)(pc - filter);
2876 prog.bf_insns = filter;
2877 }
2878
2879 if (ioctl(x->BPF_fd, BIOCSETFNR, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
2880 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog.bf_len);
2881 }
2882
2883 mDNSexport void mDNSPlatformReceiveBPF_fd(int fd)
2884 {
2885 mDNS *const m = &mDNSStorage;
2886 mDNS_Lock(m);
2887
2888 NetworkInterfaceInfoOSX *i;
2889 for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
2890 if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
2891 else
2892 {
2893 LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd);
2894
2895 struct bpf_version v;
2896 if (ioctl(fd, BIOCVERSION, &v) < 0)
2897 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2898 else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
2899 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
2900 fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
2901
2902 if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
2903 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2904
2905 if (i->BPF_len > sizeof(m->imsg))
2906 {
2907 i->BPF_len = sizeof(m->imsg);
2908 if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
2909 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2910 else
2911 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd, i->ifinfo.ifname, i->BPF_len);
2912 }
2913
2914 static const u_int opt_one = 1;
2915 if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0)
2916 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2917
2918 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
2919 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2920
2921 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
2922 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2923
2924 /* <rdar://problem/10287386>
2925 * make socket non blocking see comments in bpf_callback_common for more info
2926 */
2927 if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
2928 {
2929 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2930 }
2931
2932 struct ifreq ifr;
2933 mDNSPlatformMemZero(&ifr, sizeof(ifr));
2934 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
2935 if (ioctl(fd, BIOCSETIF, &ifr) < 0)
2936 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
2937 else
2938 {
2939 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2940 i->BPF_fd = fd;
2941 i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());
2942 if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
2943 dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);});
2944 dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);});
2945 dispatch_resume(i->BPF_source);
2946 #else
2947 CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
2948 i->BPF_fd = fd;
2949 i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
2950 i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
2951 CFRunLoopAddSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode);
2952 #endif
2953 mDNSPlatformUpdateProxyList(i->ifinfo.InterfaceID);
2954 }
2955 }
2956
2957 mDNS_Unlock(m);
2958 }
2959
2960 #endif // APPLE_OSX_mDNSResponder
2961
2962 #if COMPILER_LIKES_PRAGMA_MARK
2963 #pragma mark -
2964 #pragma mark - Key Management
2965 #endif
2966
2967 #ifndef NO_SECURITYFRAMEWORK
2968 mDNSlocal CFArrayRef CopyCertChain(SecIdentityRef identity)
2969 {
2970 CFMutableArrayRef certChain = NULL;
2971 if (!identity) { LogMsg("CopyCertChain: identity is NULL"); return(NULL); }
2972 SecCertificateRef cert;
2973 OSStatus err = SecIdentityCopyCertificate(identity, &cert);
2974 if (err || !cert) LogMsg("CopyCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
2975 else
2976 {
2977 #pragma clang diagnostic push
2978 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2979 SecPolicySearchRef searchRef;
2980 err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
2981 if (err || !searchRef) LogMsg("CopyCertChain: SecPolicySearchCreate() returned %d", (int) err);
2982 else
2983 {
2984 SecPolicyRef policy;
2985 err = SecPolicySearchCopyNext(searchRef, &policy);
2986 if (err || !policy) LogMsg("CopyCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
2987 else
2988 {
2989 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
2990 if (!wrappedCert) LogMsg("CopyCertChain: wrappedCert is NULL");
2991 else
2992 {
2993 SecTrustRef trust;
2994 err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
2995 if (err || !trust) LogMsg("CopyCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
2996 else
2997 {
2998 err = SecTrustEvaluate(trust, NULL);
2999 if (err) LogMsg("CopyCertChain: SecTrustEvaluate() returned %d", (int) err);
3000 else
3001 {
3002 CFArrayRef rawCertChain;
3003 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
3004 err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
3005 if (err || !rawCertChain || !statusChain) LogMsg("CopyCertChain: SecTrustGetResult() returned %d", (int) err);
3006 else
3007 {
3008 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
3009 if (!certChain) LogMsg("CopyCertChain: certChain is NULL");
3010 else
3011 {
3012 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
3013 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
3014 CFArraySetValueAtIndex(certChain, 0, identity);
3015 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
3016 if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
3017 }
3018 CFRelease(rawCertChain);
3019 // Do not free statusChain:
3020 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
3021 // certChain: Call the CFRelease function to release this object when you are finished with it.
3022 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
3023 }
3024 }
3025 CFRelease(trust);
3026 }
3027 CFRelease(wrappedCert);
3028 }
3029 CFRelease(policy);
3030 }
3031 CFRelease(searchRef);
3032 }
3033 #pragma clang diagnostic pop
3034 CFRelease(cert);
3035 }
3036 return certChain;
3037 }
3038 #endif /* NO_SECURITYFRAMEWORK */
3039
3040 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
3041 {
3042 #ifdef NO_SECURITYFRAMEWORK
3043 return mStatus_UnsupportedErr;
3044 #else
3045 SecIdentityRef identity = nil;
3046 SecIdentitySearchRef srchRef = nil;
3047 OSStatus err;
3048
3049 #pragma clang diagnostic push
3050 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3051 // search for "any" identity matching specified key use
3052 // In this app, we expect there to be exactly one
3053 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
3054 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
3055
3056 err = SecIdentitySearchCopyNext(srchRef, &identity);
3057 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
3058 #pragma clang diagnostic pop
3059
3060 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
3061 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
3062
3063 // Found one. Call CopyCertChain to create the correct certificate chain.
3064 ServerCerts = CopyCertChain(identity);
3065 if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: CopyCertChain error"); return mStatus_UnknownErr; }
3066
3067 return mStatus_NoError;
3068 #endif /* NO_SECURITYFRAMEWORK */
3069 }
3070
3071 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
3072 {
3073 #ifndef NO_SECURITYFRAMEWORK
3074 if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
3075 #endif /* NO_SECURITYFRAMEWORK */
3076 }
3077
3078 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
3079 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
3080 {
3081 CFStringEncoding encoding = kCFStringEncodingUTF8;
3082 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
3083 if (cfs)
3084 {
3085 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3086 CFRelease(cfs);
3087 }
3088 }
3089
3090 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
3091 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
3092 {
3093 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
3094 if (cfs)
3095 {
3096 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3097 CFRelease(cfs);
3098 }
3099 }
3100
3101 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
3102 {
3103 mDNSs32 val;
3104 CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
3105 if (!state) return mDNSfalse;
3106 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
3107 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
3108 return val ? mDNStrue : mDNSfalse;
3109 }
3110
3111 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
3112 {
3113 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
3114
3115 if (sa->sa_family == AF_INET)
3116 {
3117 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
3118 ip->type = mDNSAddrType_IPv4;
3119 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
3120 return(mStatus_NoError);
3121 }
3122
3123 if (sa->sa_family == AF_INET6)
3124 {
3125 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
3126 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
3127 // value into the second word of the IPv6 link-local address, so they can just
3128 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
3129 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
3130 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
3131 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
3132 ip->type = mDNSAddrType_IPv6;
3133 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
3134 return(mStatus_NoError);
3135 }
3136
3137 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
3138 return(mStatus_Invalid);
3139 }
3140
3141 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
3142 {
3143 mDNSEthAddr eth = zeroEthAddr;
3144
3145 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
3146 if (entityname)
3147 {
3148 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, entityname);
3149 if (dict)
3150 {
3151 CFRange range = { 0, 6 }; // Offset, length
3152 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
3153 if (data && CFDataGetLength(data) == 6)
3154 CFDataGetBytes(data, range, eth.b);
3155 CFRelease(dict);
3156 }
3157 CFRelease(entityname);
3158 }
3159
3160 return(eth);
3161 }
3162
3163 mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
3164 {
3165 struct ifaddrs *ifa;
3166 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
3167 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
3168 {
3169 const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
3170 if (sdl->sdl_index == ifindex)
3171 { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
3172 }
3173 *eth = zeroEthAddr;
3174 return -1;
3175 }
3176
3177 #ifndef SIOCGIFWAKEFLAGS
3178 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
3179 #endif
3180
3181 #ifndef IF_WAKE_ON_MAGIC_PACKET
3182 #define IF_WAKE_ON_MAGIC_PACKET 0x01
3183 #endif
3184
3185 #ifndef ifr_wake_flags
3186 #define ifr_wake_flags ifr_ifru.ifru_intval
3187 #endif
3188
3189 mDNSlocal
3190 kern_return_t
3191 RegistryEntrySearchCFPropertyAndIOObject( io_registry_entry_t entry,
3192 const io_name_t plane,
3193 CFStringRef keystr,
3194 CFTypeRef * outProperty,
3195 io_registry_entry_t * outEntry)
3196 {
3197 kern_return_t kr;
3198
3199 IOObjectRetain(entry);
3200 while (entry)
3201 {
3202 CFTypeRef ref = IORegistryEntryCreateCFProperty(entry, keystr, kCFAllocatorDefault, mDNSNULL);
3203 if (ref)
3204 {
3205 if (outProperty) *outProperty = ref;
3206 else CFRelease(ref);
3207 break;
3208 }
3209 io_registry_entry_t parent;
3210 kr = IORegistryEntryGetParentEntry(entry, plane, &parent);
3211 if (kr != KERN_SUCCESS) parent = mDNSNULL;
3212 IOObjectRelease(entry);
3213 entry = parent;
3214 }
3215 if (!entry) kr = kIOReturnNoDevice;
3216 else
3217 {
3218 if (outEntry) *outEntry = entry;
3219 else IOObjectRelease(entry);
3220 kr = KERN_SUCCESS;
3221 }
3222 return(kr);
3223 }
3224
3225 mDNSlocal mDNSBool CheckInterfaceSupport(NetworkInterfaceInfo *const intf, const char *key)
3226 {
3227 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
3228 if (!service)
3229 {
3230 LogSPS("CheckInterfaceSupport: No service for interface %s", intf->ifname);
3231 return mDNSfalse;
3232 }
3233
3234 mDNSBool ret = mDNSfalse;
3235
3236 CFStringRef keystr = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
3237 kern_return_t kr = RegistryEntrySearchCFPropertyAndIOObject(service, kIOServicePlane, keystr, mDNSNULL, mDNSNULL);
3238 CFRelease(keystr);
3239 if (kr == KERN_SUCCESS) ret = mDNStrue;
3240 else
3241 {
3242 io_name_t n1;
3243 IOObjectGetClass(service, n1);
3244 LogSPS("CheckInterfaceSupport: No %s for interface %s/%s kr %d", key, intf->ifname, n1, kr);
3245 ret = mDNSfalse;
3246 }
3247
3248 IOObjectRelease(service);
3249 return ret;
3250 }
3251
3252
3253 mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
3254 {
3255 return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
3256 }
3257
3258 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
3259 {
3260 // We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D.
3261 if (!MulticastInterface(i) || (i->ifa_flags & IFF_LOOPBACK) || i->D2DInterface)
3262 {
3263 LogSPS("NetWakeInterface: returning false for %s", i->ifinfo.ifname);
3264 return(mDNSfalse);
3265 }
3266
3267 // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
3268 // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
3269 // when the power source is not AC Power.
3270 if (InterfaceSupportsKeepAlive(&i->ifinfo))
3271 {
3272 LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i->ifinfo.ifname);
3273 return mDNStrue;
3274 }
3275
3276 int s = socket(AF_INET, SOCK_DGRAM, 0);
3277 if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); }
3278
3279 struct ifreq ifr;
3280 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3281 if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
3282 {
3283 const int ioctl_errno = errno;
3284 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
3285 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
3286 // error code is being returned from the kernel, we need to use the kernel version.
3287 #define KERNEL_EOPNOTSUPP 102
3288 if (ioctl_errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
3289 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, ioctl_errno, strerror(ioctl_errno));
3290 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
3291 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
3292 ifr.ifr_wake_flags = (ioctl_errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
3293 }
3294
3295 close(s);
3296
3297 // 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
3298
3299 LogSPS("NetWakeInterface: %-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
3300
3301 return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
3302 }
3303
3304 mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
3305 {
3306 int sockFD;
3307 struct ifreq ifr;
3308
3309 sockFD = socket(AF_INET, SOCK_DGRAM, 0);
3310 if (sockFD < 0)
3311 {
3312 LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno, strerror(errno));
3313 return 0;
3314 }
3315
3316 ifr.ifr_addr.sa_family = AF_INET;
3317 strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
3318
3319 if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
3320 {
3321 LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno));
3322 ifr.ifr_eflags = 0;
3323 }
3324
3325 close(sockFD);
3326 return ifr.ifr_eflags;
3327 }
3328
3329 #if TARGET_OS_OSX
3330 // IFRTYPE_FUNCTIONAL_INTCOPROC type interfaces on macOS do not support Bonjour discovery.
3331 mDNSlocal mDNSBool isCoprocessorInterface(int sockFD, char * ifa_name)
3332 {
3333 struct ifreq ifr;
3334
3335 if (sockFD < 0)
3336 {
3337 LogMsg("isCoprocessorInterface: invalid socket FD passed: %d", sockFD);
3338 return mDNSfalse;
3339 }
3340
3341 memset(&ifr, 0, sizeof(struct ifreq));
3342 strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
3343
3344 if (ioctl(sockFD, SIOCGIFFUNCTIONALTYPE, (caddr_t)&ifr) == -1)
3345 {
3346 LogMsg("isCoprocessorInterface: SIOCGIFFUNCTIONALTYPE failed, errno = %d (%s)", errno, strerror(errno));
3347 return mDNSfalse;
3348 }
3349
3350 if (ifr.ifr_functional_type == IFRTYPE_FUNCTIONAL_INTCOPROC)
3351 {
3352 LogMsg("isCoprocessorInterface: %s marked as coprocessor interface", ifa_name);
3353 return mDNStrue;
3354 }
3355 else
3356 return mDNSfalse;
3357 }
3358
3359 #else // TARGET_OS_OSX
3360 #define isCoprocessorInterface(A, B) mDNSfalse
3361 #endif // TARGET_OS_OSX
3362
3363 #if TARGET_OS_IPHONE
3364
3365 // Function pointers for the routines we use in the MobileWiFi framework.
3366 static WiFiManagerClientRef (*WiFiManagerClientCreate_p)(CFAllocatorRef allocator, WiFiClientType type) = mDNSNULL;
3367 static CFArrayRef (*WiFiManagerClientCopyDevices_p)(WiFiManagerClientRef manager) = mDNSNULL;
3368 static WiFiNetworkRef (*WiFiDeviceClientCopyCurrentNetwork_p)(WiFiDeviceClientRef device) = mDNSNULL;
3369 static bool (*WiFiNetworkIsCarPlay_p)(WiFiNetworkRef network) = mDNSNULL;
3370
3371 mDNSlocal mDNSBool MobileWiFiLibLoad(void)
3372 {
3373 static mDNSBool isInitialized = mDNSfalse;
3374 static void *MobileWiFiLib_p = mDNSNULL;
3375 static const char path[] = "/System/Library/PrivateFrameworks/MobileWiFi.framework/MobileWiFi";
3376
3377 if (!isInitialized)
3378 {
3379 if (!MobileWiFiLib_p)
3380 {
3381 MobileWiFiLib_p = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
3382 if (!MobileWiFiLib_p)
3383 {
3384 LogInfo("MobileWiFiLibLoad: dlopen() failed.");
3385 goto exit;
3386 }
3387 }
3388
3389 if (!WiFiManagerClientCreate_p)
3390 {
3391 WiFiManagerClientCreate_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCreate");
3392 if (!WiFiManagerClientCreate_p)
3393 {
3394 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCreate symbol failed.");
3395 goto exit;
3396 }
3397 }
3398
3399 if (!WiFiManagerClientCopyDevices_p)
3400 {
3401 WiFiManagerClientCopyDevices_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCopyDevices");
3402 if (!WiFiManagerClientCopyDevices_p)
3403 {
3404 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCopyDevices symbol failed.");
3405 goto exit;
3406 }
3407 }
3408
3409 if (!WiFiDeviceClientCopyCurrentNetwork_p)
3410 {
3411 WiFiDeviceClientCopyCurrentNetwork_p = dlsym(MobileWiFiLib_p, "WiFiDeviceClientCopyCurrentNetwork");
3412 if (!WiFiDeviceClientCopyCurrentNetwork_p)
3413 {
3414 LogInfo("MobileWiFiLibLoad: load of WiFiDeviceClientCopyCurrentNetwork symbol failed.");
3415 goto exit;
3416 }
3417 }
3418
3419 if (!WiFiNetworkIsCarPlay_p)
3420 {
3421 WiFiNetworkIsCarPlay_p = dlsym(MobileWiFiLib_p, "WiFiNetworkIsCarPlay");
3422 if (!WiFiNetworkIsCarPlay_p)
3423 {
3424 LogInfo("MobileWiFiLibLoad: load of WiFiNetworkIsCarPlay symbol failed.");
3425 goto exit;
3426 }
3427 }
3428
3429 isInitialized = mDNStrue;
3430 }
3431
3432 exit:
3433 return isInitialized;
3434 }
3435
3436 #define CARPLAY_DEBUG 0
3437
3438 // Return true if the interface is associate to a CarPlay hosted SSID.
3439 // If we have associated with a CarPlay hosted SSID, then use the same
3440 // optimizations that are used when an interface has the IFEF_DIRECTLINK flag set.
3441 mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
3442 {
3443 static WiFiManagerClientRef manager = NULL;
3444 CFArrayRef devices;
3445 WiFiDeviceClientRef device;
3446 WiFiNetworkRef network;
3447 mDNSBool rvalue = mDNSfalse;
3448
3449 if (!MobileWiFiLibLoad())
3450 {
3451 LogInfo("IsCarPlaySSID: MobileWiFiLibLoad() failed!");
3452 return mDNSfalse;
3453 }
3454
3455 // Cache the WiFiManagerClientRef.
3456 if (manager == NULL)
3457 manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
3458
3459 if (manager == NULL)
3460 {
3461 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3462 return mDNSfalse;
3463 }
3464
3465 devices = WiFiManagerClientCopyDevices_p(manager);
3466
3467 // If the first call fails, update the cached WiFiManagerClientRef pointer and try again.
3468 if (devices == NULL)
3469 {
3470 LogInfo("IsCarPlaySSID: First call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
3471
3472 // Release the previously cached WiFiManagerClientRef which is apparently now stale.
3473 CFRelease(manager);
3474 manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
3475 if (manager == NULL)
3476 {
3477 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3478 return mDNSfalse;
3479 }
3480 devices = WiFiManagerClientCopyDevices_p(manager);
3481 if (devices == NULL)
3482 {
3483 LogInfo("IsCarPlaySSID: Second call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
3484 return mDNSfalse;
3485 }
3486 }
3487
3488 device = (WiFiDeviceClientRef)CFArrayGetValueAtIndex(devices, 0);
3489 network = WiFiDeviceClientCopyCurrentNetwork_p(device);
3490 if (network != NULL)
3491 {
3492 if (WiFiNetworkIsCarPlay_p(network))
3493 {
3494 LogInfo("IsCarPlaySSID: %s is CarPlay hosted", ifa_name);
3495 rvalue = mDNStrue;
3496 }
3497 #if CARPLAY_DEBUG
3498 else
3499 LogInfo("IsCarPlaySSID: %s is NOT CarPlay hosted", ifa_name);
3500 #endif // CARPLAY_DEBUG
3501
3502 CFRelease(network);
3503 }
3504 else
3505 LogInfo("IsCarPlaySSID: WiFiDeviceClientCopyCurrentNetwork() returned NULL for %s", ifa_name);
3506
3507 CFRelease(devices);
3508
3509 return rvalue;
3510 }
3511
3512 #else // TARGET_OS_IPHONE
3513
3514 mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
3515 {
3516 (void)ifa_name; // unused
3517
3518 // OSX WifiManager currently does not implement WiFiNetworkIsCarPlay()
3519 return mDNSfalse;;
3520 }
3521
3522 #endif // TARGET_OS_IPHONE
3523
3524 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
3525 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
3526 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
3527 // (e.g. sa_family not AF_INET or AF_INET6)
3528 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(struct ifaddrs *ifa, mDNSs32 utc)
3529 {
3530 mDNS *const m = &mDNSStorage;
3531 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
3532 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
3533 u_int64_t eflags = getExtendedFlags(ifa->ifa_name);
3534
3535 mDNSAddr ip, mask;
3536 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
3537 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
3538
3539 NetworkInterfaceInfoOSX **p;
3540 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
3541 if (scope_id == (*p)->scope_id &&
3542 mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
3543 mDNSSameEthAddress(&bssid, &(*p)->BSSID))
3544 {
3545 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);
3546 // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
3547 // When interfaces are created with same MAC address, kernel resurrects the old interface.
3548 // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
3549 // we get the corresponding name for the interface index on which the packet was received and check against
3550 // the InterfaceList for a matching name. So, keep the name in sync
3551 strlcpy((*p)->ifinfo.ifname, ifa->ifa_name, sizeof((*p)->ifinfo.ifname));
3552
3553 // Determine if multicast state has changed.
3554 const mDNSBool txrx = MulticastInterface(*p);
3555 if ((*p)->ifinfo.McastTxRx != txrx)
3556 {
3557 (*p)->ifinfo.McastTxRx = txrx;
3558 (*p)->Exists = MulticastStateChanged; // State change; need to deregister and reregister this interface
3559 }
3560 else
3561 (*p)->Exists = mDNStrue;
3562
3563 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
3564 if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
3565
3566 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
3567 // we may need to start or stop or sleep proxy browse operation
3568 const mDNSBool NetWake = NetWakeInterface(*p);
3569 if ((*p)->ifinfo.NetWake != NetWake)
3570 {
3571 (*p)->ifinfo.NetWake = NetWake;
3572 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
3573 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
3574 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
3575 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
3576 if ((*p)->Registered)
3577 {
3578 mDNS_Lock(m);
3579 if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo);
3580 else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
3581 mDNS_Unlock(m);
3582 }
3583 }
3584 // Reset the flag if it has changed this time.
3585 (*p)->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
3586
3587 return(*p);
3588 }
3589
3590 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
3591 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
3592 if (!i) return(mDNSNULL);
3593 mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
3594 i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
3595 i->ifinfo.ip = ip;
3596 i->ifinfo.mask = mask;
3597 strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
3598 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
3599 // We can be configured to disable multicast advertisement, but we want to to support
3600 // local-only services, which need a loopback address record.
3601 i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
3602 i->ifinfo.Loopback = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse;
3603 i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
3604
3605 // Setting DirectLink indicates we can do the optimization of skipping the probe phase
3606 // for the interface address records since they should be unique.
3607 // Unfortunately, the legacy p2p* interfaces do not set the IFEF_LOCALNET_PRIVATE
3608 // or IFEF_DIRECTLINK flags, so we have to match against the name.
3609 if ((eflags & (IFEF_DIRECTLINK | IFEF_AWDL)) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0))
3610 i->ifinfo.DirectLink = mDNStrue;
3611 else
3612 i->ifinfo.DirectLink = IsCarPlaySSID(ifa->ifa_name);
3613
3614 if (i->ifinfo.DirectLink)
3615 LogInfo("AddInterfaceToList: DirectLink set for %s", ifa->ifa_name);
3616
3617 i->next = mDNSNULL;
3618 i->m = m;
3619 i->Exists = mDNStrue;
3620 i->Flashing = mDNSfalse;
3621 i->Occulting = mDNSfalse;
3622
3623 i->D2DInterface = ((eflags & IFEF_LOCALNET_PRIVATE) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0)) ? mDNStrue: mDNSfalse;
3624 if (i->D2DInterface)
3625 LogInfo("AddInterfaceToList: D2DInterface set for %s", ifa->ifa_name);
3626
3627 i->isExpensive = (eflags & IFEF_EXPENSIVE) ? mDNStrue: mDNSfalse;
3628 i->isAWDL = (eflags & IFEF_AWDL) ? mDNStrue: mDNSfalse;
3629 i->isCLAT46 = (eflags & IFEF_CLAT46) ? mDNStrue: mDNSfalse;
3630 if (eflags & IFEF_AWDL)
3631 {
3632 // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
3633 // limited AWDL resources so we don't set the kDNSQClass_UnicastResponse bit in
3634 // Bonjour requests over the AWDL interface.
3635 i->ifinfo.SupportsUnicastMDNSResponse = mDNSfalse;
3636 AWDLInterfaceID = i->ifinfo.InterfaceID;
3637 LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
3638 }
3639 else
3640 {
3641 i->ifinfo.SupportsUnicastMDNSResponse = mDNStrue;
3642 }
3643 i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
3644 i->LastSeen = utc;
3645 i->ifa_flags = ifa->ifa_flags;
3646 i->scope_id = scope_id;
3647 i->BSSID = bssid;
3648 i->sa_family = ifa->ifa_addr->sa_family;
3649 i->BPF_fd = -1;
3650 i->BPF_mcfd = -1;
3651 i->BPF_len = 0;
3652 i->Registered = mDNSNULL;
3653
3654 // MulticastInterface() depends on the "m" and "ifa_flags" values being initialized above.
3655 i->ifinfo.McastTxRx = MulticastInterface(i);
3656 // Do this AFTER i->BSSID has been set up
3657 i->ifinfo.NetWake = (eflags & IFEF_EXPENSIVE)? mDNSfalse : NetWakeInterface(i);
3658 GetMAC(&i->ifinfo.MAC, scope_id);
3659 if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
3660 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
3661
3662 *p = i;
3663 return(i);
3664 }
3665
3666 #if APPLE_OSX_mDNSResponder
3667
3668 #if COMPILER_LIKES_PRAGMA_MARK
3669 #pragma mark -
3670 #pragma mark - AutoTunnel
3671 #endif
3672
3673 #define kRacoonPort 4500
3674
3675 static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
3676
3677 #ifndef NO_SECURITYFRAMEWORK
3678
3679 static CFMutableDictionaryRef domainStatusDict = NULL;
3680
3681 mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
3682 {
3683 if (q->LongLived)
3684 {
3685 if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
3686 return mStatus_NoSuchRecord;
3687 else if (q->state == LLQ_Poll)
3688 return mStatus_PollingMode;
3689 else if (q->state != LLQ_Established && !q->DuplicateOf)
3690 return mStatus_TransientErr;
3691 }
3692
3693 return mStatus_NoError;
3694 }
3695
3696 mDNSlocal mStatus UpdateLLQStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
3697 {
3698 mStatus status = mStatus_NoError;
3699 DNSQuestion* q, *worst_q = mDNSNULL;
3700 for (q = mDNSStorage.Questions; q; q=q->next)
3701 if (q->AuthInfo == info)
3702 {
3703 mStatus newStatus = CheckQuestionForStatus(q);
3704 if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
3705 else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; }
3706 else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
3707 }
3708
3709 if (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success");
3710 else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
3711 else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
3712 else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
3713 return status;
3714 }
3715
3716 mDNSlocal mStatus UpdateRRStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
3717 {
3718 AuthRecord *r;
3719
3720 if (info->deltime) return mStatus_NoError;
3721 for (r = mDNSStorage.ResourceRecords; r; r = r->next)
3722 {
3723 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
3724 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
3725 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
3726 // has already checked
3727 const domainname *n = r->resrec.name;
3728 while (n->c[0])
3729 {
3730 DomainAuthInfo *ptr;
3731 for (ptr = mDNSStorage.AuthInfoList; ptr; ptr = ptr->next)
3732 if (SameDomainName(&ptr->domain, n))
3733 {
3734 if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime))
3735 {
3736 mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
3737 return r->updateError;
3738 }
3739 }
3740 n = (const domainname *)(n->c + 1 + n->c[0]);
3741 }
3742 }
3743 return mStatus_NoError;
3744 }
3745
3746 #endif // ndef NO_SECURITYFRAMEWORK
3747
3748 // MUST be called with lock held
3749 mDNSlocal void UpdateAutoTunnelDomainStatus(const DomainAuthInfo *const info)
3750 {
3751 #ifdef NO_SECURITYFRAMEWORK
3752 (void)info;
3753 #else
3754 // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
3755 // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
3756 mDNS *const m = &mDNSStorage;
3757 const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL;
3758 const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL;
3759 char buffer[1024];
3760 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3761 CFStringRef domain = NULL;
3762 CFStringRef tmp = NULL;
3763 CFNumberRef num = NULL;
3764 mStatus status = mStatus_NoError;
3765 mStatus llqStatus = mStatus_NoError;
3766 char llqBuffer[1024];
3767
3768 mDNS_CheckLock(m);
3769
3770 if (!domainStatusDict)
3771 {
3772 domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3773 if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
3774 }
3775
3776 if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
3777
3778 mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c);
3779 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3780 if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3781
3782 if (info->deltime)
3783 {
3784 if (CFDictionaryContainsKey(domainStatusDict, domain))
3785 {
3786 CFDictionaryRemoveValue(domainStatusDict, domain);
3787 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3788 }
3789 CFRelease(domain);
3790 CFRelease(dict);
3791
3792 return;
3793 }
3794
3795 mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
3796 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3797 if (!tmp)
3798 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
3799 else
3800 {
3801 CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
3802 CFRelease(tmp);
3803 }
3804
3805 if (llq)
3806 {
3807 mDNSu32 port = mDNSVal16(llq->ExternalPort);
3808
3809 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3810 if (!num)
3811 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
3812 else
3813 {
3814 CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
3815 CFRelease(num);
3816 }
3817
3818 if (llq->Result)
3819 {
3820 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
3821 if (!num)
3822 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
3823 else
3824 {
3825 CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
3826 CFRelease(num);
3827 }
3828 }
3829 }
3830
3831 if (tun)
3832 {
3833 mDNSu32 port = mDNSVal16(tun->ExternalPort);
3834
3835 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3836 if (!num)
3837 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
3838 else
3839 {
3840 CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
3841 CFRelease(num);
3842 }
3843
3844 mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress);
3845 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3846 if (!tmp)
3847 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
3848 else
3849 {
3850 CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
3851 CFRelease(tmp);
3852 }
3853
3854 if (tun->Result)
3855 {
3856 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
3857 if (!num)
3858 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
3859 else
3860 {
3861 CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
3862 CFRelease(num);
3863 }
3864 }
3865 }
3866 if (tun || llq)
3867 {
3868 mDNSu32 code = m->LastNATMapResultCode;
3869
3870 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
3871 if (!num)
3872 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
3873 else
3874 {
3875 CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
3876 CFRelease(num);
3877 }
3878 }
3879
3880 mDNS_snprintf(buffer, sizeof(buffer), "Success");
3881 llqStatus = UpdateLLQStatus(llqBuffer, sizeof(llqBuffer), info);
3882 status = UpdateRRStatus(buffer, sizeof(buffer), info);
3883
3884 // If we have a bad signature error updating a RR, it overrides any error as it needs to be
3885 // reported so that it can be fixed automatically (or the user needs to be notified)
3886 if (status != mStatus_NoError)
3887 {
3888 LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer);
3889 }
3890 else if (m->Router.type == mDNSAddrType_None)
3891 {
3892 status = mStatus_NoRouter;
3893 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
3894 }
3895 else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
3896 {
3897 status = mStatus_NoRouter;
3898 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
3899 }
3900 else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress))
3901 {
3902 status = mStatus_ServiceNotRunning;
3903 mDNS_snprintf(buffer, sizeof(buffer), "No inner address");
3904 }
3905 else if (!llq && !tun)
3906 {
3907 status = mStatus_NotInitializedErr;
3908 mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
3909 }
3910 else if (llqStatus == mStatus_NoSuchRecord)
3911 {
3912 status = llqStatus;
3913 mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
3914 }
3915 else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
3916 {
3917 status = mStatus_DoubleNAT;
3918 mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address");
3919 }
3920 else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) ||
3921 (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
3922 (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
3923 {
3924 status = mStatus_NATPortMappingDisabled;
3925 mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router");
3926 }
3927 else if ((llq && llq->Result) || (tun && tun->Result))
3928 {
3929 status = mStatus_NATTraversal;
3930 mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
3931 }
3932 else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
3933 {
3934 status = mStatus_NATTraversal;
3935 mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
3936 }
3937 else
3938 {
3939 status = llqStatus;
3940 mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
3941 LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer);
3942 }
3943
3944 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
3945 if (!num)
3946 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
3947 else
3948 {
3949 CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
3950 CFRelease(num);
3951 }
3952
3953 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3954 if (!tmp)
3955 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
3956 else
3957 {
3958 CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
3959 CFRelease(tmp);
3960 }
3961
3962 if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
3963 !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
3964 {
3965 CFDictionarySetValue(domainStatusDict, domain, dict);
3966 if (!m->ShutdownTime)
3967 {
3968 LogInfo("UpdateAutoTunnelDomainStatus: %s status %d", status ? "failure" : "success", status);
3969 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3970 }
3971 }
3972
3973 CFRelease(domain);
3974 CFRelease(dict);
3975
3976 debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
3977 #endif // def NO_SECURITYFRAMEWORK
3978 }
3979
3980 // MUST be called with lock held
3981 mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
3982 {
3983 #ifdef NO_SECURITYFRAMEWORK
3984 (void) m;
3985 #else
3986 mDNS_CheckLock(m);
3987 DomainAuthInfo* info;
3988 for (info = m->AuthInfoList; info; info = info->next)
3989 if (info->AutoTunnel && !info->deltime)
3990 UpdateAutoTunnelDomainStatus(info);
3991 #endif // def NO_SECURITYFRAMEWORK
3992 }
3993
3994 mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we need racoon to accept incoming connections
3995 {
3996 DomainAuthInfo *info;
3997
3998 for (info = m->AuthInfoList; info; info = info->next)
3999 if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
4000 break;
4001
4002 if (info != AnonymousRacoonConfig)
4003 {
4004 AnonymousRacoonConfig = info;
4005 LogInfo("UpdateAnonymousRacoonConfig need not be done in mDNSResponder");
4006 }
4007 }
4008
4009 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
4010
4011 // Caller must hold the lock
4012 mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record)
4013 {
4014 mDNS_CheckLock(m);
4015
4016 LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c);
4017
4018 if (record->resrec.RecordType > kDNSRecordTypeDeregistering)
4019 {
4020 mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal);
4021 if (err)
4022 {
4023 record->resrec.RecordType = kDNSRecordTypeUnregistered;
4024 LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c);
4025 return mDNSfalse;
4026 }
4027 else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
4028 }
4029 else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType);
4030
4031 return mDNStrue;
4032 }
4033
4034 // Caller must hold the lock
4035 mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
4036 {
4037 if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord))
4038 {
4039 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
4040 m->NextSRVUpdate = NonZeroTime(m->timenow);
4041 }
4042 }
4043
4044 // Caller must hold the lock
4045 mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
4046 {
4047 mStatus err;
4048 mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result;
4049
4050 mDNS_CheckLock(m);
4051
4052 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem))
4053 {
4054 LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
4055 info->domain.c, info->AutoTunnelServiceStarted, info->deltime, &info->AutoTunnelInnerAddress, m->SleepState);
4056 DeregisterAutoTunnelHostRecord(m, info);
4057 }
4058 else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
4059 {
4060 mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
4061 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4062 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
4063 AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
4064 AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
4065 info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = info->AutoTunnelInnerAddress;
4066 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
4067
4068 err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
4069 if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c);
4070 else
4071 {
4072 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
4073 m->NextSRVUpdate = NonZeroTime(m->timenow);
4074 LogInfo("UpdateAutoTunnelHostRecord registering %##s", info->AutoTunnelHostRecord.namestorage.c);
4075 }
4076 }
4077 else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType);
4078 }
4079
4080 // Caller must hold the lock
4081 mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4082 {
4083 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
4084
4085 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget);
4086 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService);
4087 UpdateAutoTunnelHostRecord(m, info);
4088 }
4089
4090 // Caller must hold the lock
4091 mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4092 {
4093 mDNS_CheckLock(m);
4094
4095 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)
4096 {
4097 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);
4098 DeregisterAutoTunnelServiceRecords(m, info);
4099 }
4100 else
4101 {
4102 if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
4103 {
4104 // 1. Set up our address record for the external tunnel address
4105 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
4106 mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL,
4107 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4108 AssignDomainName (&info->AutoTunnelTarget.namestorage, (const domainname*) "\x0B" "_autotunnel");
4109 AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->hostlabel);
4110 AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
4111 info->AutoTunnelTarget.resrec.rdata->u.ipv4 = m->AutoTunnelNAT.ExternalAddress;
4112 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
4113
4114 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelTarget);
4115 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelTarget.namestorage.c);
4116 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelTarget.namestorage.c);
4117 }
4118 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType);
4119
4120 if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
4121 {
4122 // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
4123 mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL,
4124 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4125 AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4126 AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
4127 AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
4128 info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
4129 info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
4130 info->AutoTunnelService.resrec.rdata->u.srv.port = m->AutoTunnelNAT.ExternalPort;
4131 AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
4132 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
4133
4134 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelService);
4135 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelService.namestorage.c);
4136 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelService.namestorage.c);
4137 }
4138 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType);
4139
4140 UpdateAutoTunnelHostRecord(m, info);
4141
4142 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
4143 info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(m->AutoTunnelNAT.IntPort),
4144 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4145
4146 }
4147 }
4148
4149 // Caller must hold the lock
4150 mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4151 {
4152 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo);
4153 }
4154
4155 // Caller must hold the lock
4156 mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4157 {
4158 mDNS_CheckLock(m);
4159
4160 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime)
4161 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4162 else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
4163 {
4164 mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4165 ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
4166
4167 info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data);
4168 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
4169
4170 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
4171 if (err) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
4172 else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info->AutoTunnelDeviceInfo.namestorage.c);
4173 }
4174 else
4175 LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType);
4176 }
4177
4178 // Caller must hold the lock
4179 mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4180 {
4181 LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
4182
4183 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
4184 UpdateAutoTunnelHostRecord(m, info);
4185 UpdateAutoTunnelDomainStatus(info);
4186 }
4187
4188 // Caller must hold the lock
4189 mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4190 {
4191 mDNS_CheckLock(m);
4192
4193 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr) || m->SleepState != SleepState_Awake)
4194 DeregisterAutoTunnel6Record(m, info);
4195 else if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
4196 {
4197 mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
4198 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4199 AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
4200 AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
4201 AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
4202 info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr;
4203 info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
4204
4205 mStatus err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
4206 if (err) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err, info->AutoTunnel6Record.namestorage.c);
4207 else LogInfo("UpdateAutoTunnel6Record registering %##s", info->AutoTunnel6Record.namestorage.c);
4208
4209 UpdateAutoTunnelHostRecord(m, info);
4210
4211 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
4212 info->AutoTunnel6Record.namestorage.c, &m->AutoTunnelRelayAddr,
4213 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4214
4215 }
4216 else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType);
4217 }
4218
4219 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
4220 {
4221 DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
4222 if (result == mStatus_MemFree)
4223 {
4224 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
4225
4226 mDNS_Lock(m);
4227
4228 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
4229 if (rr == &info->AutoTunnelHostRecord)
4230 {
4231 rr->namestorage.c[0] = 0;
4232 m->NextSRVUpdate = NonZeroTime(m->timenow);
4233 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4234 }
4235 if (m->ShutdownTime)
4236 {
4237 LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
4238 mDNS_Unlock(m);
4239 return;
4240 }
4241 if (rr == &info->AutoTunnelHostRecord)
4242 {
4243 LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
4244 UpdateAutoTunnelHostRecord(m,info);
4245 }
4246 else if (rr == &info->AutoTunnelDeviceInfo)
4247 {
4248 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
4249 UpdateAutoTunnelDeviceInfoRecord(m,info);
4250 }
4251 else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
4252 {
4253 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
4254 UpdateAutoTunnelServiceRecords(m,info);
4255 }
4256 else if (rr == &info->AutoTunnel6Record)
4257 {
4258 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
4259 UpdateAutoTunnel6Record(m,info);
4260 }
4261
4262 mDNS_Unlock(m);
4263 }
4264 }
4265
4266 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
4267 {
4268 DomainAuthInfo *info;
4269
4270 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
4271 n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort));
4272
4273 mDNS_Lock(m);
4274
4275 m->NextSRVUpdate = NonZeroTime(m->timenow);
4276 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4277
4278 for (info = m->AuthInfoList; info; info = info->next)
4279 if (info->AutoTunnel)
4280 UpdateAutoTunnelServiceRecords(m, info);
4281
4282 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
4283
4284 UpdateAutoTunnelDomainStatuses(m);
4285
4286 mDNS_Unlock(m);
4287 }
4288
4289 mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
4290 {
4291 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
4292
4293 mDNS_Lock(m);
4294 // We forcibly deregister the records that are based on the hostname.
4295 // When deregistration of each completes, the MemFree callback will make the
4296 // appropriate Update* call to use the new name to reregister.
4297 DeregisterAutoTunnelHostRecord(m, info);
4298 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4299 DeregisterAutoTunnelServiceRecords(m, info);
4300 DeregisterAutoTunnel6Record(m, info);
4301 m->NextSRVUpdate = NonZeroTime(m->timenow);
4302 mDNS_Unlock(m);
4303 }
4304
4305 // Must be called with the lock held
4306 mDNSexport void StartServerTunnel(DomainAuthInfo *const info)
4307 {
4308 mDNS *const m = &mDNSStorage;
4309 if (info->deltime) return;
4310
4311 if (info->AutoTunnelServiceStarted)
4312 {
4313 // On wake from sleep, this function will be called when determining SRV targets,
4314 // and needs to re-register the host record for the target to be set correctly
4315 UpdateAutoTunnelHostRecord(m, info);
4316 return;
4317 }
4318
4319 info->AutoTunnelServiceStarted = mDNStrue;
4320
4321 // Now that we have a service in this domain, we need to try to register the
4322 // AutoTunnel records, because the relay connection & NAT-T may have already been
4323 // started for another domain. If the relay connection is not up or the NAT-T has not
4324 // yet succeeded, the Update* functions are smart enough to not register the records.
4325 // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
4326 // decide whether to register the AutoTunnel records in the calls below.
4327 UpdateAutoTunnelServiceRecords(m, info);
4328 UpdateAutoTunnel6Record(m, info);
4329 UpdateAutoTunnelDeviceInfoRecord(m, info);
4330 UpdateAutoTunnelHostRecord(m, info);
4331
4332 // If the global AutoTunnel NAT-T is not yet started, start it.
4333 if (!m->AutoTunnelNAT.clientContext)
4334 {
4335 m->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
4336 m->AutoTunnelNAT.clientContext = (void*)1; // Means AutoTunnelNAT Traversal is active;
4337 m->AutoTunnelNAT.Protocol = NATOp_MapUDP;
4338 m->AutoTunnelNAT.IntPort = IPSECPort;
4339 m->AutoTunnelNAT.RequestedPort = IPSECPort;
4340 m->AutoTunnelNAT.NATLease = 0;
4341 mStatus err = mDNS_StartNATOperation_internal(m, &m->AutoTunnelNAT);
4342 if (err) LogMsg("StartServerTunnel: error %d starting NAT mapping", err);
4343 }
4344 }
4345
4346 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
4347 {
4348 mDNSv6Addr loc_outer6;
4349 mDNSv6Addr rmt_outer6;
4350
4351 // When we are tunneling over IPv6 Relay address, the port number is zero
4352 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4353 {
4354 loc_outer6 = tun->loc_outer6;
4355 rmt_outer6 = tun->rmt_outer6;
4356 }
4357 else
4358 {
4359 loc_outer6 = zerov6Addr;
4360 loc_outer6.b[0] = tun->loc_outer.b[0];
4361 loc_outer6.b[1] = tun->loc_outer.b[1];
4362 loc_outer6.b[2] = tun->loc_outer.b[2];
4363 loc_outer6.b[3] = tun->loc_outer.b[3];
4364
4365 rmt_outer6 = zerov6Addr;
4366 rmt_outer6.b[0] = tun->rmt_outer.b[0];
4367 rmt_outer6.b[1] = tun->rmt_outer.b[1];
4368 rmt_outer6.b[2] = tun->rmt_outer.b[2];
4369 rmt_outer6.b[3] = tun->rmt_outer.b[3];
4370 }
4371
4372 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)));
4373 }
4374
4375 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
4376 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
4377
4378 mDNSlocal void ReissueBlockedQuestionWithType(domainname *d, mDNSBool success, mDNSu16 qtype)
4379 {
4380 mDNS *const m = &mDNSStorage;
4381 DNSQuestion *q = m->Questions;
4382 while (q)
4383 {
4384 if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
4385 {
4386 LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4387 mDNSQuestionCallback *tmp = q->QuestionCallback;
4388 q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
4389 mDNS_StopQuery(m, q);
4390 mDNS_StartQuery(m, q);
4391 q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
4392 if (!success) q->NoAnswer = NoAnswer_Fail;
4393 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
4394 // In general we have to assume that the question list might have changed in arbitrary ways.
4395 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
4396 // already in use. The safest solution is just to go back to the start of the list and start again.
4397 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
4398 // just one suspended question, so it's really a 2n algorithm.
4399 q = m->Questions;
4400 }
4401 else
4402 q = q->next;
4403 }
4404 }
4405
4406 mDNSlocal void ReissueBlockedQuestions(domainname *d, mDNSBool success)
4407 {
4408 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
4409 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
4410 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
4411 // 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.
4412 // 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.
4413 ReissueBlockedQuestionWithType(d, success, kDNSType_AAAA);
4414 ReissueBlockedQuestionWithType(d, mDNStrue, kDNSType_A);
4415 }
4416
4417 mDNSlocal void UnlinkAndReissueBlockedQuestions(ClientTunnel *tun, mDNSBool success)
4418 {
4419 mDNS *const m = &mDNSStorage;
4420 ClientTunnel **p = &m->TunnelClients;
4421 while (*p != tun && *p) p = &(*p)->next;
4422 if (*p) *p = tun->next;
4423 ReissueBlockedQuestions(&tun->dstname, success);
4424 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
4425 freeL("ClientTunnel", tun);
4426 }
4427
4428 mDNSlocal mDNSBool TunnelClientDeleteMatching(ClientTunnel *tun, mDNSBool v6Tunnel)
4429 {
4430 mDNS *const m = &mDNSStorage;
4431 ClientTunnel **p;
4432 mDNSBool needSetKeys = mDNStrue;
4433
4434 p = &tun->next;
4435 while (*p)
4436 {
4437 // Is this a tunnel to the same host that we are trying to setup now?
4438 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4439 else
4440 {
4441 ClientTunnel *old = *p;
4442 if (v6Tunnel)
4443 {
4444 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4445 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4446 if (old->q.ThisQInterval >= 0)
4447 {
4448 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4449 mDNS_StopQuery(m, &old->q);
4450 }
4451 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4452 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4453 !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
4454 !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
4455 {
4456 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4457 // the other parameters of the tunnel are different
4458 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4459 AutoTunnelSetKeys(old, mDNSfalse);
4460 }
4461 else
4462 {
4463 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4464 // as "tun" and "old" are identical
4465 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
4466 &old->rmt_inner);
4467 needSetKeys = mDNSfalse;
4468 }
4469 }
4470 else
4471 {
4472 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4473 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4474 if (old->q.ThisQInterval >= 0)
4475 {
4476 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4477 mDNS_StopQuery(m, &old->q);
4478 }
4479 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4480 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4481 !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
4482 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
4483 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
4484 {
4485 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4486 // the other parameters of the tunnel are different
4487 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4488 AutoTunnelSetKeys(old, mDNSfalse);
4489 }
4490 else
4491 {
4492 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4493 // as "tun" and "old" are identical
4494 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
4495 &old->rmt_inner);
4496 needSetKeys = mDNSfalse;
4497 }
4498 }
4499
4500 *p = old->next;
4501 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
4502 freeL("ClientTunnel", old);
4503 }
4504 }
4505 return needSetKeys;
4506 }
4507
4508 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
4509 // tunnel will be deleted
4510 mDNSlocal void TunnelClientDeleteAny(ClientTunnel *tun, mDNSBool v6Tunnel)
4511 {
4512 ClientTunnel **p;
4513
4514 p = &tun->next;
4515 while (*p)
4516 {
4517 // If there is more than one client tunnel to the same host, delete all of them.
4518 // We do this by just checking against the EUI64 rather than the full address
4519 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4520 else
4521 {
4522 ClientTunnel *old = *p;
4523 if (v6Tunnel)
4524 {
4525 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4526 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4527 }
4528 else
4529 {
4530 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4531 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4532 }
4533 if (old->q.ThisQInterval >= 0)
4534 {
4535 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4536 mDNS_StopQuery(&mDNSStorage, &old->q);
4537 }
4538 else
4539 {
4540 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4541 AutoTunnelSetKeys(old, mDNSfalse);
4542 }
4543 *p = old->next;
4544 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
4545 freeL("ClientTunnel", old);
4546 }
4547 }
4548 }
4549
4550 mDNSlocal void TunnelClientFinish(DNSQuestion *question, const ResourceRecord *const answer)
4551 {
4552 mDNS *const m = &mDNSStorage;
4553 mDNSBool needSetKeys = mDNStrue;
4554 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4555 mDNSBool v6Tunnel = mDNSfalse;
4556 DomainAuthInfo *info;
4557
4558 // If the port is zero, then we have a relay address of the peer
4559 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4560 v6Tunnel = mDNStrue;
4561
4562 if (v6Tunnel)
4563 {
4564 LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
4565 tun->rmt_outer6 = answer->rdata->u.ipv6;
4566 tun->loc_outer6 = m->AutoTunnelRelayAddr;
4567 }
4568 else
4569 {
4570 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
4571 tun->rmt_outer = answer->rdata->u.ipv4;
4572 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
4573 tmpDst.ip.v4 = tun->rmt_outer;
4574 mDNSAddr tmpSrc = zeroAddr;
4575 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
4576 if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
4577 else tun->loc_outer = m->AdvertisedV4.ip.v4;
4578 }
4579
4580 question->ThisQInterval = -1; // So we know this tunnel setup has completed
4581
4582 info = GetAuthInfoForName(m, &tun->dstname);
4583 if (!info)
4584 {
4585 LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
4586 ReissueBlockedQuestions(&tun->dstname, mDNSfalse);
4587 return;
4588 }
4589
4590 tun->loc_inner = info->AutoTunnelInnerAddress;
4591
4592 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
4593 // look for existing tunnels to see whether they have the same information for our peer.
4594 // If not, delete them and need to create a new tunnel. If they are same, just use the
4595 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
4596 TunnelClientDeleteAny(tun, !v6Tunnel);
4597 needSetKeys = TunnelClientDeleteMatching(tun, v6Tunnel);
4598
4599 if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
4600 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
4601
4602 mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
4603 LogInfo("TunnelClientFinish: Tunnel setup result %d", result);
4604 // Kick off any questions that were held pending this tunnel setup
4605 ReissueBlockedQuestions(&tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
4606 }
4607
4608 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
4609 {
4610 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4611 DomainAuthInfo *info;
4612
4613 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
4614
4615 if (!AddRecord) return;
4616 mDNS_StopQuery(m, question);
4617
4618 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
4619 // The code below will look for _autotunnel._udp SRV record followed by A record
4620 if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
4621 {
4622 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
4623 UnlinkAndReissueBlockedQuestions(tun, mDNSfalse);
4624 return;
4625 }
4626
4627 switch (tun->tc_state)
4628 {
4629 case TC_STATE_AAAA_PEER:
4630 if (question->qtype != kDNSType_AAAA)
4631 {
4632 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
4633 }
4634 info = GetAuthInfoForName(m, &tun->dstname);
4635 if (!info)
4636 {
4637 LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
4638 UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4639 return;
4640 }
4641 if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
4642 {
4643 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
4644 UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4645 return;
4646 }
4647 if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
4648 {
4649 LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6);
4650 UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
4651 return;
4652 }
4653 tun->rmt_inner = answer->rdata->u.ipv6;
4654 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
4655 if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
4656 {
4657 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
4658 tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
4659 question->qtype = kDNSType_AAAA;
4660 AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
4661 }
4662 else
4663 {
4664 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
4665 tun->tc_state = TC_STATE_SRV_PEER;
4666 question->qtype = kDNSType_SRV;
4667 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4668 }
4669 AppendDomainName(&question->qname, &tun->dstname);
4670 mDNS_StartQuery(m, &tun->q);
4671 return;
4672 case TC_STATE_AAAA_PEER_RELAY:
4673 if (question->qtype != kDNSType_AAAA)
4674 {
4675 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
4676 }
4677 // If it failed, look for the SRV record.
4678 if (!answer->rdlength)
4679 {
4680 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
4681 tun->tc_state = TC_STATE_SRV_PEER;
4682 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4683 AppendDomainName(&question->qname, &tun->dstname);
4684 question->qtype = kDNSType_SRV;
4685 mDNS_StartQuery(m, &tun->q);
4686 return;
4687 }
4688 TunnelClientFinish(question, answer);
4689 return;
4690 case TC_STATE_SRV_PEER:
4691 if (question->qtype != kDNSType_SRV)
4692 {
4693 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
4694 }
4695 LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
4696 tun->tc_state = TC_STATE_ADDR_PEER;
4697 AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
4698 tun->rmt_outer_port = answer->rdata->u.srv.port;
4699 question->qtype = kDNSType_A;
4700 mDNS_StartQuery(m, &tun->q);
4701 return;
4702 case TC_STATE_ADDR_PEER:
4703 if (question->qtype != kDNSType_A)
4704 {
4705 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
4706 }
4707 TunnelClientFinish(question, answer);
4708 return;
4709 default:
4710 LogMsg("AutoTunnelCallback: Unknown question %p", question);
4711 }
4712 }
4713
4714 // Must be called with the lock held
4715 mDNSexport void AddNewClientTunnel(DNSQuestion *const q)
4716 {
4717 mDNS *const m = &mDNSStorage;
4718 ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
4719 if (!p) return;
4720 AssignDomainName(&p->dstname, &q->qname);
4721 p->MarkedForDeletion = mDNSfalse;
4722 p->loc_inner = zerov6Addr;
4723 p->loc_outer = zerov4Addr;
4724 p->loc_outer6 = zerov6Addr;
4725 p->rmt_inner = zerov6Addr;
4726 p->rmt_outer = zerov4Addr;
4727 p->rmt_outer6 = zerov6Addr;
4728 p->rmt_outer_port = zeroIPPort;
4729 p->tc_state = TC_STATE_AAAA_PEER;
4730 p->next = m->TunnelClients;
4731 m->TunnelClients = p; // We intentionally build list in reverse order
4732
4733 p->q.InterfaceID = mDNSInterface_Any;
4734 p->q.flags = 0;
4735 p->q.Target = zeroAddr;
4736 AssignDomainName(&p->q.qname, &q->qname);
4737 p->q.qtype = kDNSType_AAAA;
4738 p->q.qclass = kDNSClass_IN;
4739 p->q.LongLived = mDNSfalse;
4740 p->q.ExpectUnique = mDNStrue;
4741 p->q.ForceMCast = mDNSfalse;
4742 p->q.ReturnIntermed = mDNStrue;
4743 p->q.SuppressUnusable = mDNSfalse;
4744 p->q.SearchListIndex = 0;
4745 p->q.AppendSearchDomains = 0;
4746 p->q.RetryWithSearchDomains = mDNSfalse;
4747 p->q.TimeoutQuestion = 0;
4748 p->q.WakeOnResolve = 0;
4749 p->q.UseBackgroundTrafficClass = mDNSfalse;
4750 p->q.ValidationRequired = 0;
4751 p->q.ValidatingResponse = 0;
4752 p->q.ProxyQuestion = 0;
4753 p->q.qnameOrig = mDNSNULL;
4754 p->q.AnonInfo = mDNSNULL;
4755 p->q.pid = mDNSPlatformGetPID();
4756 p->q.euid = 0;
4757 p->q.QuestionCallback = AutoTunnelCallback;
4758 p->q.QuestionContext = p;
4759
4760 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
4761 mDNS_StartQuery_internal(m, &p->q);
4762 }
4763
4764 #endif // APPLE_OSX_mDNSResponder
4765
4766 #if COMPILER_LIKES_PRAGMA_MARK
4767 #pragma mark -
4768 #pragma mark - Power State & Configuration Change Management
4769 #endif
4770
4771 mDNSlocal mStatus ReorderInterfaceList()
4772 {
4773 // Disable Reorder lists till <rdar://problem/30071012> is fixed to prevent spurious name conflicts
4774 return (mStatus_NoError);
4775
4776 mDNS *const m = &mDNSStorage;
4777 nwi_state_t state = nwi_state_copy();
4778
4779 if (state == mDNSNULL)
4780 {
4781 LogMsg("NWI State is NULL!");
4782 return (mStatus_Invalid);
4783 }
4784
4785 // Get the count of interfaces
4786 mDNSu32 count = nwi_state_get_interface_names(state, mDNSNULL, 0);
4787 if (count == 0)
4788 {
4789 LogMsg("Unable to get the ordered list of interface names");
4790 nwi_state_release(state);
4791 return (mStatus_Invalid);
4792 }
4793
4794 // Get the ordered interface list
4795 int i;
4796 const char *names[count];
4797 count = nwi_state_get_interface_names(state, names, count);
4798
4799 NetworkInterfaceInfo *newList = mDNSNULL;
4800 for (i = count-1; i >= 0; i--)
4801 { // Build a new ordered interface list
4802 NetworkInterfaceInfo **ptr = &m->HostInterfaces;
4803 while (*ptr != mDNSNULL )
4804 {
4805 if (strcmp((*ptr)->ifname, names[i]) == 0)
4806 {
4807 NetworkInterfaceInfo *node = *ptr;
4808 *ptr = (*ptr)->next;
4809 node->next = newList;
4810 newList = node;
4811 }
4812 else
4813 ptr = &((*ptr)->next);
4814 }
4815 }
4816
4817 // Get to the end of the list
4818 NetworkInterfaceInfo *newListEnd = newList;
4819 while (newListEnd != mDNSNULL && newListEnd->next != mDNSNULL)
4820 newListEnd = newListEnd->next;
4821
4822 // Add any remaing interfaces to the end of the sorted list
4823 if (newListEnd != mDNSNULL)
4824 newListEnd->next = m->HostInterfaces;
4825
4826 // If we have a valid new list, point to that now
4827 if (newList != mDNSNULL)
4828 m->HostInterfaces = newList;
4829
4830 nwi_state_release(state);
4831 return (mStatus_NoError);
4832 }
4833
4834 mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
4835 {
4836 mDNS *const m = &mDNSStorage;
4837 mDNSBool foundav4 = mDNSfalse;
4838 mDNSBool foundav6 = mDNSfalse;
4839 struct ifaddrs *ifa = myGetIfAddrs(0);
4840 struct ifaddrs *v4Loopback = NULL;
4841 struct ifaddrs *v6Loopback = NULL;
4842 char defaultname[64];
4843 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
4844 if (InfoSocket < 3 && errno != EAFNOSUPPORT)
4845 LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
4846
4847 if (m->SleepState == SleepState_Sleeping) ifa = NULL;
4848
4849 while (ifa)
4850 {
4851 #if LIST_ALL_INTERFACES
4852 if (ifa->ifa_addr)
4853 {
4854 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
4855 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
4856 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4857 else if (ifa->ifa_addr->sa_family == AF_LINK)
4858 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
4859 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4860 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
4861 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
4862 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4863 }
4864 else
4865 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X ifa_addr is NOT set",
4866 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags);
4867
4868 if (!(ifa->ifa_flags & IFF_UP))
4869 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
4870 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4871 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4872 if (!(ifa->ifa_flags & IFF_MULTICAST))
4873 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
4874 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4875 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4876 if (ifa->ifa_flags & IFF_POINTOPOINT)
4877 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
4878 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4879 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4880 if (ifa->ifa_flags & IFF_LOOPBACK)
4881 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
4882 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4883 ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4884 #endif
4885
4886 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
4887 {
4888 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
4889 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
4890 mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
4891 }
4892
4893 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr && !isCoprocessorInterface(InfoSocket, ifa->ifa_name))
4894 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
4895 {
4896 if (!ifa->ifa_netmask)
4897 {
4898 mDNSAddr ip;
4899 SetupAddr(&ip, ifa->ifa_addr);
4900 LogMsg("UpdateInterfaceList: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
4901 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
4902 }
4903 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
4904 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4905 else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0)
4906 {
4907 mDNSAddr ip;
4908 SetupAddr(&ip, ifa->ifa_addr);
4909 LogMsg("UpdateInterfaceList: ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
4910 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
4911 }
4912 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
4913 else if ((int)if_nametoindex(ifa->ifa_name) <= 0)
4914 {
4915 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
4916 }
4917 else
4918 {
4919 // Make sure ifa_netmask->sa_family is set correctly
4920 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4921 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
4922 int ifru_flags6 = 0;
4923
4924 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
4925 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
4926 {
4927 struct in6_ifreq ifr6;
4928 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
4929 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
4930 ifr6.ifr_addr = *sin6;
4931 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
4932 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
4933 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
4934 }
4935
4936 if (!(ifru_flags6 & (IN6_IFF_TENTATIVE | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
4937 {
4938 if (ifa->ifa_flags & IFF_LOOPBACK)
4939 {
4940 if (ifa->ifa_addr->sa_family == AF_INET)
4941 v4Loopback = ifa;
4942 else if (sin6->sin6_addr.s6_addr[0] != 0xFD)
4943 v6Loopback = ifa;
4944 }
4945 else
4946 {
4947 NetworkInterfaceInfoOSX *i = AddInterfaceToList(ifa, utc);
4948 if (i && MulticastInterface(i) && i->ifinfo.Advertise)
4949 {
4950 if (ifa->ifa_addr->sa_family == AF_INET)
4951 foundav4 = mDNStrue;
4952 else
4953 foundav6 = mDNStrue;
4954 }
4955 }
4956 }
4957 }
4958 }
4959 ifa = ifa->ifa_next;
4960 }
4961
4962 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
4963 if (!foundav4 && v4Loopback) AddInterfaceToList(v4Loopback, utc);
4964 if (!foundav6 && v6Loopback) AddInterfaceToList(v6Loopback, utc);
4965
4966 if (InfoSocket >= 0)
4967 close(InfoSocket);
4968
4969 mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
4970 m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
4971
4972 // Set up the nice label
4973 domainlabel nicelabel;
4974 nicelabel.c[0] = 0;
4975 GetUserSpecifiedFriendlyComputerName(&nicelabel);
4976 if (nicelabel.c[0] == 0)
4977 {
4978 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
4979 MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
4980 }
4981
4982 // Set up the RFC 1034-compliant label
4983 domainlabel hostlabel;
4984 hostlabel.c[0] = 0;
4985 GetUserSpecifiedLocalHostName(&hostlabel);
4986 if (hostlabel.c[0] == 0)
4987 {
4988 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
4989 MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
4990 }
4991
4992 mDNSBool namechange = mDNSfalse;
4993
4994 // We use a case-sensitive comparison here because even though changing the capitalization
4995 // of the name alone is not significant to DNS, it's still a change from the user's point of view
4996 if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
4997 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
4998 else
4999 {
5000 if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
5001 LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
5002 m->p->usernicelabel = m->nicelabel = nicelabel;
5003 namechange = mDNStrue;
5004 }
5005
5006 if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
5007 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
5008 else
5009 {
5010 if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
5011 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
5012 m->p->userhostlabel = m->hostlabel = hostlabel;
5013 mDNS_SetFQDN(m);
5014 namechange = mDNStrue;
5015 }
5016
5017 if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
5018 {
5019 #if APPLE_OSX_mDNSResponder
5020 DomainAuthInfo *info;
5021 for (info = m->AuthInfoList; info; info = info->next)
5022 if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
5023 #endif // APPLE_OSX_mDNSResponder
5024 }
5025
5026 return(mStatus_NoError);
5027 }
5028
5029 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
5030 // Returns -1 if all the one-bits are not contiguous
5031 mDNSlocal int CountMaskBits(mDNSAddr *mask)
5032 {
5033 int i = 0, bits = 0;
5034 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
5035 while (i < bytes)
5036 {
5037 mDNSu8 b = mask->ip.v6.b[i++];
5038 while (b & 0x80) { bits++; b <<= 1; }
5039 if (b) return(-1);
5040 }
5041 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
5042 return(bits);
5043 }
5044
5045 // Returns count of non-link local V4 addresses registered (why? -- SC)
5046 mDNSlocal int SetupActiveInterfaces(mDNSs32 utc)
5047 {
5048 mDNS *const m = &mDNSStorage;
5049 NetworkInterfaceInfoOSX *i;
5050 int count = 0;
5051
5052 // Recalculate SuppressProbes time based on the current set of active interfaces.
5053 m->SuppressProbes = 0;
5054 for (i = m->p->InterfaceList; i; i = i->next)
5055 if (i->Exists)
5056 {
5057 NetworkInterfaceInfo *const n = &i->ifinfo;
5058 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
5059 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
5060
5061 if (i->Registered && i->Registered != primary) // Sanity check
5062 {
5063 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
5064 i->Registered = mDNSNULL;
5065 }
5066
5067 if (!i->Registered)
5068 {
5069 InterfaceActivationSpeed activationSpeed;
5070
5071 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5072 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5073 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it.
5074 i->Registered = primary;
5075
5076 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
5077 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
5078 // 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.
5079 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
5080
5081 // The "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
5082 // every time a new interface is created. We think it is a duplicate and hence consider it
5083 // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
5084 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
5085 // logs a warning message to system.log noting frequent interface transitions.
5086 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
5087 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
5088 {
5089 activationSpeed = FastActivation;
5090 LogInfo("SetupActiveInterfaces: %s DirectLink interface registering", i->ifinfo.ifname);
5091 }
5092 else if (i->Flashing && i->Occulting)
5093 {
5094 activationSpeed = SlowActivation;
5095 }
5096 else
5097 {
5098 activationSpeed = NormalActivation;
5099 }
5100
5101 mDNS_RegisterInterface(m, n, activationSpeed);
5102
5103 if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
5104 LogInfo("SetupActiveInterfaces: Registered %7s(%u) BSSID %.6a Struct addr %p, primary %p, %#a/%d%s%s%s",
5105 i->ifinfo.ifname, i->scope_id, &i->BSSID, i, primary, &n->ip, CountMaskBits(&n->mask),
5106 i->Flashing ? " (Flashing)" : "",
5107 i->Occulting ? " (Occulting)" : "",
5108 n->InterfaceActive ? " (Primary)" : "");
5109
5110 if (!n->McastTxRx)
5111 {
5112 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);
5113 #if TARGET_OS_EMBEDDED
5114 // We join the Bonjour multicast group on Apple embedded platforms ONLY when a client request is active,
5115 // so we leave the multicast group here to clear any residual group membership.
5116 if (i->sa_family == AF_INET)
5117 {
5118 struct ip_mreq imr;
5119 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
5120 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
5121 imr.imr_interface = primary->ifa_v4addr;
5122
5123 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET) == i)
5124 {
5125 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
5126 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
5127 if (err < 0 && (errno != EADDRNOTAVAIL))
5128 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
5129 }
5130 }
5131 if (i->sa_family == AF_INET6)
5132 {
5133 struct ipv6_mreq i6mr;
5134 i6mr.ipv6mr_interface = primary->scope_id;
5135 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
5136
5137 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET6) == i)
5138 {
5139 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IPV6_LEAVE_GROUP for %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5140 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
5141 if (err < 0 && (errno != EADDRNOTAVAIL))
5142 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5143 }
5144 }
5145 #endif // TARGET_OS_EMBEDDED
5146 }
5147 else
5148 {
5149 if (i->sa_family == AF_INET)
5150 {
5151 struct ip_mreq imr;
5152 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
5153 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
5154 imr.imr_interface = primary->ifa_v4addr;
5155
5156 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
5157 // before trying to join the group, to clear out stale kernel state which may be lingering.
5158 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
5159 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
5160 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
5161 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
5162 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
5163 // because by the time we get the configuration change notification, the interface is already gone,
5164 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
5165 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
5166 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET) == i)
5167 {
5168 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);
5169 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
5170 if (err < 0 && (errno != EADDRNOTAVAIL))
5171 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
5172 }
5173
5174 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
5175 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
5176 // Joining same group twice can give "Address already in use" error -- no need to report that
5177 if (err < 0 && (errno != EADDRINUSE))
5178 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
5179 }
5180 if (i->sa_family == AF_INET6)
5181 {
5182 struct ipv6_mreq i6mr;
5183 i6mr.ipv6mr_interface = primary->scope_id;
5184 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
5185
5186 if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET6) == i)
5187 {
5188 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);
5189 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
5190 if (err < 0 && (errno != EADDRNOTAVAIL))
5191 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5192 }
5193
5194 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5195 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
5196 // Joining same group twice can give "Address already in use" error -- no need to report that
5197 if (err < 0 && (errno != EADDRINUSE))
5198 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5199 }
5200 }
5201 }
5202 }
5203
5204 return count;
5205 }
5206
5207 mDNSlocal void MarkAllInterfacesInactive(mDNSs32 utc)
5208 {
5209 NetworkInterfaceInfoOSX *i;
5210 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
5211 {
5212 if (i->Exists) i->LastSeen = utc;
5213 i->Exists = mDNSfalse;
5214 }
5215 }
5216
5217 // Returns count of non-link local V4 addresses deregistered (why? -- SC)
5218 mDNSlocal int ClearInactiveInterfaces(mDNSs32 utc)
5219 {
5220 mDNS *const m = &mDNSStorage;
5221 // First pass:
5222 // If an interface is going away, then deregister this from the mDNSCore.
5223 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
5224 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
5225 // it refers to has gone away we'll crash.
5226 NetworkInterfaceInfoOSX *i;
5227 int count = 0;
5228 for (i = m->p->InterfaceList; i; i = i->next)
5229 {
5230 // If this interface is no longer active, or its InterfaceID is changing, deregister it
5231 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
5232 if (i->Registered)
5233 if (i->Exists == 0 || i->Exists == MulticastStateChanged || i->Registered != primary)
5234 {
5235 InterfaceActivationSpeed activationSpeed;
5236
5237 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
5238 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5239 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary,
5240 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
5241 i->Flashing ? " (Flashing)" : "",
5242 i->Occulting ? " (Occulting)" : "",
5243 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5244
5245 // "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
5246 // every time it creates a new interface. We think it is a duplicate and hence consider it
5247 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
5248 // stale data returned to the application even after the interface is removed. The application
5249 // then starts to send data but the new interface is not yet created.
5250 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
5251 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
5252 {
5253 activationSpeed = FastActivation;
5254 LogInfo("ClearInactiveInterfaces: %s DirectLink interface deregistering", i->ifinfo.ifname);
5255 }
5256 else if (i->Flashing && i->Occulting)
5257 {
5258 activationSpeed = SlowActivation;
5259 }
5260 else
5261 {
5262 activationSpeed = NormalActivation;
5263 }
5264 mDNS_DeregisterInterface(m, &i->ifinfo, activationSpeed);
5265
5266 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
5267 i->Registered = mDNSNULL;
5268 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5269 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5270 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
5271
5272 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
5273 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
5274 }
5275 }
5276
5277 // Second pass:
5278 // Now that everything that's going to deregister has done so, we can clean up and free the memory
5279 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
5280 while (*p)
5281 {
5282 i = *p;
5283 // If no longer active, delete interface from list and free memory
5284 if (!i->Exists)
5285 {
5286 if (i->LastSeen == utc) i->LastSeen = utc - 1;
5287 const mDNSBool delete = (i->isAWDL || (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0)) && (utc - i->LastSeen >= 60);
5288 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
5289 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
5290 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
5291 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5292 #if APPLE_OSX_mDNSResponder
5293 if (i->BPF_fd >= 0) CloseBPF(i);
5294 #endif // APPLE_OSX_mDNSResponder
5295 if (delete)
5296 {
5297 *p = i->next;
5298 freeL("NetworkInterfaceInfoOSX", i);
5299 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
5300 }
5301 }
5302 p = &i->next;
5303 }
5304 return count;
5305 }
5306
5307 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
5308 {
5309 DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
5310 if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
5311 else
5312 {
5313 dnle->next = mDNSNULL;
5314 dnle->uid = uid;
5315 AssignDomainName(&dnle->name, name);
5316 **List = dnle;
5317 *List = &dnle->next;
5318 }
5319 }
5320
5321 mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
5322 {
5323 dns_resolver_t *a = *(dns_resolver_t**)aa;
5324 dns_resolver_t *b = *(dns_resolver_t**)bb;
5325
5326 return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
5327 }
5328
5329 mDNSlocal void UpdateSearchDomainHash(MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID)
5330 {
5331 mDNS *const m = &mDNSStorage;
5332 char *buf = ".";
5333 mDNSu32 scopeid = 0;
5334 char ifid_buf[16];
5335
5336 if (domain)
5337 buf = domain;
5338 //
5339 // Hash the search domain name followed by the InterfaceID.
5340 // As we have scoped search domains, we also included InterfaceID. If either of them change,
5341 // we will detect it. Even if the order of them change, we will detect it.
5342 //
5343 // Note: We have to handle a few of these tricky cases.
5344 //
5345 // 1) Current: com, apple.com Changing to: comapple.com
5346 // 2) Current: a.com,b.com Changing to a.comb.com
5347 // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
5348 // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
5349 //
5350 // There are more variants of the above. The key thing is if we include the null in each case
5351 // at the end of name and the InterfaceID, it will prevent a new name (which can't include
5352 // NULL as part of the name) to be mistakenly thought of as a old name.
5353
5354 scopeid = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
5355 // mDNS_snprintf always null terminates
5356 if (mDNS_snprintf(ifid_buf, sizeof(ifid_buf), "%u", scopeid) >= sizeof(ifid_buf))
5357 LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid);
5358
5359 LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf, ifid_buf);
5360 MD5_Update(sdc, buf, strlen(buf) + 1);
5361 MD5_Update(sdc, ifid_buf, strlen(ifid_buf) + 1);
5362 }
5363
5364 mDNSlocal void FinalizeSearchDomainHash(MD5_CTX *sdc)
5365 {
5366 mDNS *const m = &mDNSStorage;
5367 mDNSu8 md5_hash[MD5_LEN];
5368
5369 MD5_Final(md5_hash, sdc);
5370
5371 if (memcmp(md5_hash, m->SearchDomainsHash, MD5_LEN))
5372 {
5373 // If the hash is different, either the search domains have changed or
5374 // the ordering between them has changed. Restart the questions that
5375 // would be affected by this.
5376 LogInfo("FinalizeSearchDomains: The hash is different");
5377 memcpy(m->SearchDomainsHash, md5_hash, MD5_LEN);
5378 RetrySearchDomainQuestions(m);
5379 }
5380 else { LogInfo("FinalizeSearchDomains: The hash is same"); }
5381 }
5382
5383 mDNSexport const char *DNSScopeToString(mDNSu32 scope)
5384 {
5385 switch (scope)
5386 {
5387 case kScopeNone:
5388 return "Unscoped";
5389 case kScopeInterfaceID:
5390 return "InterfaceScoped";
5391 case kScopeServiceID:
5392 return "ServiceScoped";
5393 default:
5394 return "Unknown";
5395 }
5396 }
5397
5398 mDNSlocal void ConfigSearchDomains(dns_resolver_t *resolver, mDNSInterfaceID interfaceId, mDNSu32 scope, MD5_CTX *sdc, uint64_t generation)
5399 {
5400 const char *scopeString = DNSScopeToString(scope);
5401 int j;
5402 domainname d;
5403
5404 if (scope == kScopeNone)
5405 interfaceId = mDNSInterface_Any;
5406
5407 if (scope == kScopeNone || scope == kScopeInterfaceID)
5408 {
5409 for (j = 0; j < resolver->n_search; j++)
5410 {
5411 if (MakeDomainNameFromDNSNameString(&d, resolver->search[j]) != NULL)
5412 {
5413 static char interface_buf[32];
5414 mDNS_snprintf(interface_buf, sizeof(interface_buf), "for interface %s", InterfaceNameForID(&mDNSStorage, interfaceId));
5415 LogInfo("ConfigSearchDomains: (%s) configuring search domain %s %s (generation= %llu)", scopeString,
5416 resolver->search[j], (interfaceId == mDNSInterface_Any) ? "" : interface_buf, generation);
5417 UpdateSearchDomainHash(sdc, resolver->search[j], interfaceId);
5418 mDNS_AddSearchDomain_CString(resolver->search[j], interfaceId);
5419 }
5420 else
5421 {
5422 LogInfo("ConfigSearchDomains: An invalid search domain was detected for %s domain %s n_nameserver %d, (generation= %llu)",
5423 DNSScopeToString(scope), resolver->domain, resolver->n_nameserver, generation);
5424 }
5425 }
5426 }
5427 else
5428 {
5429 LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString, InterfaceNameForID(&mDNSStorage, interfaceId));
5430 }
5431 }
5432
5433 mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNSu32 ifindex)
5434 {
5435 NetworkInterfaceInfoOSX *ni;
5436 mDNSInterfaceID interface;
5437
5438 for (ni = mDNSStorage.p->InterfaceList; ni; ni = ni->next)
5439 {
5440 if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex)
5441 break;
5442 }
5443 if (ni != NULL)
5444 {
5445 interface = ni->ifinfo.InterfaceID;
5446 }
5447 else
5448 {
5449 // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
5450 // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
5451 // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
5452 // As the caller is going to ack the configuration always, we have to add all the DNS servers
5453 // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
5454
5455 LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex);
5456
5457 // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
5458 interface = (mDNSInterfaceID)(unsigned long)ifindex;
5459 }
5460 return interface;
5461 }
5462
5463 mDNSlocal void ConfigNonUnicastResolver(dns_resolver_t *r)
5464 {
5465 char *opt = r->options;
5466 domainname d;
5467
5468 if (opt && !strncmp(opt, "mdns", strlen(opt)))
5469 {
5470 if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5471 {
5472 LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain);
5473 return;
5474 }
5475 mDNS_AddMcastResolver(&mDNSStorage, &d, mDNSInterface_Any, r->timeout);
5476 }
5477 }
5478
5479 mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID)
5480 {
5481 int n;
5482 domainname d;
5483 int serviceID = 0;
5484 mDNSBool cellIntf = mDNSfalse;
5485 mDNSBool reqA, reqAAAA;
5486 NetworkInterfaceInfoOSX *info;
5487 mDNSBool isExpensive;
5488 mDNSBool isCLAT46;
5489
5490 if (!r->domain || !*r->domain)
5491 {
5492 d.c[0] = 0;
5493 }
5494 else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5495 {
5496 LogMsg("ConfigDNSServers: bad domain %s", r->domain);
5497 return;
5498 }
5499 // Parse the resolver specific attributes that affects all the DNS servers.
5500 if (scope == kScopeServiceID)
5501 {
5502 serviceID = r->service_identifier;
5503 }
5504
5505 #if TARGET_OS_IPHONE
5506 cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
5507 #endif
5508 reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse);
5509 reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
5510 info = IfindexToInterfaceInfoOSX(interface);
5511 isExpensive = (info && info->isExpensive) ? mDNStrue : mDNSfalse;
5512 isCLAT46 = (info && info->isCLAT46) ? mDNStrue : mDNSfalse;
5513
5514 for (n = 0; n < r->n_nameserver; n++)
5515 {
5516 mDNSAddr saddr;
5517 DNSServer *s;
5518
5519 if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6)
5520 continue;
5521
5522 if (SetupAddr(&saddr, r->nameserver[n]))
5523 {
5524 LogMsg("ConfigDNSServers: Bad address");
5525 continue;
5526 }
5527
5528 // The timeout value is for all the DNS servers in a given resolver, hence we pass
5529 // the timeout value only for the first DNSServer. If we don't have a value in the
5530 // resolver, then use the core's default value
5531 //
5532 // Note: this assumes that when the core picks a list of DNSServers for a question,
5533 // it takes the sum of all the timeout values for all DNS servers. By doing this, it
5534 // tries all the DNS servers in a specified timeout
5535 s = mDNS_AddDNSServer(&mDNSStorage, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope,
5536 (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, isExpensive, isCLAT46,
5537 resGroupID, reqA, reqAAAA, mDNStrue);
5538 if (s)
5539 {
5540 LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c);
5541 }
5542 }
5543 }
5544
5545 // ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
5546 // Service scope resolvers. This is indicated by the scope argument.
5547 //
5548 // "resolver" has entries that should only be used for unscoped questions.
5549 //
5550 // "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
5551 // interface index (q->InterfaceID)
5552 //
5553 // "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
5554 // a service identifier (q->ServiceID)
5555 //
5556 mDNSlocal void ConfigResolvers(dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc, mDNSu16 resGroupID)
5557 {
5558 int i;
5559 dns_resolver_t **resolver;
5560 int nresolvers;
5561 const char *scopeString = DNSScopeToString(scope);
5562 mDNSInterfaceID interface;
5563
5564 switch (scope)
5565 {
5566 case kScopeNone:
5567 resolver = config->resolver;
5568 nresolvers = config->n_resolver;
5569 break;
5570 case kScopeInterfaceID:
5571 resolver = config->scoped_resolver;
5572 nresolvers = config->n_scoped_resolver;
5573 break;
5574 case kScopeServiceID:
5575 resolver = config->service_specific_resolver;
5576 nresolvers = config->n_service_specific_resolver;
5577 break;
5578 default:
5579 return;
5580 }
5581 qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
5582
5583 for (i = 0; i < nresolvers; i++)
5584 {
5585 dns_resolver_t *r = resolver[i];
5586
5587 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString, i, r->domain, r->n_nameserver);
5588
5589 interface = mDNSInterface_Any;
5590
5591 // Parse the interface index
5592 if (r->if_index != 0)
5593 {
5594 interface = ConfigParseInterfaceID(r->if_index);
5595 }
5596
5597 if (setsearch)
5598 {
5599 ConfigSearchDomains(resolver[i], interface, scope, sdc, config->generation);
5600
5601 // Parse other scoped resolvers for search lists
5602 if (!setservers)
5603 continue;
5604 }
5605
5606 if (r->port == 5353 || r->n_nameserver == 0)
5607 {
5608 ConfigNonUnicastResolver(r);
5609 }
5610 else
5611 {
5612 // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the
5613 // scoped resolver are not used by other non-scoped or scoped resolvers.
5614 if (scope != kScopeNone)
5615 resGroupID++;
5616
5617 ConfigDNSServers(r, interface, scope, resGroupID);
5618 }
5619 }
5620 }
5621
5622 #if APPLE_OSX_mDNSResponder
5623 mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
5624 {
5625 if (QuerySuppressed(q))
5626 {
5627 debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5628 return mDNSfalse;
5629 }
5630 if (mDNSOpaque16IsZero(q->TargetQID))
5631 {
5632 debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5633 return mDNSfalse;
5634 }
5635 // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
5636 // for trigger.
5637 if (q->LOAddressAnswers)
5638 {
5639 debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5640 return mDNSfalse;
5641 }
5642 return mDNStrue;
5643 }
5644 #endif
5645
5646 // This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
5647 // We set our state appropriately so that if we start receiving answers, trigger the
5648 // upper layer to retry DNS questions.
5649 #if APPLE_OSX_mDNSResponder
5650 mDNSexport void mDNSPlatformUpdateDNSStatus(DNSQuestion *q)
5651 {
5652 mDNS *const m = &mDNSStorage;
5653 if (!QuestionValidForDNSTrigger(q))
5654 return;
5655
5656 // Ignore applications that start and stop queries for no reason before we ever talk
5657 // to any DNS server.
5658 if (!q->triedAllServersOnce)
5659 {
5660 LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q->qname.c, DNSTypeName(q->qtype));
5661 return;
5662 }
5663 if (q->qtype == kDNSType_A)
5664 m->p->v4answers = 0;
5665 if (q->qtype == kDNSType_AAAA)
5666 m->p->v6answers = 0;
5667 if (!m->p->v4answers || !m->p->v6answers)
5668 {
5669 LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, question %##s (%s)", m->p->v4answers, m->p->v6answers, q->qname.c,
5670 DNSTypeName(q->qtype));
5671 }
5672 }
5673 #endif
5674
5675 mDNSlocal void AckConfigd(dns_config_t *config)
5676 {
5677 mDNS_CheckLock(&mDNSStorage);
5678
5679 // Acking the configuration triggers configd to reissue the reachability queries
5680 mDNSStorage.p->DNSTrigger = NonZeroTime(mDNSStorage.timenow);
5681 _dns_configuration_ack(config, "com.apple.mDNSResponder");
5682 }
5683
5684 // If v4q is non-NULL, it means we have received some answers for "A" type questions
5685 // If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
5686 #if APPLE_OSX_mDNSResponder
5687 mDNSexport void mDNSPlatformTriggerDNSRetry(DNSQuestion *v4q, DNSQuestion *v6q)
5688 {
5689 mDNS *const m = &mDNSStorage;
5690 mDNSBool trigger = mDNSfalse;
5691 mDNSs32 timenow;
5692
5693 // Don't send triggers too often.
5694 // If we have started delivering answers to questions, we should send a trigger
5695 // if the time permits. If we are delivering answers, we should set the state
5696 // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know
5697 // whether the answers that are being delivered currently is for configd or some
5698 // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
5699 // then we won't deliver the trigger later when it is okay to send one as the
5700 // "answers" are already set to 1. Hence, don't affect the state of v4answers and
5701 // v6answers if we are not delivering triggers.
5702 mDNS_Lock(m);
5703 timenow = m->timenow;
5704 if (m->p->DNSTrigger && (timenow - m->p->DNSTrigger) < DNS_TRIGGER_INTERVAL)
5705 {
5706 if (!m->p->v4answers || !m->p->v6answers)
5707 {
5708 debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
5709 (timenow - m->p->DNSTrigger), m->p->v4answers, m->p->v6answers);
5710 }
5711 mDNS_Unlock(m);
5712 return;
5713 }
5714 mDNS_Unlock(m);
5715 if (v4q != NULL && QuestionValidForDNSTrigger(v4q))
5716 {
5717 int old = m->p->v4answers;
5718
5719 m->p->v4answers = 1;
5720
5721 // If there are IPv4 answers now and previously we did not have
5722 // any answers, trigger a DNS change so that reachability
5723 // can retry the queries again.
5724 if (!old)
5725 {
5726 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
5727 v4q->qname.c, DNSTypeName(v4q->qtype));
5728 trigger = mDNStrue;
5729 }
5730 }
5731 if (v6q != NULL && QuestionValidForDNSTrigger(v6q))
5732 {
5733 int old = m->p->v6answers;
5734
5735 m->p->v6answers = 1;
5736 // If there are IPv6 answers now and previously we did not have
5737 // any answers, trigger a DNS change so that reachability
5738 // can retry the queries again.
5739 if (!old)
5740 {
5741 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
5742 v6q->qname.c, DNSTypeName(v6q->qtype));
5743 trigger = mDNStrue;
5744 }
5745 }
5746 if (trigger)
5747 {
5748 dns_config_t *config = dns_configuration_copy();
5749 if (config)
5750 {
5751 mDNS_Lock(m);
5752 AckConfigd(config);
5753 mDNS_Unlock(m);
5754 dns_configuration_free(config);
5755 }
5756 else
5757 {
5758 LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
5759 }
5760 }
5761 }
5762
5763 mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
5764 {
5765 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
5766 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
5767 if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver &&
5768 config->resolver[0]->nameserver[0])
5769 {
5770 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
5771 }
5772 else
5773 {
5774 ActiveDirectoryPrimaryDomain.c[0] = 0;
5775 }
5776
5777 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
5778 ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
5779 if (config->n_resolver && config->resolver[0]->n_nameserver &&
5780 SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
5781 {
5782 SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
5783 }
5784 else
5785 {
5786 AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
5787 ActiveDirectoryPrimaryDomainLabelCount = 0;
5788 ActiveDirectoryPrimaryDomainServer = zeroAddr;
5789 }
5790 }
5791 #endif
5792
5793 mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
5794 {
5795 int i;
5796 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NULL
5797 domainname d;
5798
5799 CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_DynamicDNS);
5800 if (ddnsdict)
5801 {
5802 if (fqdn)
5803 {
5804 CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
5805 if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
5806 {
5807 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
5808 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
5809 if (fqdnDict && DictionaryIsEnabled(fqdnDict))
5810 {
5811 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
5812 if (name)
5813 {
5814 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5815 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
5816 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
5817 else
5818 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
5819 }
5820 }
5821 }
5822 }
5823 if (RegDomains)
5824 {
5825 CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
5826 if (regArray && CFArrayGetCount(regArray) > 0)
5827 {
5828 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
5829 if (regDict && DictionaryIsEnabled(regDict))
5830 {
5831 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
5832 if (name)
5833 {
5834 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5835 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
5836 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
5837 else
5838 {
5839 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
5840 AppendDNameListElem(&RegDomains, 0, &d);
5841 }
5842 }
5843 }
5844 }
5845 }
5846 if (BrowseDomains)
5847 {
5848 CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
5849 if (browseArray)
5850 {
5851 for (i = 0; i < CFArrayGetCount(browseArray); i++)
5852 {
5853 CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
5854 if (browseDict && DictionaryIsEnabled(browseDict))
5855 {
5856 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
5857 if (name)
5858 {
5859 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5860 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
5861 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
5862 else
5863 {
5864 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
5865 AppendDNameListElem(&BrowseDomains, 0, &d);
5866 }
5867 }
5868 }
5869 }
5870 }
5871 }
5872 CFRelease(ddnsdict);
5873 }
5874 #if MDNSRESPONDER_BTMM_SUPPORT
5875 if (RegDomains)
5876 {
5877 CFDictionaryRef btmm = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BackToMyMac);
5878 if (btmm)
5879 {
5880 CFIndex size = CFDictionaryGetCount(btmm);
5881 const void *key[size];
5882 const void *val[size];
5883 CFDictionaryGetKeysAndValues(btmm, key, val);
5884 for (i = 0; i < size; i++)
5885 {
5886 LogInfo("BackToMyMac %d", i);
5887 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
5888 LogMsg("Can't read BackToMyMac %d key %s", i, buf);
5889 else
5890 {
5891 mDNSu32 uid = atoi(buf);
5892 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
5893 LogMsg("Can't read BackToMyMac %d val %s", i, buf);
5894 else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
5895 {
5896 LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
5897 AppendDNameListElem(&RegDomains, uid, &d);
5898 }
5899 }
5900 }
5901 CFRelease(btmm);
5902 }
5903 }
5904 #endif
5905 }
5906
5907 // Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
5908 mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
5909 DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
5910 {
5911 mDNS *const m = &mDNSStorage;
5912 MD5_CTX sdc; // search domain context
5913 static mDNSu16 resolverGroupID = 0;
5914
5915 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
5916 if (fqdn ) fqdn->c[0] = 0;
5917 if (RegDomains ) *RegDomains = NULL;
5918 if (BrowseDomains) *BrowseDomains = NULL;
5919
5920 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
5921 setservers ? " setservers" : "",
5922 setsearch ? " setsearch" : "",
5923 fqdn ? " fqdn" : "",
5924 RegDomains ? " RegDomains" : "",
5925 BrowseDomains ? " BrowseDomains" : "");
5926
5927 if (setsearch) MD5_Init(&sdc);
5928
5929 // Add the inferred address-based configuration discovery domains
5930 // (should really be in core code I think, not platform-specific)
5931 if (setsearch)
5932 {
5933 struct ifaddrs *ifa = mDNSNULL;
5934 struct sockaddr_in saddr;
5935 mDNSPlatformMemZero(&saddr, sizeof(saddr));
5936 saddr.sin_len = sizeof(saddr);
5937 saddr.sin_family = AF_INET;
5938 saddr.sin_port = 0;
5939 saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
5940
5941 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
5942 if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1);
5943
5944 while (ifa)
5945 {
5946 mDNSAddr a, n;
5947 char buf[64];
5948
5949 if (ifa->ifa_addr->sa_family == AF_INET &&
5950 ifa->ifa_netmask &&
5951 !(ifa->ifa_flags & IFF_LOOPBACK) &&
5952 !SetupAddr(&a, ifa->ifa_addr) &&
5953 !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
5954 {
5955 // 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
5956 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5957 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; // Make sure ifa_netmask->sa_family is set correctly
5958 SetupAddr(&n, ifa->ifa_netmask);
5959 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
5960 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
5961 a.ip.v4.b[2] & n.ip.v4.b[2],
5962 a.ip.v4.b[1] & n.ip.v4.b[1],
5963 a.ip.v4.b[0] & n.ip.v4.b[0]);
5964 UpdateSearchDomainHash(&sdc, buf, NULL);
5965 mDNS_AddSearchDomain_CString(buf, mDNSNULL);
5966 }
5967 ifa = ifa->ifa_next;
5968 }
5969 }
5970
5971 #ifndef MDNS_NO_DNSINFO
5972 if (setservers || setsearch)
5973 {
5974 dns_config_t *config = dns_configuration_copy();
5975 if (!config)
5976 {
5977 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
5978 // Apparently this is expected behaviour -- "not a bug".
5979 // Accordingly, we suppress syslog messages for the first three minutes after boot.
5980 // If we are still getting failures after three minutes, then we log them.
5981 if ((mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
5982 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
5983 }
5984 else
5985 {
5986 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config->n_resolver, config->generation, m->p->LastConfigGeneration);
5987
5988 // For every network change, mDNSPlatformSetDNSConfig is called twice. First,
5989 // to update the search domain list (in which case, the setsearch bool is set);
5990 // and second, to update the DNS server list (in which case, the setservers bool
5991 // is set). The code assumes only one of these flags, setsearch or setserver,
5992 // will be set when mDNSPlatformSetDNSConfig is called to handle a network change.
5993 // The mDNSPlatformSetDNSConfig function also assumes that ackCfg will be set
5994 // when setservers is set.
5995
5996 // The search domains update occurs on every network change to avoid sync issues
5997 // that may occur if a network change happens during the processing
5998 // of a network change. The dns servers update occurs when the DNS config
5999 // changes. The dns servers stay in sync by saving the config's generation number
6000 // on every update; and only updating when the generation number changes.
6001
6002 // If this is a DNS server update and the configuration hasn't changed, then skip update
6003 if (setservers && m->p->LastConfigGeneration == config->generation)
6004 {
6005 LogInfo("mDNSPlatformSetDNSConfig(setservers): generation number %llu same, not processing", config->generation);
6006 dns_configuration_free(config);
6007 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6008 return mDNSfalse;
6009 }
6010 #if APPLE_OSX_mDNSResponder
6011 SetupActiveDirectoryDomain(config);
6012 #endif
6013
6014 // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry
6015 // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need
6016 // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between
6017 // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the
6018 // same resolverGroupID.
6019 //
6020 // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally.
6021 ConfigResolvers(config, kScopeNone, setsearch, setservers, &sdc, ++resolverGroupID);
6022 resolverGroupID += config->n_resolver;
6023
6024 ConfigResolvers(config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID);
6025 resolverGroupID += config->n_scoped_resolver;
6026
6027 ConfigResolvers(config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID);
6028
6029 // Acking provides a hint to other processes that the current DNS configuration has completed
6030 // its update. When configd receives the ack, it publishes a notification.
6031 // Applications monitoring the notification then know when to re-issue their DNS queries
6032 // after a network change occurs.
6033 if (ackConfig)
6034 {
6035 // Note: We have to set the generation number here when we are acking.
6036 // For every DNS configuration change, we do the following:
6037 //
6038 // 1) Copy dns configuration, handle search domains change
6039 // 2) Copy dns configuration, handle dns server change
6040 //
6041 // If we update the generation number at step (1), we won't process the
6042 // DNS servers the second time because generation number would be the same.
6043 // As we ack only when we process dns servers, we set the generation number
6044 // during acking.
6045 m->p->LastConfigGeneration = config->generation;
6046 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers, setsearch);
6047 AckConfigd(config);
6048 }
6049 dns_configuration_free(config);
6050 if (setsearch) FinalizeSearchDomainHash(&sdc);
6051 }
6052 }
6053 #endif // MDNS_NO_DNSINFO
6054 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6055 return mDNStrue;
6056 }
6057
6058
6059 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
6060 {
6061 char buf[256];
6062
6063 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_IPv4);
6064 if (dict)
6065 {
6066 r->type = mDNSAddrType_IPv4;
6067 r->ip.v4 = zerov4Addr;
6068 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
6069 if (string)
6070 {
6071 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
6072 LogMsg("Could not convert router to CString");
6073 else
6074 {
6075 struct sockaddr_in saddr;
6076 saddr.sin_len = sizeof(saddr);
6077 saddr.sin_family = AF_INET;
6078 saddr.sin_port = 0;
6079 inet_aton(buf, &saddr.sin_addr);
6080 *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
6081 }
6082 }
6083 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
6084 if (string)
6085 {
6086 mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
6087 struct ifaddrs *ifa = myGetIfAddrs(1);
6088 *v4 = *v6 = zeroAddr;
6089
6090 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
6091 {
6092 LogMsg("Could not convert router to CString");
6093 goto exit;
6094 }
6095 // find primary interface in list
6096 while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
6097 {
6098 if (!ifa->ifa_addr)
6099 {
6100 LogMsg("Skip interface, %s, since ifa_addr is not set.", (ifa->ifa_name) ? ifa->ifa_name: "name not found");
6101 ifa = ifa->ifa_next;
6102 continue;
6103 }
6104 mDNSAddr tmp6 = zeroAddr;
6105 if (!strcmp(buf, ifa->ifa_name))
6106 {
6107 if (ifa->ifa_addr->sa_family == AF_INET)
6108 {
6109 if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4))
6110 SetupAddr(v4, ifa->ifa_addr);
6111 }
6112 else if (ifa->ifa_addr->sa_family == AF_INET6)
6113 {
6114 SetupAddr(&tmp6, ifa->ifa_addr);
6115 if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
6116 {
6117 HavePrimaryGlobalv6 = mDNStrue;
6118 *v6 = tmp6;
6119 }
6120 }
6121 }
6122 else
6123 {
6124 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
6125 if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
6126 {
6127 SetupAddr(&tmp6, ifa->ifa_addr);
6128 if (tmp6.ip.v6.b[0] >> 5 == 1)
6129 *v6 = tmp6;
6130 }
6131 }
6132 ifa = ifa->ifa_next;
6133 }
6134 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
6135 // V4 to communicate w/ our DNS server
6136 }
6137
6138 exit:
6139 CFRelease(dict);
6140 }
6141 return mStatus_NoError;
6142 }
6143
6144 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
6145 {
6146 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
6147 char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6148 ConvertDomainNameToCString(dname, uname);
6149
6150 char *p = uname;
6151 while (*p)
6152 {
6153 *p = tolower(*p);
6154 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
6155 p++;
6156 }
6157
6158 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
6159 // That single entity is a CFDictionary with name "HostNames".
6160 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
6161 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
6162 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
6163 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
6164 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
6165
6166 const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
6167 const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
6168 const CFStringRef StatusKeys[1] = { CFSTR("Status") };
6169 if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
6170 else
6171 {
6172 const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
6173 if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
6174 else
6175 {
6176 const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6177 if (HostVals[0])
6178 {
6179 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6180 if (StateVals[0])
6181 {
6182 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6183 if (StateDict)
6184 {
6185 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
6186 CFRelease(StateDict);
6187 }
6188 CFRelease(StateVals[0]);
6189 }
6190 CFRelease(HostVals[0]);
6191 }
6192 CFRelease(StatusVals[0]);
6193 }
6194 CFRelease(HostKeys[0]);
6195 }
6196 }
6197
6198 #if MDNSRESPONDER_BTMM_SUPPORT
6199 #if !NO_AWACS
6200
6201 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
6202 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
6203 // help catch it
6204 mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
6205 {
6206 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
6207 if (!store)
6208 {
6209 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6210 return mDNSfalse;
6211 }
6212 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
6213 if (btmm)
6214 {
6215 CFIndex size = CFDictionaryGetCount(btmm);
6216 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6217 const void *key[size];
6218 const void *val[size];
6219 domainname dom;
6220 int i;
6221 CFDictionaryGetKeysAndValues(btmm, key, val);
6222 for (i = 0; i < size; i++)
6223 {
6224 LogInfo("BackToMyMac %d", i);
6225 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6226 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
6227 else
6228 {
6229 mDNSu32 uid = atoi(buf);
6230 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6231 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
6232 else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
6233 {
6234 if (SameDomainName(&dom, d))
6235 {
6236 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
6237 CFRelease(btmm);
6238 CFRelease(store);
6239 return mDNStrue;
6240 }
6241 }
6242 }
6243 }
6244 CFRelease(btmm);
6245 }
6246 CFRelease(store);
6247 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
6248 return mDNSfalse;
6249 }
6250
6251 // Appends data to the buffer
6252 mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
6253 {
6254 int len;
6255
6256 len = strlcpy(buf + *currlen, data, bufsz - *currlen);
6257 if (len >= (bufsz - *currlen))
6258 {
6259 // if we have exceeded the space in buf, it has already been NULL terminated
6260 // and we have nothing more to do. Set currlen to the last byte so that the caller
6261 // knows to do the right thing
6262 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
6263 *currlen = bufsz - 1;
6264 return -1;
6265 }
6266 else { (*currlen) += len; }
6267
6268 buf[*currlen] = ',';
6269 if (*currlen >= bufsz)
6270 {
6271 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
6272 *currlen = bufsz - 1;
6273 buf[*currlen] = 0;
6274 return -1;
6275 }
6276 // if we have filled up the buffer exactly, then there is no more work to do
6277 if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
6278 (*currlen)++;
6279 return *currlen;
6280 }
6281
6282 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
6283 // BTMM domains, then bring down the connection to the relay.
6284 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6285 {
6286 DomainAuthInfo *BTMMDomain = mDNSNULL;
6287 DomainAuthInfo *FoundInList;
6288 static mDNSBool AWACSDConnected = mDNSfalse;
6289 char AllUsers[1024]; // maximum size of mach message
6290 char AllPass[1024]; // maximum size of mach message
6291 char username[MAX_DOMAIN_LABEL + 1];
6292 int currulen = 0;
6293 int currplen = 0;
6294
6295 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
6296 // we may not be able to send the dns queries over the relay connection which may be needed
6297 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
6298 // need to make sure that we send the disconnect before attempting the next connect as the
6299 // awacs connections are redirected based on usernames.
6300 //
6301 // For now we send a disconnect immediately. When we start sending dns queries over the relay
6302 // connection, we will need to fix this.
6303
6304 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6305 if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
6306 {
6307 // We need the passwd from the first domain.
6308 BTMMDomain = FoundInList;
6309 ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
6310 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
6311 if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
6312 if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
6313 }
6314
6315 if (BTMMDomain)
6316 {
6317 // In the normal case (where we neither exceed the buffer size nor write bytes that
6318 // fit exactly into the buffer), currulen/currplen should be a different size than
6319 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
6320
6321 if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
6322 if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
6323
6324 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
6325 AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
6326 AWACSDConnected = mDNStrue;
6327 }
6328 else
6329 {
6330 // Disconnect only if we connected previously
6331 if (AWACSDConnected)
6332 {
6333 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
6334 AWACS_Disconnect();
6335 AWACSDConnected = mDNSfalse;
6336 }
6337 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
6338 }
6339 }
6340 #else
6341 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6342 {
6343 (void) m; // Unused
6344 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
6345 }
6346 #endif // ! NO_AWACS
6347
6348 mDNSlocal void ProcessConndConfigChanges(void);
6349
6350 #endif // MDNSRESPONDER_BTMM_SUPPORT
6351
6352 // MUST be called holding the lock
6353 mDNSlocal void SetDomainSecrets_internal(mDNS *m)
6354 {
6355 #ifdef NO_SECURITYFRAMEWORK
6356 (void) m;
6357 LogMsg("Note: SetDomainSecrets: no keychain support");
6358 #else
6359 mDNSBool haveAutoTunnels = mDNSfalse;
6360
6361 LogInfo("SetDomainSecrets");
6362
6363 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
6364 // In the case where the user simultaneously removes their DDNS host name and the key
6365 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
6366 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
6367 // address records behind that we no longer have permission to delete.
6368 DomainAuthInfo *ptr;
6369 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
6370 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
6371
6372 #if APPLE_OSX_mDNSResponder
6373 {
6374 // Mark all TunnelClients for deletion
6375 ClientTunnel *client;
6376 for (client = m->TunnelClients; client; client = client->next)
6377 {
6378 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
6379 client->MarkedForDeletion = mDNStrue;
6380 }
6381 }
6382 #endif // APPLE_OSX_mDNSResponder
6383
6384 // String Array used to write list of private domains to Dynamic Store
6385 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6386 if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
6387 CFIndex i;
6388 CFDataRef data = NULL;
6389 const int itemsPerEntry = 4; // domain name, key name, key value, Name value
6390 CFArrayRef secrets = NULL;
6391 int err = mDNSKeychainGetSecrets(&secrets);
6392 if (err || !secrets)
6393 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
6394 else
6395 {
6396 CFIndex ArrayCount = CFArrayGetCount(secrets);
6397 // Iterate through the secrets
6398 for (i = 0; i < ArrayCount; ++i)
6399 {
6400 mDNSBool AutoTunnel;
6401 int j, offset;
6402 CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
6403 if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
6404 { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i, itemsPerEntry); continue; }
6405 for (j = 0; j < CFArrayGetCount(entry); ++j)
6406 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
6407 { LogMsg("SetDomainSecrets: malformed entry item %d", j); continue; }
6408
6409 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
6410
6411 // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
6412 // Get DNS domain this key is for (kmDNSKcWhere)
6413 char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(btmmprefix)];
6414 data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere);
6415 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6416 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
6417 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6418 stringbuf[CFDataGetLength(data)] = '\0';
6419
6420 AutoTunnel = mDNSfalse;
6421 offset = 0;
6422 if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
6423 offset = strlen(dnsprefix);
6424 #if MDNSRESPONDER_BTMM_SUPPORT
6425 else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix)))
6426 {
6427 AutoTunnel = mDNStrue;
6428 offset = strlen(btmmprefix);
6429 }
6430 #endif
6431 domainname domain;
6432 if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
6433
6434 // Get key name (kmDNSKcAccount)
6435 data = CFArrayGetValueAtIndex(entry, kmDNSKcAccount);
6436 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6437 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
6438 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
6439 stringbuf[CFDataGetLength(data)] = '\0';
6440
6441 domainname keyname;
6442 if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
6443
6444 // Get key data (kmDNSKcKey)
6445 data = CFArrayGetValueAtIndex(entry, kmDNSKcKey);
6446 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6447 {
6448 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data));
6449 continue;
6450 }
6451 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6452 stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
6453
6454 // Get the Name of the keychain entry (kmDNSKcName) host or host:port
6455 // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
6456 char hostbuf[MAX_ESCAPED_DOMAIN_NAME + 6]; // Max legal domainname as C-string, including terminating NUL
6457 data = CFArrayGetValueAtIndex(entry, kmDNSKcName);
6458 if (CFDataGetLength(data) >= (int)sizeof(hostbuf))
6459 {
6460 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data));
6461 continue;
6462 }
6463 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)hostbuf);
6464 hostbuf[CFDataGetLength(data)] = '\0';
6465
6466 domainname hostname;
6467 mDNSIPPort port;
6468 char *hptr;
6469 hptr = strchr(hostbuf, ':');
6470
6471 port.NotAnInteger = 0;
6472 if (hptr)
6473 {
6474 mDNSu8 *p;
6475 mDNSu16 val = 0;
6476
6477 *hptr++ = '\0';
6478 while(hptr && *hptr != 0)
6479 {
6480 if (*hptr < '0' || *hptr > '9')
6481 { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr, val); val = 0; break;}
6482 val = val * 10 + *hptr - '0';
6483 hptr++;
6484 }
6485 if (!val) continue;
6486 p = (mDNSu8 *)&val;
6487 port.NotAnInteger = p[0] << 8 | p[1];
6488 }
6489 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
6490 hptr = strchr(hostbuf, '@');
6491 if (hptr)
6492 hptr++;
6493 else
6494 hptr = hostbuf;
6495 if (!MakeDomainNameFromDNSNameString(&hostname, hptr)) { LogMsg("SetDomainSecrets: bad host name %s", hptr); continue; }
6496
6497 DomainAuthInfo *FoundInList;
6498 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6499 if (SameDomainName(&FoundInList->domain, &domain)) break;
6500
6501 #if APPLE_OSX_mDNSResponder
6502 if (FoundInList)
6503 {
6504 // If any client tunnel destination is in this domain, set deletion flag to false
6505 ClientTunnel *client;
6506 for (client = m->TunnelClients; client; client = client->next)
6507 if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
6508 {
6509 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
6510 client->MarkedForDeletion = mDNSfalse;
6511 }
6512 }
6513
6514 #endif // APPLE_OSX_mDNSResponder
6515
6516 // Uncomment the line below to view the keys as they're read out of the system keychain
6517 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
6518 //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]));
6519 LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain.c, &keyname.c, hostname.c, (port.b[0] << 8 | port.b[1]));
6520
6521 // If didn't find desired domain in the list, make a new entry
6522 ptr = FoundInList;
6523 if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
6524 if (!FoundInList)
6525 {
6526 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
6527 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
6528 }
6529
6530 //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
6531
6532 // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
6533 if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port, AutoTunnel) == mStatus_BadParamErr)
6534 {
6535 if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
6536 continue;
6537 }
6538
6539 ConvertDomainNameToCString(&domain, stringbuf);
6540 CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
6541 if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
6542 }
6543 CFRelease(secrets);
6544 }
6545
6546 if (!privateDnsArray || !CFEqual(privateDnsArray, sa))
6547 {
6548 if (privateDnsArray)
6549 CFRelease(privateDnsArray);
6550
6551 privateDnsArray = sa;
6552 CFRetain(privateDnsArray);
6553 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
6554 }
6555 CFRelease(sa);
6556
6557 #if APPLE_OSX_mDNSResponder
6558 {
6559 // clean up ClientTunnels
6560 ClientTunnel **pp = &m->TunnelClients;
6561 while (*pp)
6562 {
6563 if ((*pp)->MarkedForDeletion)
6564 {
6565 ClientTunnel *cur = *pp;
6566 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
6567 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
6568 AutoTunnelSetKeys(cur, mDNSfalse);
6569 *pp = cur->next;
6570 freeL("ClientTunnel", cur);
6571 }
6572 else
6573 pp = &(*pp)->next;
6574 }
6575
6576 mDNSBool needAutoTunnelNAT = mDNSfalse;
6577 DomainAuthInfo *info;
6578 for (info = m->AuthInfoList; info; info = info->next)
6579 {
6580 if (info->AutoTunnel)
6581 {
6582 UpdateAutoTunnelDeviceInfoRecord(m, info);
6583 UpdateAutoTunnelHostRecord(m, info);
6584 UpdateAutoTunnelServiceRecords(m, info);
6585 UpdateAutoTunnel6Record(m, info);
6586 if (info->deltime)
6587 {
6588 if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse;
6589 }
6590 else if (info->AutoTunnelServiceStarted)
6591 needAutoTunnelNAT = true;
6592
6593 UpdateAutoTunnelDomainStatus(info);
6594 }
6595 }
6596
6597 // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
6598 if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext)
6599 {
6600 // stop the NAT operation, reset port, cleanup state
6601 mDNS_StopNATOperation_internal(m, &m->AutoTunnelNAT);
6602 m->AutoTunnelNAT.ExternalAddress = zerov4Addr;
6603 m->AutoTunnelNAT.NewAddress = zerov4Addr;
6604 m->AutoTunnelNAT.ExternalPort = zeroIPPort;
6605 m->AutoTunnelNAT.RequestedPort = zeroIPPort;
6606 m->AutoTunnelNAT.Lifetime = 0;
6607 m->AutoTunnelNAT.Result = mStatus_NoError;
6608 m->AutoTunnelNAT.clientContext = mDNSNULL;
6609 }
6610
6611 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
6612 #if MDNSRESPONDER_BTMM_SUPPORT
6613 ProcessConndConfigChanges(); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
6614 #endif
6615 }
6616 #endif // APPLE_OSX_mDNSResponder
6617
6618 CheckSuppressUnusableQuestions(m);
6619
6620 #endif /* NO_SECURITYFRAMEWORK */
6621 }
6622
6623 mDNSexport void SetDomainSecrets(mDNS *m)
6624 {
6625 #if DEBUG
6626 // Don't get secrets for BTMM if running in debug mode
6627 if (!IsDebugSocketInUse())
6628 #endif
6629 SetDomainSecrets_internal(m);
6630 }
6631
6632 mDNSlocal void SetLocalDomains(void)
6633 {
6634 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6635 if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
6636
6637 CFArrayAppendValue(sa, CFSTR("local"));
6638 CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
6639 CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
6640 CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
6641 CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
6642 CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
6643
6644 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
6645 CFRelease(sa);
6646 }
6647
6648 mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
6649 {
6650
6651 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_PowerSettings);
6652 if (!dict)
6653 {
6654 LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
6655 }
6656 else
6657 {
6658 CFNumberRef number = CFDictionaryGetValue(dict, name);
6659 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
6660 *val = 0;
6661 CFRelease(dict);
6662 }
6663
6664 }
6665
6666 #if APPLE_OSX_mDNSResponder
6667
6668 static CFMutableDictionaryRef spsStatusDict = NULL;
6669 static const CFStringRef kMetricRef = CFSTR("Metric");
6670
6671 mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
6672 {
6673 mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
6674 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
6675 if (!num)
6676 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
6677 else
6678 {
6679 CFDictionarySetValue(dict, key, num);
6680 CFRelease(num);
6681 }
6682 }
6683
6684 mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
6685 {
6686 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6687 if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
6688
6689 char buffer[1024];
6690 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
6691 CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
6692 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
6693 CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
6694 CFRelease(spsname);
6695
6696 if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
6697 if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
6698 if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
6699 if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
6700
6701 mDNSu32 tmp = SPSMetric(ptr);
6702 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
6703 if (!num)
6704 LogMsg("SPSCreateDict: Could not create CFNumber");
6705 else
6706 {
6707 CFDictionarySetValue(dict, kMetricRef, num);
6708 CFRelease(num);
6709 }
6710
6711 if (ptr[0] >= 12)
6712 {
6713 memcpy(buffer, ptr + 13, ptr[0] - 12);
6714 buffer[ptr[0] - 12] = 0;
6715 spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
6716 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
6717 else
6718 {
6719 CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
6720 CFRelease(spsname);
6721 }
6722 }
6723
6724 return dict;
6725 }
6726
6727 mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
6728 {
6729 (void)context;
6730 return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
6731 (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
6732 NULL);
6733 }
6734
6735 mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
6736 {
6737 NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
6738 debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
6739
6740 mDNS_Lock(m);
6741 mDNS_UpdateAllowSleep(m);
6742 mDNS_Unlock(m);
6743
6744 if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names
6745
6746 if (!spsStatusDict)
6747 {
6748 spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6749 if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
6750 }
6751
6752 CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
6753 if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
6754
6755 CFMutableArrayRef array = NULL;
6756
6757 if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
6758 {
6759 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6760 if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
6761 CFDictionarySetValue(spsStatusDict, ifname, array);
6762 CFRelease(array); // let go of our reference, now that the dict has one
6763 }
6764 else
6765 if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
6766
6767 if (!answer) // special call that means the question has been stopped (because the interface is going away)
6768 CFArrayRemoveAllValues(array);
6769 else
6770 {
6771 CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
6772 if (!dict) { CFRelease(ifname); return; }
6773
6774 if (AddRecord)
6775 {
6776 if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
6777 {
6778 int i=0;
6779 for (i=0; i<CFArrayGetCount(array); i++)
6780 if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
6781 break;
6782 CFArrayInsertValueAtIndex(array, i, dict);
6783 }
6784 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
6785 }
6786 else
6787 {
6788 CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
6789 if (i != -1) CFArrayRemoveValueAtIndex(array, i);
6790 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
6791 }
6792
6793 CFRelease(dict);
6794 }
6795
6796 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
6797
6798 CFRelease(ifname);
6799 }
6800
6801 mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
6802 {
6803 mDNSs32 val = -1;
6804 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
6805 if (!store)
6806 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6807 else
6808 {
6809 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
6810 if (dict)
6811 {
6812 CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
6813 if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
6814 CFRelease(dict);
6815 }
6816 CFRelease(store);
6817 }
6818 return val;
6819 }
6820
6821 mDNSlocal void SetSPS(mDNS *const m)
6822 {
6823
6824 // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
6825 mDNSu8 sps = (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware : 0;
6826
6827 // For devices that are not running NAT, but are set to never sleep, we may choose to act
6828 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
6829 //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
6830
6831 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
6832
6833 // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
6834 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
6835 // We rate such a device as metric 70 ("Incidentally Available Hardware")
6836 if (SPMetricMarginalPower <= 60 && !sps) sps = mDNSSleepProxyMetric_IncidentalHardware;
6837
6838 // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
6839 // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
6840 if (sps && OfferSleepProxyService && OfferSleepProxyService < 100) sps = OfferSleepProxyService;
6841
6842 #ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI
6843 // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active.
6844 if (IsAppleTV())
6845 {
6846 NetworkInterfaceInfo *intf = mDNSNULL;
6847 mDNSEthAddr bssid = zeroEthAddr;
6848 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
6849 {
6850 if (intf->InterfaceID == AWDLInterfaceID) continue;
6851 bssid = GetBSSID(intf->ifname);
6852 if (!mDNSSameEthAddress(&bssid, &zeroEthAddr))
6853 {
6854 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
6855 sps = 0;
6856 break;
6857 }
6858 }
6859 }
6860 #endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI
6861
6862 mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
6863 }
6864
6865 // The definitions below should eventually come from some externally-supplied header file.
6866 // However, since these definitions can't really be changed without breaking binary compatibility,
6867 // they should never change, so in practice it should not be a big problem to have them defined here.
6868
6869 enum
6870 { // commands from the daemon to the driver
6871 cmd_mDNSOffloadRR = 21, // give the mdns update buffer to the driver
6872 };
6873
6874 typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr;
6875
6876 typedef struct
6877 { // cmd_mDNSOffloadRR structure
6878 uint32_t command; // set to OffloadRR
6879 uint32_t rrBufferSize; // number of bytes of RR records
6880 uint32_t numUDPPorts; // number of SRV UDP ports
6881 uint32_t numTCPPorts; // number of SRV TCP ports
6882 uint32_t numRRRecords; // number of RR records
6883 uint32_t compression; // rrRecords - compression is base for compressed strings
6884 FatPtr rrRecords; // address of array of pointers to the rr records
6885 FatPtr udpPorts; // address of udp port list (SRV)
6886 FatPtr tcpPorts; // address of tcp port list (SRV)
6887 } mDNSOffloadCmd;
6888
6889 #include <IOKit/IOKitLib.h>
6890 #include <dns_util.h>
6891
6892 mDNSlocal mDNSu32 GetPortArray(int trans, mDNSIPPort *portarray)
6893 {
6894 mDNS *const m = &mDNSStorage;
6895 const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
6896 mDNSu32 count = 0;
6897
6898 AuthRecord *rr;
6899 for (rr = m->ResourceRecords; rr; rr=rr->next)
6900 {
6901 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c))
6902 {
6903 if (!portarray)
6904 count++;
6905 else
6906 {
6907 mDNSu32 i;
6908 for (i = 0; i < count; i++)
6909 if (mDNSSameIPPort(portarray[i], rr->resrec.rdata->u.srv.port))
6910 break;
6911
6912 // Add it into the port list only if it not already present in the list
6913 if (i >= count)
6914 portarray[count++] = rr->resrec.rdata->u.srv.port;
6915 }
6916 }
6917 }
6918
6919 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
6920 if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext)
6921 {
6922 LogSPS("GetPortArray Back to My Mac at %u", count);
6923 if (portarray) portarray[count] = IPSECPort;
6924 count++;
6925 }
6926 return(count);
6927 }
6928
6929 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6930 mDNSlocal mDNSBool SupportsTCPKeepAlive()
6931 {
6932 IOReturn ret = kIOReturnSuccess;
6933 CFTypeRef obj = NULL;
6934 mDNSBool supports = mDNSfalse;
6935
6936 ret = IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj);
6937 if ((kIOReturnSuccess == ret) && (obj != NULL))
6938 {
6939 supports = (obj == kCFBooleanTrue)? mDNStrue : mDNSfalse;
6940 CFRelease(obj);
6941 }
6942 LogSPS("%s: The hardware %s TCP Keep Alive", __func__, (supports ? "supports" : "does not support"));
6943 return supports;
6944 }
6945
6946 mDNSlocal mDNSBool OnBattery(void)
6947 {
6948 CFTypeRef powerInfo = IOPSCopyPowerSourcesInfo();
6949 CFTypeRef powerSrc = IOPSGetProvidingPowerSourceType(powerInfo);
6950 mDNSBool result = mDNSfalse;
6951
6952 if (powerInfo != NULL)
6953 {
6954 result = CFEqual(CFSTR(kIOPSBatteryPowerValue), powerSrc);
6955 CFRelease(powerInfo);
6956 }
6957 LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
6958 return result;
6959 }
6960
6961 #endif // !TARGET_OS_EMBEDDED
6962
6963 #define TfrRecordToNIC(RR) \
6964 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
6965
6966 mDNSlocal mDNSu32 CountProxyRecords(uint32_t *const numbytes, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
6967 {
6968 mDNS *const m = &mDNSStorage;
6969 *numbytes = 0;
6970 uint32_t count = 0;
6971 mDNSBool isKeepAliveRecord = mDNSfalse;
6972
6973 AuthRecord *rr;
6974
6975 for (rr = m->ResourceRecords; rr; rr=rr->next)
6976 {
6977 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
6978 {
6979 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6980 isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
6981 // Skip over all other records if we are registering TCP KeepAlive records only
6982 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
6983 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
6984 continue;
6985 #else
6986 (void) TCPKAOnly; // unused
6987 (void) supportsTCPKA; // unused
6988 #endif
6989 if (TfrRecordToNIC(rr))
6990 {
6991 // For KeepAlive records, use an estimated length of 256, which is the maximum size.
6992 const uint32_t rdataLen = isKeepAliveRecord ? ((uint32_t)sizeof(UTF8str255)) : rr->resrec.rdestimate;
6993 const uint32_t recordSize = DomainNameLength(rr->resrec.name) + 10 + rdataLen;
6994 *numbytes += recordSize;
6995 LogSPS("CountProxyRecords: %3u size %5u total %5u %s", count, recordSize, *numbytes, ARDisplayString(m,rr));
6996 count++;
6997 }
6998 }
6999 }
7000 return(count);
7001 }
7002
7003 mDNSlocal void GetProxyRecords(DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records,
7004 uint32_t *outRecordCount, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
7005 {
7006 mDNS *const m = &mDNSStorage;
7007 mDNSu8 *p = msg->data;
7008 const mDNSu8 *const limit = p + *numbytes;
7009 InitializeDNSMessage(&msg->h, zeroID, zeroID);
7010
7011 uint32_t count = 0;
7012 AuthRecord *rr;
7013
7014 for (rr = m->ResourceRecords; rr; rr=rr->next)
7015 {
7016 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
7017 {
7018 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7019 const mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
7020
7021 // Skip over all other records if we are registering TCP KeepAlive records only
7022 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
7023 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
7024 continue;
7025
7026 // Update the record before calculating the number of bytes required
7027 // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
7028 // attempt to update the record again.
7029 if (isKeepAliveRecord)
7030 {
7031 if (UpdateKeepaliveRData(m, rr, intf, mDNSfalse, mDNSNULL) != mStatus_NoError)
7032 {
7033 LogSPS("GetProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m, rr));
7034 continue;
7035 }
7036 // Offload only Valid Keepalive records
7037 if (!mDNSValidKeepAliveRecord(rr))
7038 {
7039 continue;
7040 }
7041 }
7042 #else
7043 (void) intf; // unused
7044 (void) TCPKAOnly; // unused
7045 (void) supportsTCPKA; // unused
7046 #endif // APPLE_OSX_mDNSResponder
7047
7048 if (TfrRecordToNIC(rr))
7049 {
7050 records[count].sixtyfourbits = zeroOpaque64;
7051 records[count].ptr = p;
7052 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
7053 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it
7054 p = PutResourceRecordTTLWithLimit(msg, p, &msg->h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
7055 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state
7056 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
7057 count, records[count].ptr, p, p - (mDNSu8 *)records[count].ptr, p - msg->data, ARDisplayString(m,rr));
7058 count++;
7059 }
7060 }
7061 }
7062 *numbytes = p - msg->data;
7063 if (outRecordCount) *outRecordCount = count;
7064 }
7065
7066 mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf)
7067 {
7068 if(!UseInternalSleepProxy)
7069 {
7070 LogMsg("SupportsInNICProxy: Internal Sleep Proxy is disabled");
7071 return mDNSfalse;
7072 }
7073 return CheckInterfaceSupport(intf, mDNS_IOREG_KEY);
7074 }
7075
7076 // Called with the lock held
7077 mDNSexport mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool offloadKeepAlivesOnly, mDNSBool *keepaliveOnly)
7078 {
7079 mStatus result = mStatus_UnknownErr;
7080 mDNSBool TCPKAOnly = mDNSfalse;
7081 mDNSBool supportsTCPKA = mDNSfalse;
7082 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
7083
7084 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7085 // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
7086 supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive()) ? mDNStrue : mDNSfalse;
7087 if (!offloadKeepAlivesOnly)
7088 {
7089 // Only TCP Keepalive records are to be offloaded if
7090 // - The system is on battery
7091 // - OR wake for network access is not set but powernap is enabled
7092 TCPKAOnly = supportsTCPKA && ((mDNSStorage.SystemWakeOnLANEnabled == mDNS_WakeOnBattery) || OnBattery());
7093 }
7094 else
7095 {
7096 TCPKAOnly = mDNStrue;
7097 }
7098 #else
7099 (void)offloadKeepAlivesOnly; // Unused.
7100 #endif
7101 if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", intf->ifname); return(mStatus_UnknownErr); }
7102
7103 io_name_t n1, n2;
7104 IOObjectGetClass(service, n1);
7105
7106 CFTypeRef ref;
7107 io_object_t parent;
7108 kern_return_t kr = RegistryEntrySearchCFPropertyAndIOObject(service, kIOServicePlane, CFSTR(mDNS_IOREG_KEY), &ref, &parent);
7109 IOObjectRelease(service);
7110 if (kr != KERN_SUCCESS) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s kr %d", intf->ifname, n1, kr);
7111 else
7112 {
7113 IOObjectGetClass(parent, n2);
7114 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf->ifname, n1, n2);
7115
7116 if (CFGetTypeID(ref) != CFStringGetTypeID() || !CFEqual(ref, CFSTR(mDNS_IOREG_VALUE)))
7117 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
7118 intf->ifname, n1, n2, CFStringGetCStringPtr(ref, mDNSNULL), mDNS_IOREG_VALUE);
7119 else if (!UseInternalSleepProxy)
7120 LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf->ifname);
7121 else
7122 {
7123 io_connect_t conObj;
7124 kr = IOServiceOpen(parent, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE, &conObj);
7125 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf->ifname, n1, n2, kr);
7126 else
7127 {
7128 mDNSOffloadCmd cmd;
7129 mDNSPlatformMemZero(&cmd, sizeof(cmd)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
7130 cmd.command = cmd_mDNSOffloadRR;
7131 cmd.numUDPPorts = TCPKAOnly ? 0 : GetPortArray(mDNSTransport_UDP, mDNSNULL);
7132 cmd.numTCPPorts = TCPKAOnly ? 0 : GetPortArray(mDNSTransport_TCP, mDNSNULL);
7133 cmd.numRRRecords = CountProxyRecords(&cmd.rrBufferSize, TCPKAOnly, supportsTCPKA);
7134 cmd.compression = sizeof(DNSMessageHeader);
7135
7136 DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
7137 cmd.rrRecords.ptr = cmd.numRRRecords ? mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr)) : NULL;
7138 cmd.udpPorts.ptr = cmd.numUDPPorts ? mallocL("mDNSOffloadCmd udpPorts" , cmd.numUDPPorts * sizeof(mDNSIPPort)) : NULL;
7139 cmd.tcpPorts.ptr = cmd.numTCPPorts ? mallocL("mDNSOffloadCmd tcpPorts" , cmd.numTCPPorts * sizeof(mDNSIPPort)) : NULL;
7140
7141 LogSPS("ActivateLocalProxy: msg %p %u RR %p %u, UDP %p %u, TCP %p %u",
7142 msg, cmd.rrBufferSize,
7143 cmd.rrRecords.ptr, cmd.numRRRecords,
7144 cmd.udpPorts.ptr, cmd.numUDPPorts,
7145 cmd.tcpPorts.ptr, cmd.numTCPPorts);
7146
7147 if (msg && cmd.rrRecords.ptr)
7148 {
7149 GetProxyRecords(msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, &cmd.numRRRecords, intf, TCPKAOnly, supportsTCPKA);
7150 }
7151 if (cmd.udpPorts.ptr) cmd.numUDPPorts = TCPKAOnly ? 0 : GetPortArray(mDNSTransport_UDP, cmd.udpPorts.ptr);
7152 if (cmd.tcpPorts.ptr) cmd.numTCPPorts = TCPKAOnly ? 0 : GetPortArray(mDNSTransport_TCP, cmd.tcpPorts.ptr);
7153
7154 char outputData[2];
7155 size_t outputDataSize = sizeof(outputData);
7156 kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize);
7157 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr);
7158 if (kr == KERN_SUCCESS) result = mStatus_NoError;
7159
7160 if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts.ptr);
7161 if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts.ptr);
7162 if (cmd.rrRecords.ptr) freeL("mDNSOffloadCmd rrRecords", cmd.rrRecords.ptr);
7163 if (msg) freeL("mDNSOffloadCmd msg", msg);
7164 IOServiceClose(conObj);
7165 }
7166 }
7167 CFRelease(ref);
7168 IOObjectRelease(parent);
7169 }
7170 *keepaliveOnly = (TCPKAOnly && supportsTCPKA) ? mDNStrue : mDNSfalse;
7171 return result;
7172 }
7173
7174 #endif // APPLE_OSX_mDNSResponder
7175
7176 mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
7177 {
7178 mDNSs32 val = 0;
7179 mDNSu8 ret = (mDNSu8)mDNS_NoWake;
7180
7181 #if TARGET_OS_IOS
7182 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7183 return ret;
7184 #endif
7185
7186 if (DisableSleepProxyClient)
7187 {
7188 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7189 return ret;
7190 }
7191
7192 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
7193
7194 ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
7195
7196 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7197 // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
7198 // Further policy decisions on whether to offload the records is handled during sleep processing.
7199 if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive())
7200 ret = (mDNSu8)mDNS_WakeOnBattery;
7201 #endif // APPLE_OSX_mDNSResponder
7202
7203 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret);
7204 return ret;
7205 }
7206
7207 mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
7208 {
7209 mDNSs32 val = 0;
7210 // PrioritizeNetworkReachabilityOverSleep has been deprecated.
7211 // GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
7212 // Statically set the PrioritizeNetworkReachabilityOverSleep value to 1 for AppleTV
7213 if (IsAppleTV())
7214 val = 1;
7215 return val != 0 ? mDNStrue : mDNSfalse;
7216 }
7217
7218
7219 #if APPLE_OSX_mDNSResponder
7220 // When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
7221 // gets deregistered, so that older peers are forced to connect over direct UDP instead of
7222 // the RR relay.
7223 //
7224 // When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
7225 // service records are deregistered, so they do not appear in peers' Finder sidebars.
7226 // We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
7227 // depend on their associated SRV record and therefore will be deregistered together in a
7228 // single update with the SRV record.
7229 //
7230 // Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
7231 // its presence shouldn't delay sleep.
7232 //
7233 // Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
7234 // relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
7235 //
7236 // Also note that returning false here will not delay sleep past the maximum of 10 seconds.
7237 mDNSexport mDNSBool RecordReadyForSleep(AuthRecord *rr)
7238 {
7239 mDNS *const m = &mDNSStorage;
7240 if (!AuthRecord_uDNS(rr)) return mDNStrue;
7241
7242 if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
7243 {
7244 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7245 return mDNSfalse;
7246 }
7247
7248 if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result))
7249 {
7250 if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone
7251 && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel"))
7252 {
7253 DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
7254 if (info && info->AutoTunnel)
7255 {
7256 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7257 return mDNSfalse;
7258 }
7259 }
7260 }
7261
7262 return mDNStrue;
7263 }
7264
7265 // Caller must hold the lock
7266 mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
7267 {
7268 DomainAuthInfo *info;
7269 // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
7270 // deregister the record, and the MemFree callback won't re-register.
7271 m->AutoTunnelRelayAddr = zerov6Addr;
7272 for (info = m->AuthInfoList; info; info = info->next)
7273 if (info->AutoTunnel)
7274 UpdateAutoTunnel6Record(m, info);
7275 }
7276 #endif /* APPLE_OSX_mDNSResponder */
7277
7278 #if MDNSRESPONDER_BTMM_SUPPORT
7279 mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname)
7280 {
7281 struct ifaddrs *ifa;
7282 struct ifaddrs *ifaddrs;
7283 mDNSAddr addr;
7284
7285 if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;}
7286
7287 if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;}
7288
7289 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
7290 {
7291 if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
7292 continue;
7293 if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
7294 continue;
7295 if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
7296 {
7297 LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
7298 continue;
7299 }
7300 if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6))
7301 {
7302 LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr);
7303 break;
7304 }
7305 }
7306 freeifaddrs(ifaddrs);
7307 return ifa != NULL;
7308 }
7309
7310 mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf)
7311 {
7312 mDNSv6Addr retVal;
7313 struct addrinfo hints;
7314 struct addrinfo *res0;
7315
7316 memset(&hints, 0, sizeof(hints));
7317 hints.ai_family = AF_INET6;
7318 hints.ai_flags = AI_NUMERICHOST;
7319
7320 int err = getaddrinfo(buf, NULL, &hints, &res0);
7321 if (err)
7322 return zerov6Addr;
7323
7324 retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr;
7325
7326 freeaddrinfo(res0);
7327
7328 return retVal;
7329 }
7330
7331 mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict()
7332 {
7333 CFDictionaryRef connd = NULL;
7334 CFDictionaryRef BTMMDict = NULL;
7335
7336 connd = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BTMMConnectivity);
7337 if (!connd)
7338 {
7339 LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
7340 goto end;
7341 }
7342
7343 BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
7344 if (!BTMMDict)
7345 {
7346 LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
7347 goto end;
7348 }
7349
7350 // Non-dictionary is treated as non-existent dictionary
7351 if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
7352 {
7353 BTMMDict = NULL;
7354 LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
7355 goto end;
7356 }
7357
7358 CFRetain(BTMMDict);
7359
7360 end:
7361 if (connd) CFRelease(connd);
7362
7363 return BTMMDict;
7364 }
7365
7366 #define MAX_IPV6_TEXTUAL 40
7367
7368 mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey)
7369 {
7370 mDNSv6Addr retVal = zerov6Addr;
7371 CFTypeRef string = NULL;
7372 char ifname[IFNAMSIZ];
7373 char address[MAX_IPV6_TEXTUAL];
7374
7375 if (!BTMMDict)
7376 return zerov6Addr;
7377
7378 if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string))
7379 {
7380 LogInfo("ParseBackToMyMacAddr: interface key does not exist");
7381 return zerov6Addr;
7382 }
7383
7384 if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8))
7385 {
7386 LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
7387 return zerov6Addr;
7388 }
7389
7390 if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string))
7391 {
7392 LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
7393 return zerov6Addr;
7394 }
7395
7396 if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8))
7397 {
7398 LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
7399 return zerov6Addr;
7400 }
7401
7402 retVal = IPv6AddressFromString(address);
7403 LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal);
7404
7405 if (mDNSIPv6AddressIsZero(retVal))
7406 return zerov6Addr;
7407
7408 if (!IPv6AddressIsOnInterface(retVal, ifname))
7409 {
7410 LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname);
7411 return zerov6Addr;
7412 }
7413
7414 return retVal;
7415 }
7416
7417 mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict)
7418 {
7419 CFTypeRef zones = NULL;
7420
7421 if (!BTMMDict)
7422 return NULL;
7423
7424 if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones))
7425 {
7426 LogInfo("CopyBTMMZones: Zones key does not exist");
7427 return NULL;
7428 }
7429
7430 return zones;
7431 }
7432
7433 mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info)
7434 {
7435 mDNSv6Addr addr = zerov6Addr;
7436 char buffer[MAX_ESCAPED_DOMAIN_NAME];
7437 CFStringRef domain = NULL;
7438 CFTypeRef theZone = NULL;
7439
7440 if (!zones)
7441 return addr;
7442
7443 ConvertDomainNameToCString(&info->domain, buffer);
7444 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
7445 if (!domain)
7446 return addr;
7447
7448 if (CFDictionaryGetValueIfPresent(zones, domain, &theZone))
7449 addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address"));
7450
7451 CFRelease(domain);
7452
7453 return addr;
7454 }
7455
7456 mDNSlocal void SetupBackToMyMacInnerAddresses(CFDictionaryRef BTMMDict)
7457 {
7458 mDNS *const m = &mDNSStorage;
7459 DomainAuthInfo* info;
7460 CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
7461 mDNSv6Addr newAddr;
7462
7463 for (info = m->AuthInfoList; info; info = info->next)
7464 {
7465 if (!info->AutoTunnel)
7466 continue;
7467
7468 newAddr = ParseBackToMyMacZone(zones, info);
7469
7470 if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress))
7471 continue;
7472
7473 info->AutoTunnelInnerAddress = newAddr;
7474 DeregisterAutoTunnelHostRecord(m, info);
7475 UpdateAutoTunnelHostRecord(m, info);
7476 UpdateAutoTunnelDomainStatus(info);
7477 }
7478 }
7479
7480 // MUST be called holding the lock
7481 mDNSlocal void ProcessConndConfigChanges(void)
7482 {
7483 mDNS *const m = &mDNSStorage;
7484 CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
7485 if (!dict)
7486 LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
7487 mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
7488
7489 LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
7490
7491 SetupBackToMyMacInnerAddresses(dict);
7492
7493 if (dict) CFRelease(dict);
7494
7495 if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr))
7496 {
7497 m->AutoTunnelRelayAddr = relayAddr;
7498
7499 DomainAuthInfo* info;
7500 for (info = m->AuthInfoList; info; info = info->next)
7501 if (info->AutoTunnel)
7502 {
7503 DeregisterAutoTunnel6Record(m, info);
7504 UpdateAutoTunnel6Record(m, info);
7505 UpdateAutoTunnelDomainStatus(info);
7506 }
7507
7508 // Determine whether we need racoon to accept incoming connections
7509 UpdateAnonymousRacoonConfig(m);
7510 }
7511
7512 // If awacsd crashes or exits for some reason, restart it
7513 UpdateBTMMRelayConnection(m);
7514 }
7515 #endif // MDNSRESPONDER_BTMM_SUPPORT
7516
7517 mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
7518 {
7519 DNSServer *s;
7520 // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
7521 for (s = m->DNSServers; s; s = s->next)
7522 {
7523 if (s->addr.ip.v4.b[0] == 17)
7524 {
7525 LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s->domain.c, &s->addr);
7526 return mDNStrue;
7527 }
7528 }
7529 return mDNSfalse;
7530 }
7531
7532 // Called with KQueueLock & mDNS lock
7533 // SetNetworkChanged is allowed to shorten (but not extend) the pause while we wait for configuration changes to settle
7534 mDNSlocal void SetNetworkChanged(mDNSs32 delay)
7535 {
7536 mDNS *const m = &mDNSStorage;
7537 mDNS_CheckLock(m);
7538 if (!m->NetworkChanged || m->NetworkChanged - NonZeroTime(m->timenow + delay) > 0)
7539 {
7540 m->NetworkChanged = NonZeroTime(m->timenow + delay);
7541 LogInfo("SetNetworkChanged: Scheduling in %d ticks", delay);
7542 }
7543 else
7544 LogInfo("SetNetworkChanged: *NOT* increasing delay from %d to %d", m->NetworkChanged - m->timenow, delay);
7545 }
7546
7547 // Called with KQueueLock & mDNS lock
7548 mDNSlocal void SetKeyChainTimer(mDNSs32 delay)
7549 {
7550 mDNS *const m = &mDNSStorage;
7551 // If it's not set or it needs to happen sooner than when it's currently set
7552 if (!m->p->KeyChainTimer || m->p->KeyChainTimer - NonZeroTime(m->timenow + delay) > 0)
7553 {
7554 m->p->KeyChainTimer = NonZeroTime(m->timenow + delay);
7555 LogInfo("SetKeyChainTimer: %d", delay);
7556 }
7557 }
7558
7559 mDNSexport void mDNSMacOSXNetworkChanged(void)
7560 {
7561 mDNS *const m = &mDNSStorage;
7562 LogInfo("*** Network Configuration Change *** %d ticks late%s",
7563 m->NetworkChanged ? mDNS_TimeNow(m) - m->NetworkChanged : 0,
7564 m->NetworkChanged ? "" : " (no scheduled configuration change)");
7565 m->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
7566
7567 // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring
7568 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
7569 if (InfoSocket > 0)
7570 {
7571 mDNSBool tentative = mDNSfalse;
7572 struct ifaddrs *ifa = myGetIfAddrs(1);
7573 while (ifa)
7574 {
7575 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6)
7576 {
7577 struct in6_ifreq ifr6;
7578 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
7579 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
7580 ifr6.ifr_addr = *(struct sockaddr_in6 *)ifa->ifa_addr;
7581 // We need to check for IN6_IFF_TENTATIVE here, not IN6_IFF_NOTREADY, because
7582 // IN6_IFF_NOTREADY includes both IN6_IFF_TENTATIVE and IN6_IFF_DUPLICATED addresses.
7583 // We can expect that an IN6_IFF_TENTATIVE address will shortly become ready,
7584 // but an IN6_IFF_DUPLICATED address may not.
7585 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
7586 {
7587 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
7588 {
7589 LogInfo("*** Network Configuration Change *** IPv6 address %.16a TENTATIVE, will retry", &ifr6.ifr_addr.sin6_addr);
7590 tentative = mDNStrue;
7591 // no need to check other interfaces if we already found out that one interface is TENTATIVE
7592 break;
7593 }
7594 }
7595 }
7596 ifa = ifa->ifa_next;
7597 }
7598 close(InfoSocket);
7599 if (tentative)
7600 {
7601 mDNS_Lock(m);
7602 SetNetworkChanged(mDNSPlatformOneSecond / 2);
7603 mDNS_Unlock(m);
7604 return;
7605 }
7606 LogInfo("*** Network Configuration Change *** No IPv6 address TENTATIVE, will continue");
7607 }
7608
7609 mDNSs32 utc = mDNSPlatformUTC();
7610 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
7611 m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
7612 MarkAllInterfacesInactive(utc);
7613 UpdateInterfaceList(utc);
7614 ClearInactiveInterfaces(utc);
7615 SetupActiveInterfaces(utc);
7616 ReorderInterfaceList();
7617
7618 #if APPLE_OSX_mDNSResponder
7619 #if !TARGET_OS_EMBEDDED
7620 #if MDNSRESPONDER_BTMM_SUPPORT
7621 mDNS_Lock(m);
7622 ProcessConndConfigChanges();
7623 mDNS_Unlock(m);
7624 #endif
7625
7626 // Scan to find client tunnels whose questions have completed,
7627 // but whose local inner/outer addresses have changed since the tunnel was set up
7628 ClientTunnel *p;
7629 for (p = m->TunnelClients; p; p = p->next)
7630 if (p->q.ThisQInterval < 0)
7631 {
7632 DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname);
7633 if (!info)
7634 {
7635 LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c);
7636 AutoTunnelSetKeys(p, mDNSfalse);
7637 }
7638 else
7639 {
7640 mDNSv6Addr inner = info->AutoTunnelInnerAddress;
7641
7642 if (!mDNSIPPortIsZero(p->rmt_outer_port))
7643 {
7644 mDNSAddr tmpSrc = zeroAddr;
7645 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
7646 tmpDst.ip.v4 = p->rmt_outer;
7647 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
7648 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7649 !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
7650 {
7651 AutoTunnelSetKeys(p, mDNSfalse);
7652 p->loc_inner = inner;
7653 p->loc_outer = tmpSrc.ip.v4;
7654 AutoTunnelSetKeys(p, mDNStrue);
7655 }
7656 }
7657 else
7658 {
7659 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7660 !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
7661 {
7662 AutoTunnelSetKeys(p, mDNSfalse);
7663 p->loc_inner = inner;
7664 p->loc_outer6 = m->AutoTunnelRelayAddr;
7665 AutoTunnelSetKeys(p, mDNStrue);
7666 }
7667 }
7668 }
7669 }
7670 #endif //!TARGET_OS_EMBEDDED
7671
7672 SetSPS(m);
7673
7674 NetworkInterfaceInfoOSX *i;
7675 for (i = m->p->InterfaceList; i; i = i->next)
7676 {
7677 if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
7678 {
7679 if (i->BPF_fd >= 0 && CountProxyTargets(i, mDNSNULL, mDNSNULL) == 0)
7680 CloseBPF(i);
7681 }
7682 else // else, we're Sleep Proxy Server; open BPF fds
7683 {
7684 if (i->Exists && (i->Registered == i) && SPSInterface(i) && i->BPF_fd == -1)
7685 {
7686 LogMsg("%s mDNSMacOSXNetworkChanged: requesting BPF", i->ifinfo.ifname);
7687 i->BPF_fd = -2;
7688 mDNSRequestBPF();
7689 }
7690 }
7691 }
7692
7693 #endif // APPLE_OSX_mDNSResponder
7694
7695 uDNS_SetupDNSConfig(m);
7696 mDNS_ConfigChanged(m);
7697
7698 if (IsAppleNetwork(m) != mDNS_McastTracingEnabled)
7699 {
7700 mDNS_McastTracingEnabled = mDNS_McastTracingEnabled ? mDNSfalse : mDNStrue;
7701 LogInfo("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
7702 UpdateDebugState();
7703 }
7704
7705 }
7706
7707 // Copy the fourth slash-delimited element from either:
7708 // State:/Network/Interface/<bsdname>/IPv4
7709 // or
7710 // Setup:/Network/Service/<servicename>/Interface
7711 mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
7712 {
7713 CFArrayRef a;
7714 CFStringRef name = NULL;
7715
7716 a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
7717 if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
7718 if (a != NULL) CFRelease(a);
7719
7720 return name;
7721 }
7722
7723 // Whether a key from a network change notification corresponds to
7724 // an IP service that is explicitly configured for IPv4 Link Local
7725 mDNSlocal int ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
7726 {
7727 CFDictionaryRef dict = NULL;
7728 CFMutableArrayRef a;
7729 const void **keys = NULL, **vals = NULL;
7730 CFStringRef pattern = NULL;
7731 int i, ic, j, jc;
7732 int found = 0;
7733
7734 jc = CFArrayGetCount(inkeys);
7735 if (!jc) goto done;
7736
7737 a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7738 if (a == NULL) goto done;
7739
7740 // Setup:/Network/Service/[^/]+/Interface
7741 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
7742 if (pattern == NULL) goto done;
7743 CFArrayAppendValue(a, pattern);
7744 CFRelease(pattern);
7745
7746 // Setup:/Network/Service/[^/]+/IPv4
7747 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
7748 if (pattern == NULL) goto done;
7749 CFArrayAppendValue(a, pattern);
7750 CFRelease(pattern);
7751
7752 dict = SCDynamicStoreCopyMultiple(NULL, NULL, a);
7753 CFRelease(a);
7754
7755 if (!dict)
7756 {
7757 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
7758 goto done;
7759 }
7760
7761 ic = CFDictionaryGetCount(dict);
7762 vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7763 keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7764 CFDictionaryGetKeysAndValues(dict, keys, vals);
7765
7766 // For each key we were given...
7767 for (j = 0; j < jc; j++)
7768 {
7769 CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
7770 CFStringRef ifname = NULL;
7771
7772 char buf[256];
7773
7774 // It would be nice to use a regex here
7775 if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
7776
7777 if ((ifname = CopyNameFromKey(key)) == NULL) continue;
7778 if (mDNS_LoggingEnabled)
7779 {
7780 if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7781 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
7782 }
7783
7784 // Loop over the interfaces to find matching the ifname, and see if that one has kSCValNetIPv4ConfigMethodLinkLocal
7785 for (i = 0; i < ic; i++)
7786 {
7787 CFDictionaryRef ipv4dict;
7788 CFStringRef name;
7789 CFStringRef serviceid;
7790 CFStringRef configmethod;
7791
7792 if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
7793
7794 if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
7795
7796 if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
7797
7798 if (!CFEqual(ifname, name)) continue;
7799
7800 if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
7801 if (mDNS_LoggingEnabled)
7802 {
7803 if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7804 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
7805 }
7806
7807 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
7808 CFRelease(serviceid);
7809 if (pattern == NULL) continue;
7810
7811 ipv4dict = CFDictionaryGetValue(dict, pattern);
7812 CFRelease(pattern);
7813 if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
7814
7815 configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
7816 if (!configmethod) continue;
7817
7818 if (mDNS_LoggingEnabled)
7819 {
7820 if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7821 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
7822 }
7823
7824 if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found++; break; }
7825 }
7826
7827 CFRelease(ifname);
7828 }
7829
7830 done:
7831 if (vals != NULL) mDNSPlatformMemFree(vals);
7832 if (keys != NULL) mDNSPlatformMemFree(keys);
7833 if (dict != NULL) CFRelease(dict);
7834
7835 return found;
7836 }
7837
7838 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
7839 {
7840 (void)store; // Parameter not used
7841 mDNS *const m = (mDNS *const)context;
7842 KQueueLock();
7843 mDNS_Lock(m);
7844
7845 //mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
7846 const mDNSs32 delay = (mDNSPlatformOneSecond + 39) / 40; // 25 ms delay
7847
7848 const int c = CFArrayGetCount(changedKeys); // Count changes
7849 CFRange range = { 0, c };
7850 const int c_host = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
7851 const int c_comp = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
7852 const int c_udns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0);
7853 const int c_ddns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
7854 #if MDNSRESPONDER_BTMM_SUPPORT
7855 const int c_btmm = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac ) != 0);
7856 #else
7857 const int c_btmm = 0;
7858 #endif
7859 const int c_v4ll = ChangedKeysHaveIPv4LL(changedKeys);
7860 int c_fast = 0;
7861
7862 // Do immediate network changed processing for "p2p*" interfaces and
7863 // for interfaces with the IFEF_DIRECTLINK or IFEF_AWDL flag set or association with a CarPlay
7864 // hosted SSID.
7865 {
7866 CFArrayRef labels;
7867 CFIndex n;
7868 for (int i = 0; i < c; i++)
7869 {
7870 CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i);
7871
7872 // Only look at keys with prefix "State:/Network/Interface/"
7873 if (!CFStringHasPrefix(key, NetworkChangedKey_StateInterfacePrefix))
7874 continue;
7875
7876 // And suffix "IPv6" or "IPv4".
7877 if (!CFStringHasSuffix(key, kSCEntNetIPv6) && !CFStringHasSuffix(key, kSCEntNetIPv4))
7878 continue;
7879
7880 labels = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
7881 if (labels == NULL)
7882 break;
7883 n = CFArrayGetCount(labels);
7884
7885 // Interface changes will have keys of the form:
7886 // State:/Network/Interface/<interfaceName>/IPv6
7887 // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
7888 if (n == 5)
7889 {
7890 char buf[256];
7891
7892 // The 4th label (index = 3) should be the interface name.
7893 if (CFStringGetCString(CFArrayGetValueAtIndex(labels, 3), buf, sizeof(buf), kCFStringEncodingUTF8)
7894 && (strstr(buf, "p2p") || (getExtendedFlags(buf) & (IFEF_DIRECTLINK | IFEF_AWDL)) || IsCarPlaySSID(buf)))
7895 {
7896 LogInfo("NetworkChanged: interface %s qualifies for reduced change handling delay", buf);
7897 c_fast++;
7898 CFRelease(labels);
7899 break;
7900 }
7901 }
7902 CFRelease(labels);
7903 }
7904 }
7905
7906 //if (c && c - c_host - c_comp - c_udns - c_ddns - c_btmm - c_v4ll - c_fast == 0)
7907 // delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
7908
7909 if (mDNS_LoggingEnabled)
7910 {
7911 int i;
7912 for (i=0; i<c; i++)
7913 {
7914 char buf[256];
7915 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7916 LogInfo("*** Network Configuration Change *** SC key: %s", buf);
7917 }
7918 LogInfo("*** Network Configuration Change *** %d change%s %s%s%s%s%s%s%sdelay %d%s",
7919 c, c>1 ? "s" : "",
7920 c_host ? "(Local Hostname) " : "",
7921 c_comp ? "(Computer Name) " : "",
7922 c_udns ? "(DNS) " : "",
7923 c_ddns ? "(DynamicDNS) " : "",
7924 c_btmm ? "(BTMM) " : "",
7925 c_v4ll ? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
7926 c_fast ? "(P2P/IFEF_DIRECTLINK/IFEF_AWDL/IsCarPlaySSID) " : "",
7927 delay,
7928 (c_ddns || c_btmm) ? " + SetKeyChainTimer" : "");
7929 }
7930
7931 SetNetworkChanged(delay);
7932
7933 // Other software might pick up these changes to register or browse in WAB or BTMM domains,
7934 // so in order for secure updates to be made to the server, make sure to read the keychain and
7935 // setup the DomainAuthInfo before handing the network change.
7936 // If we don't, then we will first try to register services in the clear, then later setup the
7937 // DomainAuthInfo, which is incorrect.
7938 if (c_ddns || c_btmm)
7939 SetKeyChainTimer(delay);
7940
7941 // Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
7942
7943 mDNS_Unlock(m);
7944 KQueueUnlock("NetworkChanged");
7945 }
7946
7947 #if APPLE_OSX_mDNSResponder
7948 mDNSlocal void RefreshSPSStatus(const void *key, const void *value, void *context)
7949 {
7950 (void)context;
7951 char buf[IFNAMSIZ];
7952
7953 CFStringRef ifnameStr = (CFStringRef)key;
7954 CFArrayRef array = (CFArrayRef)value;
7955 if (!CFStringGetCString(ifnameStr, buf, sizeof(buf), kCFStringEncodingUTF8))
7956 buf[0] = 0;
7957
7958 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf, CFArrayGetCount(array));
7959 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, buf, value);
7960 }
7961 #endif
7962
7963 mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
7964 {
7965 mDNS *const m = (mDNS *const)info;
7966 (void)store;
7967
7968 KQueueLock(); // serialize with KQueueLoop()
7969
7970 LogInfo("DynamicStoreReconnected: Reconnected");
7971
7972 // State:/Network/MulticastDNS
7973 SetLocalDomains();
7974
7975 // State:/Network/DynamicDNS
7976 if (m->FQDN.c[0])
7977 mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
7978
7979 // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
7980 // as we receive network change notifications and thus not necessary. But we leave it here
7981 // so that if things are done differently in the future, this code still works.
7982
7983 // State:/Network/PrivateDNS
7984 if (privateDnsArray)
7985 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
7986
7987 #if APPLE_OSX_mDNSResponder
7988 // State:/Network/BackToMyMac
7989 UpdateAutoTunnelDomainStatuses(m);
7990
7991 // State:/Network/Interface/en0/SleepProxyServers
7992 if (spsStatusDict)
7993 CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
7994 #endif
7995 KQueueUnlock("DynamicStoreReconnected");
7996 }
7997
7998 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
7999 {
8000 mStatus err = -1;
8001 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
8002 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
8003 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8004 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
8005 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
8006 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8007
8008 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
8009 if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
8010
8011 CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
8012 CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
8013 CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
8014 CFArrayAppendValue(keys, NetworkChangedKey_Computername);
8015 CFArrayAppendValue(keys, NetworkChangedKey_DNS);
8016 CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
8017 CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings);
8018 #if MDNSRESPONDER_BTMM_SUPPORT
8019 CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
8020 CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
8021 #endif
8022 CFArrayAppendValue(patterns, pattern1);
8023 CFArrayAppendValue(patterns, pattern2);
8024 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
8025 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
8026 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
8027
8028 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8029 if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()))
8030 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8031 #else
8032 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
8033 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8034 CFRunLoopAddSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode);
8035 #endif
8036 SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected);
8037 m->p->Store = store;
8038 err = 0;
8039 goto exit;
8040
8041 error:
8042 if (store) CFRelease(store);
8043
8044 exit:
8045 if (patterns) CFRelease(patterns);
8046 if (pattern2) CFRelease(pattern2);
8047 if (pattern1) CFRelease(pattern1);
8048 if (keys) CFRelease(keys);
8049
8050 return(err);
8051 }
8052
8053 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8054
8055 mDNSlocal void mDNSSetPacketFilterRules(char * ifname, const ResourceRecord *const excludeRecord)
8056 {
8057 mDNS *const m = &mDNSStorage;
8058 AuthRecord *rr;
8059 pfArray_t portArray;
8060 pfArray_t protocolArray;
8061 uint32_t count = 0;
8062
8063 for (rr = m->ResourceRecords; rr; rr=rr->next)
8064 {
8065 if ((rr->resrec.rrtype == kDNSServiceType_SRV)
8066 && ((rr->ARType == AuthRecordAnyIncludeP2P) || (rr->ARType == AuthRecordAnyIncludeAWDLandP2P)))
8067 {
8068 const mDNSu8 *p;
8069
8070 if (count >= PFPortArraySize)
8071 {
8072 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize, ARDisplayString(m, rr));
8073 continue;
8074 }
8075
8076 if (excludeRecord && IdenticalResourceRecord(&rr->resrec, excludeRecord))
8077 {
8078 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m, rr));
8079 continue;
8080 }
8081
8082 LogMsg("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr));
8083
8084 portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger;
8085
8086 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
8087 p = rr->resrec.name->c;
8088
8089 // Skip to App Protocol
8090 if (p[0])
8091 p += 1 + p[0];
8092
8093 // Skip to Transport Protocol
8094 if (p[0])
8095 p += 1 + p[0];
8096
8097 if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp"))
8098 {
8099 protocolArray[count] = IPPROTO_TCP;
8100 }
8101 else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp"))
8102 {
8103 protocolArray[count] = IPPROTO_UDP;
8104 }
8105 else
8106 {
8107 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
8108 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m, rr));
8109 return;
8110 }
8111 count++;
8112 }
8113 }
8114 mDNSPacketFilterControl(PF_SET_RULES, ifname, count, portArray, protocolArray);
8115 }
8116
8117 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
8118 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8119 {
8120 mDNS *const m = &mDNSStorage;
8121
8122 NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
8123 while (intf)
8124 {
8125 if (strncmp(intf->ifname, "p2p", 3) == 0)
8126 {
8127 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname);
8128 mDNSSetPacketFilterRules(intf->ifname, excludeRecord);
8129 break;
8130 }
8131 intf = GetFirstActiveInterface(intf->next);
8132 }
8133 }
8134
8135 #else // !TARGET_OS_EMBEDDED
8136
8137 // Currently no packet filter setup required on embedded platforms.
8138 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8139 {
8140 (void) excludeRecord; // unused
8141 }
8142
8143 #endif // !TARGET_OS_EMBEDDED
8144
8145 // AWDL should no longer generate KEV_DL_MASTER_ELECTED events, so just log a message if we receive one.
8146 mDNSlocal void newMasterElected(struct net_event_data * ptr)
8147 {
8148 char ifname[IFNAMSIZ];
8149 mDNSu32 interfaceIndex;
8150
8151 snprintf(ifname, IFNAMSIZ, "%s%d", ptr->if_name, ptr->if_unit);
8152 interfaceIndex = if_nametoindex(ifname);
8153
8154 if (!interfaceIndex)
8155 {
8156 LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname);
8157 return;
8158 }
8159
8160 LogInfo("newMasterElected: KEV_DL_MASTER_ELECTED received on ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
8161 }
8162
8163 // An ssth array of all zeroes indicates the peer has no services registered.
8164 mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op)
8165 {
8166 int i;
8167 int *intp = (int *) op->ssth;
8168
8169 // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
8170 // it's not, print an error message and return false so that
8171 // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
8172 // is received.
8173 if (MAX_SSTH_SIZE % sizeof(int))
8174 {
8175 LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE);
8176 return mDNSfalse;
8177 }
8178
8179 for (i = 0; i < (int)(MAX_SSTH_SIZE / sizeof(int)); i++, intp++)
8180 {
8181 if (*intp)
8182 return mDNSfalse;
8183 }
8184 return mDNStrue;
8185 }
8186
8187 // Mark records from this peer for deletion from the cache.
8188 mDNSlocal void removeCachedPeerRecords(mDNSu32 ifindex, mDNSAddr *ap, bool purgeNow)
8189 {
8190 mDNS *const m = &mDNSStorage;
8191 mDNSu32 slot;
8192 CacheGroup *cg;
8193 CacheRecord *cr;
8194 NetworkInterfaceInfoOSX *infoOSX;
8195 mDNSInterfaceID InterfaceID;
8196
8197 // Using mDNSPlatformInterfaceIDfromInterfaceIndex() would lead to recursive
8198 // locking issues, see: <rdar://problem/21332983>
8199 infoOSX = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
8200 if (!infoOSX)
8201 {
8202 LogInfo("removeCachedPeerRecords: interface %d not yet active", ifindex);
8203 return;
8204 }
8205 InterfaceID = infoOSX->ifinfo.InterfaceID;
8206
8207 FORALL_CACHERECORDS(slot, cg, cr)
8208 {
8209 if ((InterfaceID == cr->resrec.InterfaceID) && mDNSSameAddress(ap, & cr->sourceAddress))
8210 {
8211 LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
8212 DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c);
8213
8214 if (purgeNow)
8215 mDNS_PurgeCacheResourceRecord(m, cr);
8216 else
8217 mDNS_Reconfirm_internal(m, cr, 0); // use default minimum reconfirm time
8218 }
8219 }
8220 }
8221
8222 // Handle KEV_DL_NODE_PRESENCE event.
8223 mDNSlocal void nodePresence(struct kev_dl_node_presence * p)
8224 {
8225 struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info;
8226
8227 LogInfo("nodePresence: IPv6 address: %.16a, SUI %d", p->sin6_node_address.sin6_addr.s6_addr, op->SUI);
8228
8229 // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
8230 // all zeroes when a node is present and has no services registered.
8231 if (allZeroSSTH(op))
8232 {
8233 mDNSAddr peerAddr;
8234
8235 peerAddr.type = mDNSAddrType_IPv6;
8236 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8237
8238 LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer");
8239 removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, false);
8240 }
8241 }
8242
8243 // Handle KEV_DL_NODE_ABSENCE event.
8244 mDNSlocal void nodeAbsence(struct kev_dl_node_absence * p)
8245 {
8246 mDNSAddr peerAddr;
8247
8248 peerAddr.type = mDNSAddrType_IPv6;
8249 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8250
8251 LogInfo("nodeAbsence: immediately purge cached records from %.16a", p->sin6_node_address.sin6_addr.s6_addr);
8252 removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, true);
8253 }
8254
8255 mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context, __unused mDNSBool encounteredEOF)
8256 {
8257 mDNS *const m = (mDNS *const)context;
8258
8259 mDNS_Lock(m);
8260
8261 struct { struct kern_event_msg k; char extra[256]; } msg;
8262 int bytes = recv(s1, &msg, sizeof(msg), 0);
8263 if (bytes < 0)
8264 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
8265 else
8266 {
8267 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
8268 bytes, msg.k.total_size,
8269 msg.k.vendor_code, msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?",
8270 msg.k.kev_class, msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
8271 msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?",
8272 msg.k.id, msg.k.event_code,
8273 msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" :
8274 msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" :
8275 msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" :
8276 msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" :
8277 msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" :
8278 msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" :
8279 msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" :
8280 msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" :
8281 msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" :
8282 msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" :
8283 msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" :
8284 msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" :
8285 msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" :
8286 msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" :
8287 msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" :
8288 msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
8289 msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" :
8290 msg.k.event_code == KEV_DL_IF_IDLE_ROUTE_REFCNT ? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
8291 msg.k.event_code == KEV_DL_IFCAP_CHANGED ? "KEV_DL_IFCAP_CHANGED" :
8292 msg.k.event_code == KEV_DL_LINK_QUALITY_METRIC_CHANGED ? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" :
8293 msg.k.event_code == KEV_DL_NODE_PRESENCE ? "KEV_DL_NODE_PRESENCE" :
8294 msg.k.event_code == KEV_DL_NODE_ABSENCE ? "KEV_DL_NODE_ABSENCE" :
8295 msg.k.event_code == KEV_DL_MASTER_ELECTED ? "KEV_DL_MASTER_ELECTED" :
8296 "?");
8297
8298 if (msg.k.event_code == KEV_DL_NODE_PRESENCE)
8299 nodePresence((struct kev_dl_node_presence *) &msg.k.event_data);
8300
8301 if (msg.k.event_code == KEV_DL_NODE_ABSENCE)
8302 nodeAbsence((struct kev_dl_node_absence *) &msg.k.event_data);
8303
8304 if (msg.k.event_code == KEV_DL_MASTER_ELECTED)
8305 newMasterElected((struct net_event_data *) &msg.k.event_data);
8306
8307 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
8308 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
8309 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
8310 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
8311 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
8312
8313 if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
8314 SetNetworkChanged(mDNSPlatformOneSecond * 2);
8315
8316 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8317
8318 // For p2p interfaces, need to open the advertised service port in the firewall.
8319 if (msg.k.event_code == KEV_DL_IF_ATTACHED)
8320 {
8321 struct net_event_data * p;
8322 p = (struct net_event_data *) &msg.k.event_data;
8323
8324 if (strncmp(p->if_name, "p2p", 3) == 0)
8325 {
8326 char ifname[IFNAMSIZ];
8327 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8328
8329 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8330
8331 mDNSSetPacketFilterRules(ifname, NULL);
8332 }
8333 }
8334
8335 // For p2p interfaces, need to clear the firewall rules on interface detach
8336 if (msg.k.event_code == KEV_DL_IF_DETACHED)
8337 {
8338 struct net_event_data * p;
8339 p = (struct net_event_data *) &msg.k.event_data;
8340
8341 if (strncmp(p->if_name, "p2p", 3) == 0)
8342 {
8343 pfArray_t portArray, protocolArray; // not initialized since count is 0 for PF_CLEAR_RULES
8344 char ifname[IFNAMSIZ];
8345 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8346
8347 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8348
8349 mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
8350 }
8351 }
8352 #endif // !TARGET_OS_EMBEDDED
8353
8354 }
8355
8356 mDNS_Unlock(m);
8357 }
8358
8359 mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
8360 {
8361 m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
8362 if (m->p->SysEventNotifier < 0)
8363 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); }
8364
8365 struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
8366 int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
8367 if (err < 0)
8368 {
8369 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno));
8370 close(m->p->SysEventNotifier);
8371 m->p->SysEventNotifier = -1;
8372 return(mStatus_UnknownErr);
8373 }
8374
8375 m->p->SysEventKQueue.KQcallback = SysEventCallBack;
8376 m->p->SysEventKQueue.KQcontext = m;
8377 m->p->SysEventKQueue.KQtask = "System Event Notifier";
8378 KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
8379
8380 return(mStatus_NoError);
8381 }
8382
8383 #ifndef NO_SECURITYFRAMEWORK
8384 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
8385 {
8386 LogInfo("*** Keychain Changed ***");
8387 mDNS *const m = (mDNS *const)context;
8388 SecKeychainRef skc;
8389 OSStatus err = SecKeychainCopyDefault(&skc);
8390 if (!err)
8391 {
8392 if (info->keychain == skc)
8393 {
8394 // 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
8395 mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
8396 if (!relevant)
8397 {
8398 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
8399 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
8400 SecKeychainAttributeList *a = NULL;
8401 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
8402 if (!err)
8403 {
8404 relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
8405 (a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))));
8406 #if MDNSRESPONDER_BTMM_SUPPORT
8407 if (!relevant && (a->attr[1].length >= mDNSPlatformStrLen(btmmprefix)) && !strncasecmp(a->attr[1].data, btmmprefix, mDNSPlatformStrLen(btmmprefix)))
8408 {
8409 relevant = mDNStrue;
8410 }
8411 #endif
8412 SecKeychainItemFreeAttributesAndData(a, NULL);
8413 }
8414 }
8415 if (relevant)
8416 {
8417 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
8418 keychainEvent,
8419 keychainEvent == kSecAddEvent ? "kSecAddEvent" :
8420 keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
8421 keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
8422 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
8423 KQueueLock();
8424 mDNS_Lock(m);
8425
8426 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
8427 // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
8428 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
8429 //
8430 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
8431 // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
8432 // a one second delay is ok, as we'll still converge to correctness, and there's no race
8433 // condition between the RegistrationDomain and the DomainAuthInfo.
8434 //
8435 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
8436 // the timer here, as it will not get set by NetworkChanged().
8437 SetKeyChainTimer(mDNSPlatformOneSecond);
8438
8439 mDNS_Unlock(m);
8440 KQueueUnlock("KeychainChanged");
8441 }
8442 }
8443 CFRelease(skc);
8444 }
8445
8446 return 0;
8447 }
8448 #endif
8449
8450 mDNSlocal void PowerOn(mDNS *const m)
8451 {
8452 mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
8453
8454 if (m->p->WakeAtUTC)
8455 {
8456 long utc = mDNSPlatformUTC();
8457 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
8458 if (m->p->WakeAtUTC - utc > 30)
8459 {
8460 LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
8461 }
8462 else if (utc - m->p->WakeAtUTC > 30)
8463 {
8464 LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
8465 }
8466 else if (IsAppleTV())
8467 {
8468 LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC);
8469 }
8470 else
8471 {
8472 LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m->p->WakeAtUTC - utc);
8473 m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond;
8474 }
8475 }
8476
8477 // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
8478 // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
8479 // We will clear this assertion as soon as we think the mainenance activities are done.
8480 mDNSPlatformPreventSleep(DARK_WAKE_TIME, "mDNSResponder:maintenance");
8481
8482 }
8483
8484 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
8485 {
8486 mDNS *const m = (mDNS *const)refcon;
8487 KQueueLock();
8488 (void)service; // Parameter not used
8489 debugf("PowerChanged %X %lX", messageType, messageArgument);
8490
8491 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8492 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8493
8494 switch(messageType)
8495 {
8496 case kIOMessageCanSystemPowerOff: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
8497 case kIOMessageSystemWillPowerOff: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
8498 mDNSCoreMachineSleep(m, true);
8499 if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged();
8500 break;
8501 case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
8502 case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep"); break; // E0000270
8503 case kIOMessageSystemWillSleep: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
8504 mDNSCoreMachineSleep(m, true);
8505 break;
8506 case kIOMessageSystemWillNotSleep: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
8507 case kIOMessageSystemHasPoweredOn: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
8508 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
8509 if (m->SleepState)
8510 {
8511 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
8512 PowerOn(m);
8513 }
8514 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
8515 // the System Configuration Framework "network changed" event that we expect
8516 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
8517 mDNS_Lock(m);
8518 SetNetworkChanged(mDNSPlatformOneSecond * 2);
8519 mDNS_Unlock(m);
8520
8521 break;
8522 case kIOMessageSystemWillRestart: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
8523 case kIOMessageSystemWillPowerOn: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
8524
8525 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
8526 if (m->SleepState != SleepState_Sleeping)
8527 {
8528 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
8529 m->SleepState = SleepState_Sleeping;
8530 mDNSMacOSXNetworkChanged();
8531 }
8532 PowerOn(m);
8533 break;
8534 default: LogSPS("PowerChanged unknown message %X", messageType); break;
8535 }
8536
8537 if (messageType == kIOMessageSystemWillSleep)
8538 m->p->SleepCookie = (long)messageArgument;
8539 else if (messageType == kIOMessageCanSystemSleep)
8540 IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
8541
8542 KQueueUnlock("PowerChanged Sleep/Wake");
8543 }
8544
8545 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
8546 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
8547 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
8548 mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
8549 {
8550 mDNS *const m = (mDNS *const)refcon;
8551 KQueueLock();
8552 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
8553 connection, token, eventDescriptor,
8554 eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "",
8555 eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "",
8556 eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "",
8557 eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
8558 eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : "");
8559
8560 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8561 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8562
8563 if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
8564 {
8565 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
8566 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
8567 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
8568 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
8569 if (m->SleepLimit)
8570 {
8571 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8572 IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie);
8573 m->SleepLimit = 0;
8574 }
8575 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8576 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
8577 if (m->SleepState != SleepState_Awake)
8578 {
8579 PowerOn(m);
8580 // If the network notifications have already come before we got the wakeup, we ignored them and
8581 // in case we get no more, we need to trigger one.
8582 mDNS_Lock(m);
8583 SetNetworkChanged(mDNSPlatformOneSecond * 2);
8584 mDNS_Unlock(m);
8585 }
8586 IOPMConnectionAcknowledgeEvent(connection, token);
8587 }
8588 else
8589 {
8590 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
8591 // we should hear nothing more until we're told that the CPU has started executing again.
8592 if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
8593 //sleep(5);
8594 //mDNSMacOSXNetworkChanged(m);
8595 mDNSCoreMachineSleep(m, true);
8596 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
8597 m->p->SleepCookie = token;
8598 }
8599
8600 KQueueUnlock("SnowLeopardPowerChanged Sleep/Wake");
8601 }
8602 #endif
8603
8604 #if COMPILER_LIKES_PRAGMA_MARK
8605 #pragma mark -
8606 #pragma mark - /etc/hosts support
8607 #endif
8608
8609 // Implementation Notes
8610 //
8611 // As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
8612 // 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
8613 // them into a hash table. The implementation need to be able to do the following things efficiently
8614 //
8615 // 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
8616 // 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
8617 // 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
8618 // need to be able set the RRSet of a resource record to the first one in the list and also update when
8619 // one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
8620 // not a duplicate
8621 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
8622 //
8623 // CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
8624 // "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
8625 // of the core layer which does all of the above very efficiently
8626
8627 #define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
8628
8629 mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
8630 {
8631 (void)m; // unused
8632 (void)rr;
8633 (void)result;
8634 if (result == mStatus_MemFree)
8635 {
8636 LogInfo("FreeEtcHosts: %s", ARDisplayString(m, rr));
8637 freeL("etchosts", rr);
8638 }
8639 }
8640
8641 // Returns true on success and false on failure
8642 mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(const domainname *domain, const struct sockaddr *sa, const domainname *cname, char *ifname, AuthHash *auth)
8643 {
8644 AuthRecord *rr;
8645 mDNSu32 namehash;
8646 AuthGroup *ag;
8647 mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly;
8648 mDNSu16 rrtype;
8649
8650 if (!domain)
8651 {
8652 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
8653 return mDNSfalse;
8654 }
8655 if (!sa && !cname)
8656 {
8657 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
8658 return mDNSfalse;
8659 }
8660
8661 if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
8662 {
8663 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa->sa_family);
8664 return mDNSfalse;
8665 }
8666
8667
8668 if (ifname)
8669 {
8670 mDNSu32 ifindex = if_nametoindex(ifname);
8671 if (!ifindex)
8672 {
8673 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain->c, ifname);
8674 return mDNSfalse;
8675 }
8676 InterfaceID = (mDNSInterfaceID)(uintptr_t)ifindex;
8677 }
8678
8679 if (sa)
8680 rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA);
8681 else
8682 rrtype = kDNSType_CNAME;
8683
8684 // Check for duplicates. See whether we parsed an entry before like this ?
8685 namehash = DomainNameHashValue(domain);
8686 ag = AuthGroupForName(auth, namehash, domain);
8687 if (ag)
8688 {
8689 rr = ag->members;
8690 while (rr)
8691 {
8692 if (rr->resrec.rrtype == rrtype)
8693 {
8694 if (rrtype == kDNSType_A)
8695 {
8696 mDNSv4Addr ip;
8697 ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
8698 if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip))
8699 {
8700 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c);
8701 return mDNSfalse;
8702 }
8703 }
8704 else if (rrtype == kDNSType_AAAA)
8705 {
8706 mDNSv6Addr ip6;
8707 ip6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
8708 ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
8709 ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
8710 ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
8711 if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6))
8712 {
8713 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c);
8714 return mDNSfalse;
8715 }
8716 }
8717 else if (rrtype == kDNSType_CNAME)
8718 {
8719 if (SameDomainName(&rr->resrec.rdata->u.name, cname))
8720 {
8721 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname->c, domain->c);
8722 return mDNSfalse;
8723 }
8724 }
8725 }
8726 rr = rr->next;
8727 }
8728 }
8729 rr= mallocL("etchosts", sizeof(*rr));
8730 if (rr == NULL) return mDNSfalse;
8731 mDNSPlatformMemZero(rr, sizeof(*rr));
8732 mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
8733 AssignDomainName(&rr->namestorage, domain);
8734
8735 if (sa)
8736 {
8737 rr->resrec.rdlength = sa->sa_family == AF_INET ? sizeof(mDNSv4Addr) : sizeof(mDNSv6Addr);
8738 if (sa->sa_family == AF_INET)
8739 rr->resrec.rdata->u.ipv4.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
8740 else
8741 {
8742 rr->resrec.rdata->u.ipv6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
8743 rr->resrec.rdata->u.ipv6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
8744 rr->resrec.rdata->u.ipv6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
8745 rr->resrec.rdata->u.ipv6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
8746 }
8747 }
8748 else
8749 {
8750 rr->resrec.rdlength = DomainNameLength(cname);
8751 rr->resrec.rdata->u.name.c[0] = 0;
8752 AssignDomainName(&rr->resrec.rdata->u.name, cname);
8753 }
8754 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
8755 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
8756 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(&mDNSStorage, rr));
8757 InsertAuthRecord(&mDNSStorage, auth, rr);
8758 return mDNStrue;
8759 }
8760
8761 mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **name)
8762 {
8763 int i;
8764
8765 *name = NULL;
8766 for (i = start; i < length; i++)
8767 {
8768 if (buffer[i] == '#')
8769 return -1;
8770 if (buffer[i] != ' ' && buffer[i] != ',' && buffer[i] != '\t')
8771 {
8772 *name = &buffer[i];
8773
8774 // Found the start of a name, find the end and null terminate
8775 for (i++; i < length; i++)
8776 {
8777 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
8778 {
8779 buffer[i] = 0;
8780 break;
8781 }
8782 }
8783 return i;
8784 }
8785 }
8786 return -1;
8787 }
8788
8789 mDNSlocal void mDNSMacOSXParseEtcHostsLine(char *buffer, ssize_t length, AuthHash *auth)
8790 {
8791 int i;
8792 int ifStart = 0;
8793 char *ifname = NULL;
8794 domainname name1d;
8795 domainname name2d;
8796 char *name1;
8797 char *name2;
8798 int aliasIndex;
8799
8800 //Ignore leading whitespaces and tabs
8801 while (*buffer == ' ' || *buffer == '\t')
8802 {
8803 buffer++;
8804 length--;
8805 }
8806
8807 // Find the end of the address string
8808 for (i = 0; i < length; i++)
8809 {
8810 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t' || buffer[i] == '%')
8811 {
8812 if (buffer[i] == '%')
8813 ifStart = i + 1;
8814 buffer[i] = 0;
8815 break;
8816 }
8817 }
8818
8819 // Convert the address string to an address
8820 struct addrinfo hints;
8821 bzero(&hints, sizeof(hints));
8822 hints.ai_flags = AI_NUMERICHOST;
8823 struct addrinfo *gairesults = NULL;
8824 if (getaddrinfo(buffer, NULL, &hints, &gairesults) != 0)
8825 {
8826 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
8827 return;
8828 }
8829
8830 if (ifStart)
8831 {
8832 // Parse the interface
8833 ifname = &buffer[ifStart];
8834 for (i = ifStart + 1; i < length; i++)
8835 {
8836 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
8837 {
8838 buffer[i] = 0;
8839 break;
8840 }
8841 }
8842 }
8843
8844 i = EtcHostsParseOneName(i + 1, length, buffer, &name1);
8845 if (i == length)
8846 {
8847 // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
8848 if (!MakeDomainNameFromDNSNameString(&name1d, name1))
8849 {
8850 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
8851 freeaddrinfo(gairesults);
8852 return;
8853 }
8854 mDNSMacOSXCreateEtcHostsEntry(&name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
8855 }
8856 else if (i != -1)
8857 {
8858 domainname first;
8859 // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
8860 // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
8861 // doing the right thing.
8862
8863 if (!MakeDomainNameFromDNSNameString(&first, name1))
8864 {
8865 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
8866 freeaddrinfo(gairesults);
8867 return;
8868 }
8869 mDNSMacOSXCreateEtcHostsEntry(&first, gairesults->ai_addr, mDNSNULL, ifname, auth);
8870
8871 // /etc/hosts alias discussion:
8872 //
8873 // If the /etc/hosts has an entry like this
8874 //
8875 // ip_address cname [aliases...]
8876 // 1.2.3.4 sun star bright
8877 //
8878 // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
8879 // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
8880 //
8881 // To achieve this, we need to add the entry like this:
8882 //
8883 // sun A 1.2.3.4
8884 // star CNAME sun
8885 // bright CNAME sun
8886 //
8887 // We store the first name we parsed in "first" and add the address (A/AAAA) record.
8888 // Then we parse additional names adding CNAME records till we reach the end.
8889
8890 aliasIndex = 0;
8891 while (i < length)
8892 {
8893 // Continue to parse additional aliases until we reach end of the line and
8894 // for each "alias" parsed, add a CNAME record where "alias" points to the first "name".
8895 // See also /etc/hosts alias discussion above
8896
8897 i = EtcHostsParseOneName(i + 1, length, buffer, &name2);
8898
8899 if (name2)
8900 {
8901 if ((aliasIndex) && (*buffer == *name2))
8902 break; // break out of the loop if we wrap around
8903
8904 if (!MakeDomainNameFromDNSNameString(&name2d, name2))
8905 {
8906 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2);
8907 freeaddrinfo(gairesults);
8908 return;
8909 }
8910 // Ignore if it points to itself
8911 if (!SameDomainName(&first, &name2d))
8912 {
8913 if (!mDNSMacOSXCreateEtcHostsEntry(&name2d, mDNSNULL, &first, ifname, auth))
8914 {
8915 freeaddrinfo(gairesults);
8916 return;
8917 }
8918 }
8919 else
8920 {
8921 LogInfo("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names first %##s, name2 %##s", first.c, name2d.c);
8922 }
8923 aliasIndex++;
8924 }
8925 else if (!aliasIndex)
8926 {
8927 // We have never parsed any aliases. This case happens if there
8928 // is just one name and some extra white spaces at the end.
8929 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c);
8930 break;
8931 }
8932 }
8933 }
8934 freeaddrinfo(gairesults);
8935 }
8936
8937 mDNSlocal void mDNSMacOSXParseEtcHosts(int fd, AuthHash *auth)
8938 {
8939 mDNSBool good;
8940 char buf[ETCHOSTS_BUFSIZE];
8941 ssize_t len;
8942 FILE *fp;
8943
8944 if (fd == -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
8945
8946 fp = fopen("/etc/hosts", "r");
8947 if (!fp) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
8948
8949 while (1)
8950 {
8951 good = (fgets(buf, ETCHOSTS_BUFSIZE, fp) != NULL);
8952 if (!good) break;
8953
8954 // skip comment and empty lines
8955 if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n')
8956 continue;
8957
8958 len = strlen(buf);
8959 if (!len) break; // sanity check
8960 //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
8961 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
8962 {
8963 buf[len - 1] = '\0';
8964 len = len - 1;
8965 }
8966 // fgets always null terminates and hence even if we have no
8967 // newline at the end, it is null terminated. The callee
8968 // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
8969 // buf[length] is zero and hence we decrement len to reflect that.
8970 if (len)
8971 {
8972 //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
8973 //here we need to check for just \r but taking extra caution.
8974 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
8975 {
8976 buf[len - 1] = '\0';
8977 len = len - 1;
8978 }
8979 }
8980 if (!len) //Sanity Check: len should never be zero
8981 {
8982 LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
8983 continue;
8984 }
8985 mDNSMacOSXParseEtcHostsLine(buf, len, auth);
8986 }
8987 fclose(fp);
8988 }
8989
8990 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m);
8991
8992 mDNSlocal int mDNSMacOSXGetEtcHostsFD(void)
8993 {
8994 mDNS *const m = &mDNSStorage;
8995 #ifdef __DISPATCH_GROUP__
8996 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
8997 static dispatch_queue_t etcq = 0;
8998 static dispatch_source_t etcsrc = 0;
8999 static dispatch_source_t hostssrc = 0;
9000
9001 // First time through? just schedule ourselves on the main queue and we'll do the work later
9002 if (!etcq)
9003 {
9004 etcq = dispatch_get_main_queue();
9005 if (etcq)
9006 {
9007 // Do this work on the queue, not here - solves potential synchronization issues
9008 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9009 }
9010 return -1;
9011 }
9012
9013 if (hostssrc) return dispatch_source_get_handle(hostssrc);
9014 #endif
9015
9016 int fd = open("/etc/hosts", O_RDONLY);
9017
9018 #ifdef __DISPATCH_GROUP__
9019 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9020 if (fd == -1)
9021 {
9022 // If the open failed and we're already watching /etc, we're done
9023 if (etcsrc) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd; }
9024
9025 // we aren't watching /etc, we should be
9026 fd = open("/etc", O_RDONLY);
9027 if (fd == -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
9028 etcsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME, etcq);
9029 if (etcsrc == NULL)
9030 {
9031 close(fd);
9032 return -1;
9033 }
9034 dispatch_source_set_event_handler(etcsrc,
9035 ^{
9036 u_int32_t flags = dispatch_source_get_data(etcsrc);
9037 LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags);
9038 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9039 {
9040 dispatch_source_cancel(etcsrc);
9041 dispatch_release(etcsrc);
9042 etcsrc = NULL;
9043 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9044 return;
9045 }
9046 if ((flags & DISPATCH_VNODE_WRITE) != 0 && hostssrc == NULL)
9047 {
9048 mDNSMacOSXUpdateEtcHosts(m);
9049 }
9050 });
9051 dispatch_source_set_cancel_handler(etcsrc, ^{close(fd);});
9052 dispatch_resume(etcsrc);
9053
9054 // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
9055 fd = open("/etc/hosts", O_RDONLY | O_EVTONLY);
9056 if (fd == -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
9057 }
9058
9059 // create a dispatch source to watch for changes to hosts file
9060 hostssrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd,
9061 (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME |
9062 DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_LINK | DISPATCH_VNODE_REVOKE), etcq);
9063 if (hostssrc == NULL)
9064 {
9065 close(fd);
9066 return -1;
9067 }
9068 dispatch_source_set_event_handler(hostssrc,
9069 ^{
9070 u_int32_t flags = dispatch_source_get_data(hostssrc);
9071 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags);
9072 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9073 {
9074 dispatch_source_cancel(hostssrc);
9075 dispatch_release(hostssrc);
9076 hostssrc = NULL;
9077 // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
9078 // the block immediately, we try to open the file and the file may not exist and may
9079 // fail to get a notification in the future. When the file does not exist and
9080 // we start to monitor the directory, on "dispatch_resume" of that source, there
9081 // is no guarantee that the file creation will be notified always because when
9082 // the dispatch_resume returns, the kevent manager may not have registered the
9083 // kevent yet but the file may have been created
9084 usleep(1000000);
9085 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9086 return;
9087 }
9088 if ((flags & DISPATCH_VNODE_WRITE) != 0)
9089 {
9090 mDNSMacOSXUpdateEtcHosts(m);
9091 }
9092 });
9093 dispatch_source_set_cancel_handler(hostssrc, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd); close(fd);});
9094 dispatch_resume(hostssrc);
9095
9096 // Cleanup /etc source, no need to watch it if we already have /etc/hosts
9097 if (etcsrc)
9098 {
9099 dispatch_source_cancel(etcsrc);
9100 dispatch_release(etcsrc);
9101 etcsrc = NULL;
9102 }
9103
9104 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
9105 return hostssrc ? (int)dispatch_source_get_handle(hostssrc) : -1;
9106 #else
9107 (void)m;
9108 return fd;
9109 #endif
9110 }
9111
9112 // When /etc/hosts is modified, flush all the cache records as there may be local
9113 // authoritative answers now
9114 mDNSlocal void FlushAllCacheRecords(mDNS *const m)
9115 {
9116 CacheRecord *cr;
9117 mDNSu32 slot;
9118 CacheGroup *cg;
9119
9120 FORALL_CACHERECORDS(slot, cg, cr)
9121 {
9122 // Skip multicast.
9123 if (cr->resrec.InterfaceID) continue;
9124
9125 // If a resource record can answer A or AAAA, they need to be flushed so that we will
9126 // never used to deliver an ADD or RMV
9127 if (RRTypeAnswersQuestionType(&cr->resrec, kDNSType_A) ||
9128 RRTypeAnswersQuestionType(&cr->resrec, kDNSType_AAAA))
9129 {
9130 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr));
9131 mDNS_PurgeCacheResourceRecord(m, cr);
9132 }
9133 }
9134 }
9135
9136 // Add new entries to the core. If justCheck is set, this function does not add, just returns true
9137 mDNSlocal mDNSBool EtcHostsAddNewEntries(AuthHash *newhosts, mDNSBool justCheck)
9138 {
9139 mDNS *const m = &mDNSStorage;
9140 AuthGroup *ag;
9141 mDNSu32 slot;
9142 AuthRecord *rr, *primary, *rrnext;
9143 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9144 for (ag = newhosts->rrauth_hash[slot]; ag; ag = ag->next)
9145 {
9146 primary = NULL;
9147 for (rr = ag->members; rr; rr = rrnext)
9148 {
9149 rrnext = rr->next;
9150 AuthGroup *ag1;
9151 AuthRecord *rr1;
9152 mDNSBool found = mDNSfalse;
9153 ag1 = AuthGroupForRecord(&m->rrauth, &rr->resrec);
9154 if (ag1 && ag1->members)
9155 {
9156 if (!primary) primary = ag1->members;
9157 rr1 = ag1->members;
9158 while (rr1)
9159 {
9160 // We are not using InterfaceID in checking for duplicates. This means,
9161 // if there are two addresses for a given name e.g., fe80::1%en0 and
9162 // fe80::1%en1, we only add the first one. It is not clear whether
9163 // this is a common case. To fix this, we also need to modify
9164 // mDNS_Register_internal in how it handles duplicates. If it becomes a
9165 // common case, we will fix it then.
9166 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9167 {
9168 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
9169 found = mDNStrue;
9170 break;
9171 }
9172 rr1 = rr1->next;
9173 }
9174 }
9175 if (!found)
9176 {
9177 if (justCheck)
9178 {
9179 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m, rr));
9180 return mDNStrue;
9181 }
9182 RemoveAuthRecord(m, newhosts, rr);
9183 // if there is no primary, point to self
9184 rr->RRSet = (primary ? primary : rr);
9185 rr->next = NULL;
9186 LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m, rr));
9187 if (mDNS_Register_internal(m, rr) != mStatus_NoError)
9188 LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr));
9189 }
9190 }
9191 }
9192 return mDNSfalse;
9193 }
9194
9195 // Delete entries from the core that are no longer needed. If justCheck is set, this function
9196 // does not delete, just returns true
9197 mDNSlocal mDNSBool EtcHostsDeleteOldEntries(AuthHash *newhosts, mDNSBool justCheck)
9198 {
9199 mDNS *const m = &mDNSStorage;
9200 AuthGroup *ag;
9201 mDNSu32 slot;
9202 AuthRecord *rr, *rrnext;
9203 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9204 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
9205 for (rr = ag->members; rr; rr = rrnext)
9206 {
9207 mDNSBool found = mDNSfalse;
9208 AuthGroup *ag1;
9209 AuthRecord *rr1;
9210 rrnext = rr->next;
9211 if (rr->RecordCallback != FreeEtcHosts) continue;
9212 ag1 = AuthGroupForRecord(newhosts, &rr->resrec);
9213 if (ag1)
9214 {
9215 rr1 = ag1->members;
9216 while (rr1)
9217 {
9218 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9219 {
9220 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m, rr));
9221 found = mDNStrue;
9222 break;
9223 }
9224 rr1 = rr1->next;
9225 }
9226 }
9227 // there is no corresponding record in newhosts for the same name. This means
9228 // we should delete this from the core.
9229 if (!found)
9230 {
9231 if (justCheck)
9232 {
9233 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m, rr));
9234 return mDNStrue;
9235 }
9236 // if primary is going away, make sure that the rest of the records
9237 // point to the new primary
9238 if (rr == ag->members)
9239 {
9240 AuthRecord *new_primary = rr->next;
9241 AuthRecord *r = new_primary;
9242 while (r)
9243 {
9244 if (r->RRSet == rr)
9245 {
9246 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m, r));
9247 r->RRSet = new_primary;
9248 }
9249 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m, r), r->resrec.name);
9250 r = r->next;
9251 }
9252 }
9253 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m, rr));
9254 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
9255 }
9256 }
9257 return mDNSfalse;
9258 }
9259
9260 mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context)
9261 {
9262 AuthHash *newhosts = (AuthHash *)context;
9263
9264 mDNS_CheckLock(m);
9265
9266 //Delete old entries from the core if they are not present in the newhosts
9267 EtcHostsDeleteOldEntries(newhosts, mDNSfalse);
9268 // Add the new entries to the core if not already present in the core
9269 EtcHostsAddNewEntries(newhosts, mDNSfalse);
9270 }
9271
9272 mDNSlocal void FreeNewHosts(AuthHash *newhosts)
9273 {
9274 mDNSu32 slot;
9275 AuthGroup *ag, *agnext;
9276 AuthRecord *rr, *rrnext;
9277
9278 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9279 for (ag = newhosts->rrauth_hash[slot]; ag; ag = agnext)
9280 {
9281 agnext = ag->next;
9282 for (rr = ag->members; rr; rr = rrnext)
9283 {
9284 rrnext = rr->next;
9285 freeL("etchosts", rr);
9286 }
9287 freeL("AuthGroups", ag);
9288 }
9289 }
9290
9291 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
9292 {
9293 AuthHash newhosts;
9294
9295 // As we will be modifying the core, we can only have one thread running at
9296 // any point in time.
9297 KQueueLock();
9298
9299 mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
9300
9301 // Get the file desecriptor (will trigger us to start watching for changes)
9302 int fd = mDNSMacOSXGetEtcHostsFD();
9303 if (fd != -1)
9304 {
9305 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd);
9306 mDNSMacOSXParseEtcHosts(fd, &newhosts);
9307 }
9308 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
9309
9310 // Optimization: Detect whether /etc/hosts changed or not.
9311 //
9312 // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
9313 // newhosts is already registered with core. If we find at least one entry that is not
9314 // registered with core, then it means we have work to do.
9315 //
9316 // 2. Next, we check to see if any of the entries that are registered with core is not present
9317 // in newhosts. If we find at least one entry that is not present, it means we have work to
9318 // do.
9319 //
9320 // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
9321 // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
9322 // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
9323 // in the future and this code does not have to change.
9324 mDNS_Lock(m);
9325 // Add the new entries to the core if not already present in the core
9326 if (!EtcHostsAddNewEntries(&newhosts, mDNStrue))
9327 {
9328 // No new entries to add, check to see if we need to delete any old entries from the
9329 // core if they are not present in the newhosts
9330 if (!EtcHostsDeleteOldEntries(&newhosts, mDNStrue))
9331 {
9332 LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
9333 FreeNewHosts(&newhosts);
9334 mDNS_Unlock(m);
9335 KQueueUnlock("/etc/hosts changed");
9336 return;
9337 }
9338 }
9339
9340 // This will flush the cache, stop and start the query so that the queries
9341 // can look at the /etc/hosts again
9342 //
9343 // Notes:
9344 //
9345 // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
9346 // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
9347 // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
9348 // delivers these events in the right order and then calls us back to delete them.
9349 //
9350 // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
9351 // is a common function that looks at all local auth records and delivers a RMV including
9352 // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
9353 // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
9354 // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
9355 // is called back where we do the Registration of the record. This results in RMV followed by ADD which
9356 // looks normal.
9357 mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts);
9358 FreeNewHosts(&newhosts);
9359 mDNS_Unlock(m);
9360 KQueueUnlock("/etc/hosts changed");
9361 }
9362
9363 #if COMPILER_LIKES_PRAGMA_MARK
9364 #pragma mark -
9365 #pragma mark - Initialization & Teardown
9366 #endif
9367
9368 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
9369 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
9370 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
9371 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
9372
9373 // Major version 13 is 10.9.x
9374 mDNSexport void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
9375 {
9376 int major = 0, minor = 0;
9377 char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
9378 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
9379 if (vers)
9380 {
9381 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
9382 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
9383 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
9384 if (cfprodname)
9385 CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
9386 if (cfprodvers)
9387 CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
9388 if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
9389 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
9390 CFRelease(vers);
9391 }
9392 if (!major)
9393 {
9394 major = 13;
9395 LogMsg("Note: No Major Build Version number found; assuming 13");
9396 }
9397 if (HINFO_SWstring)
9398 mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion));
9399 //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
9400
9401 // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
9402 if ((prodname[0] & 0xDF) == 'M')
9403 OSXVers = major;
9404 else
9405 iOSVers = major;
9406 }
9407
9408 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
9409 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
9410 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
9411 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
9412 {
9413 int err = -1;
9414 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
9415 if (s < 3)
9416 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
9417 else
9418 {
9419 struct sockaddr_in s5353;
9420 s5353.sin_family = AF_INET;
9421 s5353.sin_port = MulticastDNSPort.NotAnInteger;
9422 s5353.sin_addr.s_addr = 0;
9423 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
9424 close(s);
9425 }
9426
9427 if (err) LogMsg("No unicast UDP responses");
9428 else debugf("Unicast UDP responses okay");
9429 return(err == 0);
9430 }
9431
9432 mDNSlocal void CreatePTRRecord(const domainname *domain)
9433 {
9434 AuthRecord *rr;
9435 const domainname *pname = (domainname *)"\x9" "localhost";
9436
9437 rr= mallocL("localhosts", sizeof(*rr));
9438 if (rr == NULL) return;
9439 mDNSPlatformMemZero(rr, sizeof(*rr));
9440
9441 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
9442 AssignDomainName(&rr->namestorage, domain);
9443
9444 rr->resrec.rdlength = DomainNameLength(pname);
9445 rr->resrec.rdata->u.name.c[0] = 0;
9446 AssignDomainName(&rr->resrec.rdata->u.name, pname);
9447
9448 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
9449 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
9450 mDNS_Register(&mDNSStorage, rr);
9451 }
9452
9453 // Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
9454 // on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
9455 // fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
9456 // a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
9457 //
9458 // Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
9459 // intentionally to avoid adding to the complexity of code handling /etc/hosts.
9460 mDNSlocal void SetupLocalHostRecords(void)
9461 {
9462 domainname name;
9463
9464 MakeDomainNameFromDNSNameString(&name, "1.0.0.127.in-addr.arpa.");
9465 CreatePTRRecord(&name);
9466
9467 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.");
9468 CreatePTRRecord(&name);
9469 }
9470
9471 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
9472 mDNSlocal void setSameDomainLabelPointer(void);
9473 #endif
9474
9475 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
9476 // 1) query for b._dns-sd._udp.local on LocalOnly interface
9477 // (.local manually generated via explicit callback)
9478 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
9479 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
9480 // 4) result above should generate a callback from question in (1). result added to global list
9481 // 5) global list delivered to client via GetSearchDomainList()
9482 // 6) client calls to enumerate domains now go over LocalOnly interface
9483 // (!!!KRS may add outgoing interface in addition)
9484
9485 #if TARGET_OS_IPHONE
9486 mDNSlocal mDNSBool IsAppleInternalBuild(void)
9487 {
9488 return (os_variant_has_internal_diagnostics("com.apple.mDNSResponder") ? mDNStrue : mDNSfalse);
9489 }
9490
9491 mDNSlocal mStatus RegisterLocalOnlyAddressRecord(const domainname *const name, mDNSu16 type, const void *rdata, mDNSu16 rdlength)
9492 {
9493 switch(type)
9494 {
9495 case kDNSType_A:
9496 if (rdlength != 4) return (mStatus_BadParamErr);
9497 break;
9498
9499 case kDNSType_AAAA:
9500 if (rdlength != 16) return (mStatus_BadParamErr);
9501 break;
9502
9503 default:
9504 return (mStatus_BadParamErr);
9505 }
9506
9507 AuthRecord *rr = mallocL("etchosts", sizeof(*rr));
9508 if (!rr) return (mStatus_NoMemoryErr);
9509 mDNSPlatformMemZero(rr, sizeof(*rr));
9510
9511 mDNS_SetupResourceRecord(rr, NULL, mDNSInterface_LocalOnly, type, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
9512 AssignDomainName(&rr->namestorage, name);
9513 mDNSPlatformMemCopy(rr->resrec.rdata->u.data, rdata, rdlength);
9514
9515 const mStatus err = mDNS_Register_internal(&mDNSStorage, rr);
9516 if (err)
9517 {
9518 LogMsg("RegisterLocalOnlyAddressRecord: mDNS_Register error %d registering %s", err, ARDisplayString(&mDNSStorage, rr));
9519 freeL("etchosts", rr);
9520 }
9521 return (err);
9522 }
9523
9524 mDNSlocal void RegisterLocalOnlyARecord(const domainname *const name, const mDNSv4Addr *const addr)
9525 {
9526 RegisterLocalOnlyAddressRecord(name, kDNSType_A, addr->b, (mDNSu16)sizeof(mDNSv4Addr));
9527 }
9528
9529 mDNSlocal void RegisterLocalOnlyAAAARecord(const domainname *const name, const mDNSv6Addr *const addr)
9530 {
9531 RegisterLocalOnlyAddressRecord(name, kDNSType_AAAA, addr->b, (mDNSu16)sizeof(mDNSv6Addr));
9532 }
9533 #endif
9534
9535 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
9536 {
9537 mStatus err;
9538
9539 char HINFO_SWstring[256] = "";
9540 mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
9541
9542 #if APPLE_OSX_mDNSResponder
9543 setSameDomainLabelPointer();
9544 #endif
9545
9546 err = mDNSHelperInit();
9547 if (err)
9548 return err;
9549
9550 // Store mDNSResponder Platform
9551 if (OSXVers)
9552 {
9553 m->mDNS_plat = platform_OSX;
9554 }
9555 else if (iOSVers)
9556 {
9557 if (IsAppleTV())
9558 m->mDNS_plat = platform_Atv;
9559 else
9560 m->mDNS_plat = platform_iOS;
9561 }
9562 else
9563 {
9564 m->mDNS_plat = platform_NonApple;
9565 }
9566
9567 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
9568 // 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.
9569 int i;
9570 for (i=0; i<100; i++)
9571 {
9572 domainlabel testlabel;
9573 testlabel.c[0] = 0;
9574 GetUserSpecifiedLocalHostName(&testlabel);
9575 if (testlabel.c[0]) break;
9576 usleep(50000);
9577 }
9578
9579 m->hostlabel.c[0] = 0;
9580
9581 int get_model[2] = { CTL_HW, HW_MODEL };
9582 size_t len_model = sizeof(HINFO_HWstring_buffer);
9583
9584 // Normal Apple model names are of the form "iPhone2,1", and
9585 // internal code names are strings containing no commas, e.g. "N88AP".
9586 // We used to ignore internal code names, but Apple now uses these internal code names
9587 // even in released shipping products, so we no longer ignore strings containing no commas.
9588 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
9589 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
9590 HINFO_HWstring = HINFO_HWstring_buffer;
9591
9592 // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
9593 // For names of the form "N88AP" containg no comma, we use the entire string.
9594 HINFO_HWstring_prefixlen = strchr(HINFO_HWstring_buffer, ',') ? strcspn(HINFO_HWstring, "0123456789") : strlen(HINFO_HWstring);
9595
9596 if (mDNSPlatformInit_CanReceiveUnicast())
9597 m->CanReceiveUnicastOn5353 = mDNStrue;
9598
9599 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
9600 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
9601 if (hlen + slen < 254)
9602 {
9603 m->HIHardware.c[0] = hlen;
9604 m->HISoftware.c[0] = slen;
9605 mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
9606 mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
9607 }
9608
9609 m->p->permanentsockets.port = MulticastDNSPort;
9610 m->p->permanentsockets.m = m;
9611 m->p->permanentsockets.sktv4 = -1;
9612 m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack;
9613 m->p->permanentsockets.kqsv4.KQcontext = &m->p->permanentsockets;
9614 m->p->permanentsockets.kqsv4.KQtask = "IPv4 UDP packet reception";
9615 m->p->permanentsockets.sktv6 = -1;
9616 m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
9617 m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
9618 m->p->permanentsockets.kqsv6.KQtask = "IPv6 UDP packet reception";
9619
9620 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
9621 if (err) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET) failed error %d errno %d (%s)", err, errno, strerror(errno));
9622 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
9623 if (err) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET6) failed error %d errno %d (%s)", err, errno, strerror(errno));
9624
9625 struct sockaddr_in s4;
9626 socklen_t n4 = sizeof(s4);
9627 if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0)
9628 LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
9629 else
9630 m->UnicastPort4.NotAnInteger = s4.sin_port;
9631
9632 if (m->p->permanentsockets.sktv6 >= 0)
9633 {
9634 struct sockaddr_in6 s6;
9635 socklen_t n6 = sizeof(s6);
9636 if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
9637 else m->UnicastPort6.NotAnInteger = s6.sin6_port;
9638 }
9639
9640 m->p->InterfaceList = mDNSNULL;
9641 m->p->userhostlabel.c[0] = 0;
9642 m->p->usernicelabel.c[0] = 0;
9643 m->p->prevoldnicelabel.c[0] = 0;
9644 m->p->prevnewnicelabel.c[0] = 0;
9645 m->p->prevoldhostlabel.c[0] = 0;
9646 m->p->prevnewhostlabel.c[0] = 0;
9647 m->p->NotifyUser = 0;
9648 m->p->KeyChainTimer = 0;
9649 m->p->WakeAtUTC = 0;
9650 m->p->RequestReSleep = 0;
9651 // Assume that everything is good to begin with. If something is not working,
9652 // we will detect that when we start sending questions.
9653 m->p->v4answers = 1;
9654 m->p->v6answers = 1;
9655 m->p->DNSTrigger = 0;
9656 m->p->LastConfigGeneration = 0;
9657
9658 m->AutoTunnelRelayAddr = zerov6Addr;
9659
9660 NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
9661 NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
9662 NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
9663 NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
9664 NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
9665 NetworkChangedKey_StateInterfacePrefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, CFSTR(""), NULL);
9666 if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS || !NetworkChangedKey_StateInterfacePrefix)
9667 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
9668
9669 err = WatchForNetworkChanges(m);
9670 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
9671
9672 err = WatchForSysEvents(m);
9673 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
9674
9675 mDNSs32 utc = mDNSPlatformUTC();
9676 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
9677 myGetIfAddrs(1);
9678 UpdateInterfaceList(utc);
9679 SetupActiveInterfaces(utc);
9680 ReorderInterfaceList();
9681
9682 // Explicitly ensure that our Keychain operations utilize the system domain.
9683 #ifndef NO_SECURITYFRAMEWORK
9684 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
9685 #endif
9686
9687 mDNS_Lock(m);
9688 SetDomainSecrets(m);
9689 SetLocalDomains();
9690 mDNS_Unlock(m);
9691
9692 #ifndef NO_SECURITYFRAMEWORK
9693 err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
9694 if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
9695 #endif
9696
9697 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
9698 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
9699 #else
9700 IOPMConnection c;
9701 IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
9702 if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
9703 else
9704 {
9705 iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
9706 if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
9707 else
9708 {
9709 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9710 IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue());
9711 LogInfo("IOPMConnectionSetDispatchQueue is now running");
9712 #else
9713 iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
9714 if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
9715 LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
9716 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9717 }
9718 }
9719 m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
9720 if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
9721 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
9722 {
9723 m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
9724 if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
9725 else
9726 {
9727 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9728 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
9729 #else
9730 CFRunLoopAddSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
9731 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9732 }
9733 }
9734
9735 #if APPLE_OSX_mDNSResponder
9736 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
9737 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
9738 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
9739 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
9740 if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9741 else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9742 else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9743 else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
9744 else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; }
9745 else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; }
9746 else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /* 4kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 13W */; }
9747 else if (!strncasecmp(HINFO_HWstring, "AirPort", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 12W */; }
9748 else if ( IsAppleTV() ) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 60 /* 1W */; SPMetricTotalPower = 63 /* 2W */; }
9749 else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
9750 else if (!strncasecmp(HINFO_HWstring, "PowerBook", 9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
9751 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
9752 HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
9753 #endif // APPLE_OSX_mDNSResponder
9754
9755 // Currently this is not defined. SSL code will eventually fix this. If it becomes
9756 // critical, we will define this to workaround the bug in SSL.
9757 #ifdef __SSL_NEEDS_SERIALIZATION__
9758 SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL);
9759 #else
9760 SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
9761 #endif
9762 if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
9763
9764 #if TARGET_OS_IPHONE
9765 // On device OSes (iOS, tvOS, watchOS, etc.), ignore /etc/hosts unless the OS is an internal build. When the /etc/hosts
9766 // file is ignored, LocalOnly auth records will be registered for localhost and broadcasthost addresses contained in the
9767 // standard /etc/hosts file:
9768 //
9769 // 127.0.0.1 localhost
9770 // 255.255.255.255 broadcasthost
9771 // ::1 localhost
9772
9773 if (!IsAppleInternalBuild())
9774 {
9775 const domainname *const localHostName = (const domainname *) "\x9" "localhost";
9776 const domainname *const broadcastHostName = (const domainname *) "\xd" "broadcasthost";
9777 const mDNSv4Addr localHostV4 = { { 127, 0, 0, 1 } };
9778 mDNSv6Addr localHostV6;
9779
9780 // Register localhost 127.0.0.1 A record.
9781
9782 RegisterLocalOnlyARecord(localHostName, &localHostV4);
9783
9784 // Register broadcasthost 255.255.255.255 A record.
9785
9786 RegisterLocalOnlyARecord(broadcastHostName, &onesIPv4Addr);
9787
9788 // Register localhost ::1 AAAA record.
9789
9790 mDNSPlatformMemZero(&localHostV6, sizeof(localHostV6));
9791 localHostV6.b[15] = 1;
9792 RegisterLocalOnlyAAAARecord(localHostName, &localHostV6);
9793 }
9794 else
9795 #endif
9796 {
9797 mDNSMacOSXUpdateEtcHosts(m);
9798 }
9799 SetupLocalHostRecords();
9800
9801 return(mStatus_NoError);
9802 }
9803
9804 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
9805 {
9806 #if MDNS_NO_DNSINFO
9807 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
9808 #endif
9809
9810 // Adding interfaces will use this flag, so set it now.
9811 m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
9812
9813 #if APPLE_OSX_mDNSResponder
9814 m->SPSBrowseCallback = UpdateSPSStatus;
9815 #endif // APPLE_OSX_mDNSResponder
9816
9817 mStatus result = mDNSPlatformInit_setup(m);
9818
9819 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
9820 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
9821 if (result == mStatus_NoError)
9822 {
9823 mDNSCoreInitComplete(m, mStatus_NoError);
9824 initializeD2DPlugins(m);
9825 }
9826 result = DNSSECCryptoInit(m);
9827 return(result);
9828 }
9829
9830 mDNSexport void mDNSPlatformClose(mDNS *const m)
9831 {
9832 if (m->p->PowerConnection)
9833 {
9834 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9835 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);
9836 #else
9837 CFRunLoopRemoveSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
9838 #endif
9839 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
9840 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
9841 IODeregisterForSystemPower(&m->p->PowerNotifier);
9842 IOServiceClose ( m->p->PowerConnection);
9843 IONotificationPortDestroy ( m->p->PowerPortRef);
9844 m->p->PowerConnection = 0;
9845 }
9846
9847 if (m->p->Store)
9848 {
9849 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9850 if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
9851 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
9852 #else
9853 CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode);
9854 CFRunLoopSourceInvalidate(m->p->StoreRLS);
9855 CFRelease(m->p->StoreRLS);
9856 m->p->StoreRLS = NULL;
9857 #endif
9858 CFRelease(m->p->Store);
9859 m->p->Store = NULL;
9860 }
9861
9862 if (m->p->PMRLS)
9863 {
9864 CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->PMRLS, kCFRunLoopDefaultMode);
9865 CFRunLoopSourceInvalidate(m->p->PMRLS);
9866 CFRelease(m->p->PMRLS);
9867 m->p->PMRLS = NULL;
9868 }
9869
9870 if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
9871
9872 terminateD2DPlugins();
9873
9874 mDNSs32 utc = mDNSPlatformUTC();
9875 MarkAllInterfacesInactive(utc);
9876 ClearInactiveInterfaces(utc);
9877 CloseSocketSet(&m->p->permanentsockets);
9878
9879 #if APPLE_OSX_mDNSResponder
9880 // clean up tunnels
9881 while (m->TunnelClients)
9882 {
9883 ClientTunnel *cur = m->TunnelClients;
9884 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
9885 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
9886 AutoTunnelSetKeys(cur, mDNSfalse);
9887 m->TunnelClients = cur->next;
9888 freeL("ClientTunnel", cur);
9889 }
9890
9891 if (AnonymousRacoonConfig)
9892 {
9893 AnonymousRacoonConfig = mDNSNULL;
9894 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel need not be done in mDNSResponder");
9895 }
9896 #endif // APPLE_OSX_mDNSResponder
9897 }
9898
9899 #if COMPILER_LIKES_PRAGMA_MARK
9900 #pragma mark -
9901 #pragma mark - General Platform Support Layer functions
9902 #endif
9903
9904 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
9905 {
9906 return(arc4random());
9907 }
9908
9909 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
9910 mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
9911
9912 mDNSexport mStatus mDNSPlatformTimeInit(void)
9913 {
9914 // Notes: Typical values for mach_timebase_info:
9915 // tbi.numer = 1000 million
9916 // tbi.denom = 33 million
9917 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
9918 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
9919 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
9920 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
9921 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
9922 //
9923 // Arithmetic notes:
9924 // tbi.denom is at least 1, and not more than 2^32-1.
9925 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
9926 // tbi.denom is at least 1, and not more than 2^32-1.
9927 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
9928 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
9929 // which is unlikely on any current or future Macintosh.
9930 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
9931 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
9932 struct mach_timebase_info tbi;
9933 kern_return_t result = mach_timebase_info(&tbi);
9934 if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
9935 return(result);
9936 }
9937
9938 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
9939 {
9940 if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
9941
9942 static uint64_t last_mach_absolute_time = 0;
9943 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
9944 uint64_t this_mach_absolute_time = mach_absolute_time();
9945 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
9946 {
9947 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
9948 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
9949 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
9950 last_mach_absolute_time = this_mach_absolute_time;
9951 // Note: This bug happens all the time on 10.3
9952 NotifyOfElusiveBug("mach_absolute_time went backwards!",
9953 "This error occurs from time to time, often on newly released hardware, "
9954 "and usually the exact cause is different in each instance.\r\r"
9955 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
9956 "and assign it to Radar Component “Kernel” Version “X”.");
9957 }
9958 last_mach_absolute_time = this_mach_absolute_time;
9959
9960 return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
9961 }
9962
9963 mDNSexport mDNSs32 mDNSPlatformUTC(void)
9964 {
9965 return time(NULL);
9966 }
9967
9968 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
9969 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
9970 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
9971 mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (const char *)src); }
9972 mDNSexport mDNSu32 mDNSPlatformStrLCopy( void *dst, const void *src, mDNSu32 dstlen) { return (strlcpy((char *)dst, (const char *)src, dstlen)); }
9973 mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((const char*)src)); }
9974 mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
9975 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
9976 mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); }
9977 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); }
9978 mDNSexport void mDNSPlatformQsort ( void *base, int nel, int width, int (*compar)(const void *, const void *))
9979 {
9980 return (qsort(base, nel, width, compar));
9981 }
9982 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
9983 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
9984 #endif
9985 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
9986
9987 mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason)
9988 {
9989 mDNS *const m = &mDNSStorage;
9990 if (allowSleep && m->p->IOPMAssertion)
9991 {
9992 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
9993 IOPMAssertionRelease(m->p->IOPMAssertion);
9994 m->p->IOPMAssertion = 0;
9995 }
9996 else if (!allowSleep)
9997 {
9998 #ifdef kIOPMAssertionTypeNoIdleSleep
9999 if (m->p->IOPMAssertion)
10000 {
10001 IOPMAssertionRelease(m->p->IOPMAssertion);
10002 m->p->IOPMAssertion = 0;
10003 }
10004
10005 CFStringRef assertionName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%d %s"), getprogname(), getpid(), reason ? reason : "");
10006 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, assertionName ? assertionName : CFSTR("mDNSResponder"), &m->p->IOPMAssertion);
10007 if (assertionName) CFRelease(assertionName);
10008 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__);
10009 #endif
10010 }
10011 }
10012
10013 mDNSexport void mDNSPlatformPreventSleep(mDNSu32 timeout, const char *reason)
10014 {
10015 mDNS *const m = &mDNSStorage;
10016 if (m->p->IOPMAssertion)
10017 {
10018 LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout, reason);
10019 return;
10020 }
10021 #ifdef kIOPMAssertionTypeNoIdleSleep
10022
10023 #if TARGET_OS_EMBEDDED
10024 if (!IsAppleTV())
10025 return; // No need for maintenance wakes on non-AppleTV embedded devices.
10026 #endif
10027
10028 double timeoutVal = (double)timeout;
10029 CFStringRef str = CFStringCreateWithCString(NULL, reason, kCFStringEncodingUTF8);
10030 CFNumberRef Timeout_num = CFNumberCreate(NULL, kCFNumberDoubleType, &timeoutVal);
10031 CFMutableDictionaryRef assertionProperties = CFDictionaryCreateMutable(NULL, 0,
10032 &kCFTypeDictionaryKeyCallBacks,
10033 &kCFTypeDictionaryValueCallBacks);
10034 if (IsAppleTV())
10035 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertPreventUserIdleSystemSleep);
10036 else
10037 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertMaintenanceActivity);
10038
10039 CFDictionarySetValue(assertionProperties, kIOPMAssertionTimeoutKey, Timeout_num);
10040 CFDictionarySetValue(assertionProperties, kIOPMAssertionNameKey, str);
10041
10042 IOPMAssertionCreateWithProperties(assertionProperties, (IOPMAssertionID *)&m->p->IOPMAssertion);
10043 CFRelease(str);
10044 CFRelease(Timeout_num);
10045 CFRelease(assertionProperties);
10046 LogSPS("Got an idle sleep assertion for %d seconds for %s", timeout, reason);
10047 #endif
10048 }
10049
10050 mDNSexport void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
10051 {
10052 mDNSu32 ifindex;
10053
10054 // Sanity check
10055 ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, InterfaceID, mDNStrue);
10056 if (ifindex <= 0)
10057 {
10058 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
10059 return;
10060 }
10061 mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration);
10062 }
10063
10064 mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
10065 {
10066 NetworkInterfaceInfoOSX *info;
10067
10068 if (InterfaceID == mDNSInterface_P2P)
10069 return mDNStrue;
10070
10071 // mDNSInterface_BLE not considered a D2D interface for the purpose of this
10072 // routine, since it's not implemented via a D2D plugin.
10073 if (InterfaceID == mDNSInterface_BLE)
10074 return mDNSfalse;
10075
10076 if ( (InterfaceID == mDNSInterface_Any)
10077 || (InterfaceID == mDNSInterfaceMark)
10078 || (InterfaceID == mDNSInterface_LocalOnly)
10079 || (InterfaceID == mDNSInterface_Unicast))
10080 return mDNSfalse;
10081
10082 // Compare to cached AWDL interface ID.
10083 if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
10084 return mDNStrue;
10085
10086 info = IfindexToInterfaceInfoOSX(InterfaceID);
10087 if (info == NULL)
10088 {
10089 // this log message can print when operations are stopped on an interface that has gone away
10090 LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID);
10091 return mDNSfalse;
10092 }
10093
10094 return (mDNSBool) info->D2DInterface;
10095 }
10096
10097 // Filter records send over P2P (D2D) type interfaces
10098 // Note that the terms P2P and D2D are used synonymously in the current code and comments.
10099 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
10100 {
10101 // For an explicit match to a valid interface ID, return true.
10102 if (rr->resrec.InterfaceID == InterfaceID)
10103 return mDNStrue;
10104
10105 // Only filtering records for D2D type interfaces, return true for all other interface types.
10106 if (!mDNSPlatformInterfaceIsD2D(InterfaceID))
10107 return mDNStrue;
10108
10109 // If it's an AWDL interface the record must be explicitly marked to include AWDL.
10110 if (InterfaceID == AWDLInterfaceID)
10111 {
10112 if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10113 return mDNStrue;
10114 else
10115 return mDNSfalse;
10116 }
10117
10118 // Send record if it is explicitly marked to include all other P2P type interfaces.
10119 if (rr->ARType == AuthRecordAnyIncludeP2P || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10120 return mDNStrue;
10121
10122 // Don't send the record over this interface.
10123 return mDNSfalse;
10124 }
10125
10126 // Filter questions send over P2P (D2D) type interfaces.
10127 mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
10128 {
10129 // For an explicit match to a valid interface ID, return true.
10130 if (q->InterfaceID == intf->InterfaceID)
10131 return mDNStrue;
10132
10133 // Only filtering questions for D2D type interfaces
10134 if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
10135 return mDNStrue;
10136
10137 // If it's an AWDL interface the question must be explicitly marked to include AWDL.
10138 if (intf->InterfaceID == AWDLInterfaceID)
10139 {
10140 if (q->flags & kDNSServiceFlagsIncludeAWDL)
10141 return mDNStrue;
10142 else
10143 return mDNSfalse;
10144 }
10145
10146 // Sent question if it is explicitly marked to include all other P2P type interfaces.
10147 if (q->flags & kDNSServiceFlagsIncludeP2P)
10148 return mDNStrue;
10149
10150 // Don't send the question over this interface.
10151 return mDNSfalse;
10152 }
10153
10154 // Returns true unless record was received over the AWDL interface and
10155 // the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
10156 // with the kDNSServiceFlagsIncludeAWDL flag set.
10157 mDNSexport mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
10158 {
10159 if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID))
10160 return mDNStrue;
10161
10162 if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL))
10163 return mDNSfalse;
10164
10165 return mDNStrue;
10166 }
10167
10168 // formating time to RFC 4034 format
10169 mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
10170 {
10171 struct tm tmTime;
10172 time_t t = (time_t)te;
10173 // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
10174 // gmtime_r first and then use strftime
10175 gmtime_r(&t, &tmTime);
10176 strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
10177 }
10178
10179 mDNSexport mDNSs32 mDNSPlatformGetPID()
10180 {
10181 return getpid();
10182 }
10183
10184 // Schedule a function asynchronously on the main queue
10185 mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func)
10186 {
10187 // KQueueLock/Unlock is used for two purposes
10188 //
10189 // 1. We can't be running along with the KQueue thread and hence acquiring the lock
10190 // serializes the access to the "core"
10191 //
10192 // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
10193 // up and calls udsserver_idle which schedules the messages across the uds socket.
10194 // If "func" delivers something to the uds socket from the dispatch thread, it will
10195 // not be delivered immediately if not for the Unlock.
10196 dispatch_async(dispatch_get_main_queue(), ^{
10197 KQueueLock();
10198 func(m, context);
10199 KQueueUnlock("mDNSPlatformDispatchAsync");
10200 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10201 // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
10202 // to handle any message that "func" might deliver.
10203 TriggerEventCompletion();
10204 #endif
10205 });
10206 }
10207
10208 // definitions for device-info record construction
10209 #define DEVINFO_MODEL "model="
10210 #define DEVINFO_MODEL_LEN sizeof_string(DEVINFO_MODEL)
10211
10212 #define OSX_VER "osxvers="
10213 #define OSX_VER_LEN sizeof_string(OSX_VER)
10214 #define VER_NUM_LEN 2 // 2 digits of version number added to base string
10215
10216 #define MODEL_COLOR "ecolor="
10217 #define MODEL_COLOR_LEN sizeof_string(MODEL_COLOR)
10218 #define MODEL_RGB_VALUE_LEN sizeof_string("255,255,255") // 'r,g,b'
10219
10220 // Bytes available in TXT record for model name after subtracting space for other
10221 // fixed size strings and their length bytes.
10222 #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))
10223
10224 mDNSlocal mDNSu8 getModelIconColors(char *color)
10225 {
10226 mDNSPlatformMemZero(color, MODEL_RGB_VALUE_LEN + 1);
10227
10228 #if !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10229 mDNSu8 red = 0;
10230 mDNSu8 green = 0;
10231 mDNSu8 blue = 0;
10232
10233 IOReturn rGetDeviceColor = IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey,
10234 &red, &green, &blue);
10235 if (kIOReturnSuccess == rGetDeviceColor)
10236 {
10237 // IOKit was able to get enclosure color for the current device.
10238 return snprintf(color, MODEL_RGB_VALUE_LEN + 1, "%d,%d,%d", red, green, blue);
10239 }
10240 #endif // !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10241
10242 return 0;
10243 }
10244
10245
10246 // Initialize device-info TXT record contents and return total length of record data.
10247 mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
10248 {
10249 mDNSu8 *bufferStart = ptr;
10250 mDNSu8 len = m->HIHardware.c[0] < MAX_MODEL_NAME_LEN ? m->HIHardware.c[0] : MAX_MODEL_NAME_LEN;
10251
10252 *ptr = DEVINFO_MODEL_LEN + len; // total length of DEVINFO_MODEL string plus the hardware name string
10253 ptr++;
10254 mDNSPlatformMemCopy(ptr, DEVINFO_MODEL, DEVINFO_MODEL_LEN);
10255 ptr += DEVINFO_MODEL_LEN;
10256 mDNSPlatformMemCopy(ptr, m->HIHardware.c + 1, len);
10257 ptr += len;
10258
10259 // only include this string for OSX
10260 if (OSXVers)
10261 {
10262 char ver_num[VER_NUM_LEN + 1]; // version digits + null written by snprintf
10263 *ptr = OSX_VER_LEN + VER_NUM_LEN; // length byte
10264 ptr++;
10265 mDNSPlatformMemCopy(ptr, OSX_VER, OSX_VER_LEN);
10266 ptr += OSX_VER_LEN;
10267 // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
10268 // WARNING: This code assumes that OSXVers is always exactly two digits
10269 snprintf(ver_num, VER_NUM_LEN + 1, "%d", OSXVers);
10270 mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN);
10271 ptr += VER_NUM_LEN;
10272
10273 char rgb[MODEL_RGB_VALUE_LEN + 1]; // RGB value + null written by snprintf
10274 len = getModelIconColors(rgb);
10275 if (len)
10276 {
10277 *ptr = MODEL_COLOR_LEN + len; // length byte
10278 ptr++;
10279
10280 mDNSPlatformMemCopy(ptr, MODEL_COLOR, MODEL_COLOR_LEN);
10281 ptr += MODEL_COLOR_LEN;
10282
10283 mDNSPlatformMemCopy(ptr, rgb, len);
10284 ptr += len;
10285 }
10286 }
10287
10288 return (ptr - bufferStart);
10289 }
10290
10291 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
10292
10293 // Use the scalar version of SameDomainLabel() by default
10294 mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
10295 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
10296 mDNSlocal mDNSBool (*SameDomainLabelPointer)(const mDNSu8 *a, const mDNSu8 *b) = scalarSameDomainLabel;
10297
10298 #include <System/machine/cpu_capabilities.h>
10299 #define _cpu_capabilities ((uint32_t*) _COMM_PAGE_CPU_CAPABILITIES)[0]
10300
10301 #if TARGET_OS_EMBEDDED
10302
10303 #include <arm_neon.h>
10304
10305 // Cache line aligned table that returns 32 for the upper case letters.
10306 // This will take up 4 cache lines.
10307 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table[256] = {
10308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10312 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
10313 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10318 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 };
10325
10326 // Neon version
10327 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10328 {
10329 const int len = *a++;
10330
10331 if (len > MAX_DOMAIN_LABEL)
10332 {
10333 fprintf(stderr, "v: Malformed label (too long)\n");
10334 return(mDNSfalse);
10335 }
10336
10337 if (len != *b++)
10338 {
10339 return(mDNSfalse);
10340 }
10341
10342 uint32_t len_count = len;
10343
10344 uint8x16_t vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
10345
10346 uint8x16_t v32 = vdupq_n_u8(32);
10347 uint8x16_t v37 = vdupq_n_u8(37);
10348 uint8x16_t v101 = vdupq_n_u8(101);
10349 #if !defined __arm64__
10350 uint32x4_t vtemp32;
10351 uint32x2_t vtemp32d;
10352 uint32_t sum;
10353 #endif
10354
10355 while(len_count > 15)
10356 {
10357 vA = vld1q_u8(a);
10358 vB = vld1q_u8(b);
10359 a += 16;
10360 b += 16;
10361
10362 //Make vA to lowercase if there is any uppercase.
10363 vARotated = vaddq_u8(vA, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10364 vMaskA = vcgtq_s8(vARotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10365 vMaskA = vandq_u8(vMaskA, v32); //Prepare 32 for the elements with uppercase letters.
10366 vA = vaddq_u8(vA, vMaskA); //Add 32 only to the uppercase letters to make them lowercase letters.
10367
10368 //Make vB to lowercase if there is any uppercase.
10369 vBRotated = vaddq_u8(vB, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10370 vMaskB = vcgtq_s8(vBRotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10371 vMaskB = vandq_u8(vMaskB, v32); //Prepare 32 for the elements with uppercase letters.
10372 vB = vaddq_u8(vB, vMaskB); //Add 32 only to the uppercase letters to make them lowercase letters.
10373
10374 //Compare vA & vB
10375 vA = vceqq_u8(vA, vB);
10376
10377 #if defined __arm64__
10378 //View 8-bit element as 32-bit => a3 a2 a1 a0
10379 //If min of 4 32-bit values in vA is 0xffffffff, then it means we have 0xff for all 16.
10380 if(vminvq_u32(vA) != 0xffffffffU)
10381 {
10382 return(mDNSfalse);
10383
10384 }
10385 #else
10386 //See if any element was not same.
10387 //View 8-bit element as 16-bit => a7 a6 a5 a4 a3 a2 a1 a0
10388 //(a7+a6) (a5+a4) (a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
10389 vtemp32 = vpaddlq_u16(vA);
10390 vtemp32d = vpadd_u32(vget_low_u32(vtemp32), vget_high_u32(vtemp32));
10391 vtemp32d = vpadd_u32(vtemp32d, vtemp32d);
10392 sum = vget_lane_u32(vtemp32d, 0);
10393
10394 //0x0001fffe + 0x0001fffe + 0x0001fffe + 0x0001fffe = 0x0007fff8U when all same.
10395 if(sum != 0x0007fff8U)
10396 {
10397 return(mDNSfalse);
10398 }
10399 #endif
10400
10401 len_count -= 16;
10402 }
10403
10404 uint8x8_t vAd, vBd, vARotatedd, vBRotatedd, vMaskAd, vMaskBd;
10405
10406 uint8x8_t v32d = vdup_n_u8(32);
10407 uint8x8_t v37d = vdup_n_u8(37);
10408 uint8x8_t v101d = vdup_n_u8(101);
10409
10410 while(len_count > 7)
10411 {
10412 vAd = vld1_u8(a);
10413 vBd = vld1_u8(b);
10414 a += 8;
10415 b += 8;
10416
10417 //Make vA to lowercase if there is any uppercase.
10418 vARotatedd = vadd_u8(vAd, v37d); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10419 vMaskAd = vcgt_s8(vARotatedd, v101d); //Check if anything is greater than '101' which means we have uppercase letters.
10420 vMaskAd = vand_u8(vMaskAd, v32d); //Prepare 32 for the elements with uppercase letters.
10421 vAd = vadd_u8(vAd, vMaskAd); //Add 32 only to the uppercase letters to make them lowercase letters.
10422
10423 //Make vB to lowercase if there is any uppercase.
10424 vBRotatedd = vadd_u8(vBd, v37d); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10425 vMaskBd = vcgt_s8(vBRotatedd, v101d); //Check if anything is greater than '101' which means we have uppercase letters.
10426 vMaskBd = vand_u8(vMaskBd, v32d); //Prepare 32 for the elements with uppercase letters.
10427 vBd = vadd_u8(vBd, vMaskBd); //Add 32 only to the uppercase letters to make them lowercase letters.
10428
10429 //Compare vA & vB
10430 vAd = vceq_u8(vAd, vBd);
10431
10432 #if defined __arm64__
10433 //View 8-bit element as 32-bit => a1 a0
10434 //If min of 2 32-bit values in vAd is 0xffffffff, then it means we have 0xff for all 16.
10435 if(vminv_u32(vAd) != 0xffffffffU)
10436 {
10437 return(mDNSfalse);
10438
10439 }
10440 #else
10441 //See if any element was not same.
10442 //View 8-bit element as 16-bit => a3 a2 a1 a0
10443 //(a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
10444 vtemp32d = vpaddl_u16(vAd);
10445 vtemp32d = vpadd_u32(vtemp32d, vtemp32d);
10446 sum = vget_lane_u32(vtemp32d, 0);
10447
10448 //0x0001fffe + 0x0001fffe = 0x0003fffc when all same.
10449 if(sum != 0x0003fffcU)
10450 {
10451 return(mDNSfalse);
10452 }
10453 #endif
10454
10455 len_count -= 8;
10456 }
10457
10458 while(len_count > 0)
10459 {
10460 mDNSu8 ac = *a++;
10461 mDNSu8 bc = *b++;
10462
10463 ac += upper_to_lower_case_table[ac];
10464 bc += upper_to_lower_case_table[bc];
10465
10466 if (ac != bc)
10467 {
10468 return(mDNSfalse);
10469 }
10470
10471 len_count -= 1;
10472 }
10473 return(mDNStrue);
10474 }
10475
10476 // Use vectorized implementation if it is supported on this platform.
10477 mDNSlocal void setSameDomainLabelPointer(void)
10478 {
10479 if(_cpu_capabilities & kHasNeon)
10480 {
10481 // Use Neon Code
10482 SameDomainLabelPointer = vectorSameDomainLabel;
10483 LogMsg("setSameDomainLabelPointer: using vector code");
10484 }
10485 else
10486 LogMsg("setSameDomainLabelPointer: using scalar code");
10487 }
10488
10489 #else // TARGET_OS_EMBEDDED
10490
10491 #include <smmintrin.h>
10492
10493 // Cache line aligned table that returns 32 for the upper case letters.
10494 // This will take up 4 cache lines.
10495 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table[256] = {
10496 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10497 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10498 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10499 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10500 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
10501 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10506 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 };
10513
10514 // SSE2 version
10515 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10516 {
10517 const int len = *a++;
10518
10519 if (len > MAX_DOMAIN_LABEL)
10520 {
10521 fprintf(stderr, "v: Malformed label (too long)\n");
10522 return(mDNSfalse);
10523 }
10524
10525 if (len != *b++)
10526 {
10527 return(mDNSfalse);
10528 }
10529
10530 uint32_t len_count = len;
10531
10532 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 };
10533 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 };
10534 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 };
10535 __m128i v37 = _mm_load_si128((__m128i*)c_37);
10536 __m128i v101 = _mm_load_si128((__m128i*)c_101);
10537 __m128i v32 = _mm_load_si128((__m128i*)c_32);
10538
10539 uint32_t is_equal;
10540 __m128i vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
10541
10542 //AVX code that uses higher bandwidth (more elements per vector) was removed
10543 //to speed up the processing on the small sizes.
10544 //When I had them, the performance of 1 ~ 8 characters were slower by about 10% ~ 30%.
10545 while(len_count > 15)
10546 {
10547 vA = _mm_loadu_si128((__m128i*)a);
10548 vB = _mm_loadu_si128((__m128i*)b);
10549 a += 16;
10550 b += 16;
10551
10552 //Make vA to lowercase if there is any uppercase.
10553 vARotated = _mm_add_epi8(vA, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10554 vMaskA = _mm_cmpgt_epi8(vARotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10555 vMaskA = _mm_and_si128(vMaskA, v32); //Prepare 32 for the elements with uppercase letters.
10556 vA = _mm_add_epi8(vA, vMaskA); //Add 32 only to the uppercase letters to make them lowercase letters.
10557
10558 //Make vB to lowercase if there is any uppercase.
10559 vBRotated = _mm_add_epi8(vB, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10560 vMaskB = _mm_cmpgt_epi8(vBRotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
10561 vMaskB = _mm_and_si128(vMaskB, v32); //Prepare 32 for the elements with uppercase letters.
10562 vB = _mm_add_epi8(vB, vMaskB); //Add 32 only to the uppercase letters to make them lowercase letters.
10563
10564 //Compare vA & vB
10565 vA = _mm_cmpeq_epi8(vA, vB);
10566
10567 //Return if any different.
10568 is_equal = _mm_movemask_epi8(vA);
10569 is_equal = is_equal & 0xffff;
10570 if(is_equal != 0xffff)
10571 {
10572 return(mDNSfalse);
10573 }
10574
10575 len_count -= 16;
10576 }
10577
10578 while(len_count > 0)
10579 {
10580 mDNSu8 ac = *a++;
10581 mDNSu8 bc = *b++;
10582
10583 //Table will return 32 for upper case letters only.
10584 //0 will be returned for all others.
10585 ac += upper_to_lower_case_table[ac];
10586 bc += upper_to_lower_case_table[bc];
10587
10588 //Return if a & b are different.
10589 if (ac != bc)
10590 {
10591 return(mDNSfalse);
10592 }
10593
10594 len_count -= 1;
10595 }
10596 return(mDNStrue);
10597 }
10598
10599 // Use vectorized implementation if it is supported on this platform.
10600 mDNSlocal void setSameDomainLabelPointer(void)
10601 {
10602 if(_cpu_capabilities & kHasSSE4_1)
10603 {
10604 // Use SSE Code
10605 SameDomainLabelPointer = vectorSameDomainLabel;
10606 LogMsg("setSameDomainLabelPointer: using vector code");
10607 }
10608 else
10609 LogMsg("setSameDomainLabelPointer: using scalar code");
10610 }
10611
10612 #endif // TARGET_OS_EMBEDDED
10613
10614 // Original SameDomainLabel() implementation.
10615 mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10616 {
10617 int i;
10618 const int len = *a++;
10619
10620 if (len > MAX_DOMAIN_LABEL)
10621 { debugf("Malformed label (too long)"); return(mDNSfalse); }
10622
10623 if (len != *b++) return(mDNSfalse);
10624 for (i=0; i<len; i++)
10625 {
10626 mDNSu8 ac = *a++;
10627 mDNSu8 bc = *b++;
10628 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
10629 if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
10630 if (ac != bc) return(mDNSfalse);
10631 }
10632 return(mDNStrue);
10633 }
10634
10635 mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
10636 {
10637 return (*SameDomainLabelPointer)(a, b);
10638 }
10639
10640 #endif // APPLE_OSX_mDNSResponder
10641
10642
10643 #ifdef UNIT_TEST
10644 #include "../unittests/mdns_macosx_ut.c"
10645 #endif
10646