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