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