1 /* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
3 * Copyright (c) 2002-2020 Apple Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 // ***************************************************************************
20 // Supporting routines to run mDNS on a CFRunLoop platform
21 // ***************************************************************************
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
27 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
28 #include "DNSCommon.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"
38 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
39 #include "mdns_trust.h"
40 #include <os/feature_private.h>
44 #include <stdarg.h> // For va_list support
45 #include <stdlib.h> // For arc4random
47 #include <net/if_types.h> // For IFT_ETHER
48 #include <net/if_dl.h>
49 #include <net/bpf.h> // For BIOCSETIF etc.
51 #include <sys/param.h>
52 #include <sys/socket.h>
53 #include <sys/sysctl.h>
54 #include <sys/event.h>
56 #include <sys/ioctl.h>
57 #include <time.h> // platform support for UTC time
58 #include <arpa/inet.h> // for inet_aton
60 #include <netdb.h> // for getaddrinfo
61 #include <sys/sockio.h> // for SIOCGIFEFLAGS
63 #include <netinet/in.h> // For IP_RECVTTL
65 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
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.
72 #include <netinet/tcp.h>
74 #include <DebugServices.h>
79 #include <IOKit/IOKitLib.h>
80 #include <IOKit/IOMessage.h>
82 #include <IOKit/ps/IOPowerSources.h>
83 #include <IOKit/ps/IOPowerSourcesPrivate.h>
84 #include <IOKit/ps/IOPSKeys.h>
86 #include <mach/mach_error.h>
87 #include <mach/mach_port.h>
88 #include <mach/mach_time.h>
90 #include "P2PPacketFilter.h"
92 #include <SystemConfiguration/SCPrivate.h>
94 #if (TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST)
95 #include <MobileWiFi/WiFiManagerClient.h> // For WiFiManagerClientRef etc, declarations.
97 #endif // TARGET_OS_IPHONE
99 #include "system_utilities.h"
101 // Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
102 #include <Kernel/IOKit/apple80211/apple80211_var.h>
104 #if APPLE_OSX_mDNSResponder
105 #include <ne_session.h> // for ne_session_set_socket_attributes()
108 #if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
109 #include <IOKit/platform/IOPlatformSupportPrivate.h>
112 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
113 #include "QuerierSupport.h"
117 #include "unittest.h"
120 #define kInterfaceSpecificOption "interface="
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'
127 #define DARK_WAKE_TIME 16 // Time we hold an idle sleep assertion for maintenance after a wake notification
129 // cache the InterfaceID of the AWDL interface
130 mDNSInterfaceID AWDLInterfaceID
;
132 // ***************************************************************************
135 #if COMPILER_LIKES_PRAGMA_MARK
136 #pragma mark - Globals
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
147 mDNSexport
int OSXVers
, iOSVers
;
148 mDNSexport
int KQueueFD
;
150 #ifndef NO_SECURITYFRAMEWORK
151 static CFArrayRef ServerCerts
;
152 OSStatus
SSLSetAllowAnonymousCiphers(SSLContextRef context
, Boolean enable
);
153 #endif /* NO_SECURITYFRAMEWORK */
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");
164 static char HINFO_HWstring_buffer
[32];
165 static char *HINFO_HWstring
= "Device";
166 static int HINFO_HWstring_prefixlen
= 6;
168 mDNSexport
int WatchDogReportingThreshold
= 250;
170 dispatch_queue_t SSLqueue
;
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
179 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
180 domainname ActiveDirectoryPrimaryDomain
;
181 static int ActiveDirectoryPrimaryDomainLabelCount
;
182 static mDNSAddr ActiveDirectoryPrimaryDomainServer
;
185 // Don't send triggers too often. We arbitrarily limit it to three minutes.
186 #define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
188 const char dnsprefix
[] = "dns:";
190 // String Array used to write list of private domains to Dynamic Store
191 static CFArrayRef privateDnsArray
= NULL
;
193 // ***************************************************************************
196 #if COMPILER_LIKES_PRAGMA_MARK
198 #pragma mark - Utility Functions
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.
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))
211 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
213 #define SPSInterface(i) ((i)->ifinfo.McastTxRx && !((i)->ifa_flags & IFF_LOOPBACK) && !(i)->D2DInterface)
215 mDNSlocal
void SetNetworkChanged(mDNSs32 delay
);
217 mDNSexport
void NotifyOfElusiveBug(const char *title
, const char *msg
) // Both strings are UTF-8 text
219 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
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)
228 return; // If not at Apple, don't show the alert
232 LogMsg("NotifyOfElusiveBug: %s", title
);
233 LogMsg("NotifyOfElusiveBug: %s", msg
);
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))
239 LogMsg("Suppressing notification early in boot: %d", mDNSPlatformRawTime());
243 #ifndef NO_CFUSERNOTIFICATION
244 static int notifyCount
= 0; // To guard against excessive display of warning notifications
248 mDNSNotify(title
, msg
);
250 #endif /* NO_CFUSERNOTIFICATION */
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
, ...)
260 va_start(ptr
,format
);
261 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
263 LogMsg("!!!! %s !!!!", buffer
);
264 NotifyOfElusiveBug("Memory Corruption", buffer
);
266 *(volatile long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
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
, ...)
277 va_start(ptr
,format
);
278 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
280 LogMsg("!!!! %s !!!!", buffer
);
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
288 // Returns true if it is an AppleTV based hardware running iOS, false otherwise
289 mDNSlocal mDNSBool
IsAppleTV(void)
298 mDNSlocal
struct ifaddrs
*myGetIfAddrs(int refresh
)
300 static struct ifaddrs
*ifa
= NULL
;
313 mDNSlocal
void DynamicStoreWrite(int key
, const char* subkey
, uintptr_t value
, signed long valueCnt
)
315 CFStringRef sckey
= NULL
;
316 Boolean release_sckey
= FALSE
;
317 CFDataRef bytes
= NULL
;
318 CFPropertyListRef plist
= NULL
;
320 switch ((enum mDNSDynamicStoreSetConfigKey
)key
)
322 case kmDNSMulticastConfig
:
323 sckey
= CFSTR("State:/Network/" kDNSServiceCompMulticastDNS
);
325 case kmDNSDynamicConfig
:
326 sckey
= CFSTR("State:/Network/DynamicDNS");
328 case kmDNSPrivateConfig
:
329 sckey
= CFSTR("State:/Network/" kDNSServiceCompPrivateDNS
);
331 case kmDNSBackToMyMacConfig
:
332 sckey
= CFSTR("State:/Network/BackToMyMac");
334 case kmDNSSleepProxyServersState
:
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
;
345 case kmDNSDebugState
:
346 sckey
= CFSTR("State:/Network/mDNSResponder/DebugState");
349 LogMsg("unrecognized key %d", key
);
352 if (NULL
== (bytes
= CFDataCreateWithBytesNoCopy(NULL
, (void *)value
,
353 valueCnt
, kCFAllocatorNull
)))
355 LogMsg("CFDataCreateWithBytesNoCopy of value failed");
358 if (NULL
== (plist
= CFPropertyListCreateWithData(NULL
, bytes
, kCFPropertyListImmutable
, NULL
, NULL
)))
360 LogMsg("CFPropertyListCreateWithData of bytes failed");
365 SCDynamicStoreSetValue(NULL
, sckey
, plist
);
372 if (release_sckey
&& sckey
)
376 mDNSexport
void mDNSDynamicStoreSetConfig(int key
, const char *subkey
, CFPropertyListRef value
)
378 CFPropertyListRef valueCopy
;
379 char *subkeyCopy
= NULL
;
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
);
388 LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
393 const mDNSu32 len
= (mDNSu32
)strlen(subkey
);
394 subkeyCopy
= mDNSPlatformMemAllocate(len
+ 1);
397 LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
398 CFRelease(valueCopy
);
401 mDNSPlatformMemCopy(subkeyCopy
, subkey
, len
);
405 dispatch_async(dispatch_get_main_queue(), ^{
406 CFWriteStreamRef stream
= NULL
;
407 CFDataRef bytes
= NULL
;
411 if (NULL
== (stream
= CFWriteStreamCreateWithAllocatedBuffers(NULL
, NULL
)))
413 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
416 CFWriteStreamOpen(stream
);
417 ret
= CFPropertyListWrite(valueCopy
, stream
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
420 LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
423 if (NULL
== (bytes
= CFWriteStreamCopyProperty(stream
, kCFStreamPropertyDataWritten
)))
425 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
428 CFWriteStreamClose(stream
);
431 DynamicStoreWrite(key
, subkeyCopy
? subkeyCopy
: "", (uintptr_t)CFDataGetBytePtr(bytes
), CFDataGetLength(bytes
));
434 CFRelease(valueCopy
);
437 CFWriteStreamClose(stream
);
443 mDNSPlatformMemFree(subkeyCopy
);
445 KQueueUnlock("mDNSDynamicStoreSetConfig");
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
)
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
);
461 mDNSlocal
int myIfIndexToName(u_short ifindex
, char *name
)
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; }
471 mDNSexport NetworkInterfaceInfoOSX
*IfindexToInterfaceInfoOSX(mDNSInterfaceID ifindex
)
473 mDNS
*const m
= &mDNSStorage
;
474 mDNSu32 scope_id
= (mDNSu32
)(uintptr_t)ifindex
;
475 NetworkInterfaceInfoOSX
*i
;
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
);
484 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
485 mDNSexport mdns_interface_monitor_t
GetInterfaceMonitorForIndex(uint32_t ifIndex
)
487 mDNS
*const m
= &mDNSStorage
;
489 // We assume that interface should always be real interface, and should never be 0.
490 if (ifIndex
== 0) return NULL
;
492 if (!m
->p
->InterfaceMonitors
)
494 m
->p
->InterfaceMonitors
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &mdns_cfarray_callbacks
);
495 if (!m
->p
->InterfaceMonitors
)
497 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_ERROR
, "Failed to create InterfaceMonitors array");
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
++)
506 monitor
= (mdns_interface_monitor_t
) CFArrayGetValueAtIndex(m
->p
->InterfaceMonitors
, i
);
507 if (mdns_interface_monitor_get_interface_index(monitor
) == ifIndex
) return monitor
;
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
);
514 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_ERROR
, "Failed to create an interface monitor for index %u", ifIndex
);
517 CFArrayAppendValue(m
->p
->InterfaceMonitors
, monitor
);
519 // Put the monitor into serial queue.
520 mdns_interface_monitor_set_queue(monitor
, dispatch_get_main_queue());
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
)
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;
533 const CFRange range
= CFRangeMake(0, CFArrayGetCount(m
->p
->InterfaceMonitors
));
534 if (CFArrayContainsValue(m
->p
->InterfaceMonitors
, range
, monitor
))
536 m
->p
->if_interface_changed
= mDNStrue
;
538 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
539 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
, "Monitored interface changed: %@", monitor
);
541 // Let mDNSResponder update its network configuration.
543 SetNetworkChanged((mDNSPlatformOneSecond
+ 39) / 40); // 25 ms delay
546 KQueueUnlock("interface monitor update handler");
549 mdns_interface_monitor_set_event_handler(monitor
,
550 ^(mdns_event_t event
, OSStatus error
)
554 case mdns_event_invalidated
:
555 mdns_release(monitor
);
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
);
562 if (m
->p
->InterfaceMonitors
)
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
);
568 KQueueUnlock("interface monitor event handler");
569 mdns_interface_monitor_invalidate(monitor
);
576 mdns_interface_monitor_activate(monitor
);
582 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS
*const m
, mDNSu32 ifindex
)
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
);
590 NetworkInterfaceInfoOSX
* ifi
= IfindexToInterfaceInfoOSX((mDNSInterfaceID
)(uintptr_t)ifindex
);
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
);
599 if (!ifi
) return(mDNSNULL
);
601 return(ifi
->ifinfo
.InterfaceID
);
605 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS
*const m
, mDNSInterfaceID id
, mDNSBool suppressNetworkChange
)
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
);
613 mDNSu32 scope_id
= (mDNSu32
)(uintptr_t)id
;
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
);
619 // If we are supposed to suppress network change, return "id" back
620 if (suppressNetworkChange
) return scope_id
;
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
);
631 mDNSlocal mDNSBool
GetInterfaceSupportsWakeOnLANPacket(mDNSInterfaceID id
)
633 NetworkInterfaceInfoOSX
*info
= IfindexToInterfaceInfoOSX(id
);
636 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_ERROR
, "GetInterfaceSupportsWakeOnLANPacket: Invalid interface id %p", id
);
641 return (info
->ift_family
== IFRTYPE_FAMILY_ETHERNET
) ? mDNStrue
: mDNSfalse
;
645 mDNSlocal
uint32_t GetIFTFamily(const char * _Nonnull if_name
)
647 uint32_t ift_family
= IFRTYPE_FAMILY_ANY
;
648 int s
= socket(AF_INET
, SOCK_DGRAM
, 0);
651 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_ERROR
, "GetIFTFamily: socket() failed: " PUB_S
, strerror(errno
));
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)
659 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
, "GetIFTFamily: SIOCGIFTYPE failed: " PUB_S
, strerror(errno
));
663 ift_family
= ifr
.ifr_type
.ift_family
;
669 #if COMPILER_LIKES_PRAGMA_MARK
671 #pragma mark - UDP & TCP send & receive
674 mDNSlocal mDNSBool
AddrRequiresPPPConnection(const struct sockaddr
*addr
)
676 mDNSBool result
= mDNSfalse
;
677 SCNetworkConnectionFlags flags
;
678 CFDataRef remote_addr
;
679 CFMutableDictionaryRef options
;
680 SCNetworkReachabilityRef ReachRef
= NULL
;
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
);
688 CFRelease(remote_addr
);
692 LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions");
695 if (!SCNetworkReachabilityGetFlags(ReachRef
, &flags
))
697 LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags");
700 result
= flags
& kSCNetworkFlagsConnectionRequired
;
708 // Set traffic class for socket
709 mDNSlocal
void setTrafficClass(int socketfd
, mDNSBool useBackgroundTrafficClass
)
713 if (useBackgroundTrafficClass
)
714 traffic_class
= SO_TC_BK_SYS
;
716 traffic_class
= SO_TC_CTL
;
718 (void) setsockopt(socketfd
, SOL_SOCKET
, SO_TRAFFIC_CLASS
, (void *)&traffic_class
, sizeof(traffic_class
));
724 mDNSlocal
int mDNSPlatformGetSocktFd(void *sockCxt
, mDNSTransport_Type transType
, mDNSAddr_Type addrType
)
726 if (transType
== mDNSTransport_UDP
)
728 UDPSocket
* sock
= (UDPSocket
*) sockCxt
;
729 return (addrType
== mDNSAddrType_IPv4
) ? sock
->ss
.sktv4
: sock
->ss
.sktv6
;
731 else if (transType
== mDNSTransport_TCP
)
733 TCPSocket
* sock
= (TCPSocket
*) sockCxt
;
738 LogInfo("mDNSPlatformGetSocktFd: invalid transport %d", transType
);
739 return kInvalidSocketRef
;
743 mDNSexport
void mDNSPlatformSetSocktOpt(void *sockCxt
, mDNSTransport_Type transType
, mDNSAddr_Type addrType
, const DNSQuestion
*q
)
746 char unenc_name
[MAX_ESCAPED_DOMAIN_NAME
];
748 // verify passed-in arguments exist and that sockfd is valid
749 if (q
== mDNSNULL
|| sockCxt
== mDNSNULL
|| (sockfd
= mDNSPlatformGetSocktFd(sockCxt
, transType
, addrType
)) < 0)
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
);
759 if (setsockopt(sockfd
, SOL_SOCKET
, SO_DELEGATED_UUID
, &q
->uuid
, sizeof(q
->uuid
)) == -1)
760 LogMsg("mDNSPlatformSetSocktOpt: Delegate UUID failed %s", strerror(errno
));
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
);
769 if (setsockopt(sockfd
, SOL_SOCKET
, SO_NOWAKEFROMSLEEP
, &nowake
, sizeof(nowake
)) == -1)
770 LogInfo("mDNSPlatformSetSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno
));
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
)
782 NetworkInterfaceInfoOSX
*info
= mDNSNULL
;
783 struct sockaddr_storage to
;
785 mStatus result
= mStatus_NoError
;
788 const DNSMessage
*const dns_msg
= msg
;
792 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
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
;
804 char *ifa_name
= InterfaceID
? info
->ifinfo
.ifname
: "unicast";
806 if (dst
->type
== mDNSAddrType_IPv4
)
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
;
815 if (!mDNSAddrIsDNSMulticast(dst
))
818 const mDNSu32 ifindex
= info
? info
->scope_id
: IFSCOPE_NONE
;
819 setsockopt(s
, IPPROTO_IP
, IP_BOUND_IF
, &ifindex
, sizeof(ifindex
));
821 static int displayed
= 0;
822 if (displayed
< 1000)
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
));
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
840 if (errno
!= ENOPROTOOPT
)
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
);
846 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
847 if (err
< 0 && !m
->NetworkChanged
)
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
));
855 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
856 if (err
< 0 && !m
->NetworkChanged
)
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
));
865 else if (dst
->type
== mDNSAddrType_IPv6
)
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
877 const int err
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
880 const int setsockopt_errno
= errno
;
882 if (if_indextoname(info
->scope_id
, name
) != NULL
)
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
));
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
);
897 if (info
) // Specify outgoing interface for non-multicast destination
899 if (!mDNSAddrIsDNSMulticast(dst
))
901 if (info
->scope_id
== 0)
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
);
909 setsockopt(s
, IPPROTO_IPV6
, IPV6_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
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
;
924 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
925 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
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
));
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
);
937 // switch to background traffic class for this message if requested
938 if (useBackgroundTrafficClass
)
939 setTrafficClass(s
, useBackgroundTrafficClass
);
941 sentlen
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
942 sendto_errno
= (sentlen
< 0) ? errno
: 0;
944 // set traffic class back to default value
945 if (useBackgroundTrafficClass
)
946 setTrafficClass(s
, mDNSfalse
);
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
))
956 if ((sendto_errno
== EHOSTUNREACH
) || (sendto_errno
== ENETUNREACH
)) return(mStatus_HostUnreachErr
);
957 if ((sendto_errno
== EHOSTDOWN
) || (sendto_errno
== ENETDOWN
)) return(mStatus_TransientErr
);
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
)
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
));
974 if (MessageCount
< 50) // Cap and ensure NO spamming of LogMsgs
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
);
980 else // If logging is enabled, remove the cap and log aggressively
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
);
988 result
= mStatus_UnknownErr
;
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
)
997 static unsigned int numLogMessages
= 0;
998 struct iovec databuffers
= { (char *)buffer
, max
};
1001 struct cmsghdr
*cmPtr
;
1002 char ancillary
[1024];
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
1006 // Set up the message
1007 msg
.msg_name
= (caddr_t
)from
;
1008 msg
.msg_namelen
= *fromlen
;
1009 msg
.msg_iov
= &databuffers
;
1011 msg
.msg_control
= (caddr_t
)&ancillary
;
1012 msg
.msg_controllen
= sizeof(ancillary
);
1016 n
= recvmsg(s
, &msg
, 0);
1019 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
1022 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
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
);
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
)
1032 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
1036 *fromlen
= msg
.msg_namelen
;
1038 // Parse each option out of the ancillary data.
1039 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
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
)
1044 dstaddr
->type
= mDNSAddrType_IPv4
;
1045 dstaddr
->ip
.v4
= *(mDNSv4Addr
*)CMSG_DATA(cmPtr
);
1046 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
1048 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
1050 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
1051 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
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);
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
)
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
);
1067 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
1068 *ttl
= *(int*)CMSG_DATA(cmPtr
);
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
)
1077 NetworkInterfaceInfo
*intf
;
1079 if (addr
->type
== mDNSAddrType_IPv4
)
1081 for (intf
= mDNSStorage
.HostInterfaces
; intf
; intf
= intf
->next
)
1083 if (intf
->ip
.type
== addr
->type
&& intf
->McastTxRx
)
1085 if ((intf
->ip
.ip
.v4
.NotAnInteger
^ addr
->ip
.v4
.NotAnInteger
) == 0)
1087 return(intf
->InterfaceID
);
1093 if (addr
->type
== mDNSAddrType_IPv6
)
1095 for (intf
= mDNSStorage
.HostInterfaces
; intf
; intf
= intf
->next
)
1097 if (intf
->ip
.type
== addr
->type
&& intf
->McastTxRx
)
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)))
1104 return(intf
->InterfaceID
);
1109 return(mDNSInterface_Any
);
1112 mDNSexport
void myKQSocketCallBack(int s1
, short filter
, void *context
, mDNSBool encounteredEOF
)
1114 KQSocketSet
*const ss
= (KQSocketSet
*)context
;
1115 mDNS
*const m
= ss
->m
;
1117 int count
= 0, closed
= 0, recvfrom_errno
= 0;
1119 if (filter
!= EVFILT_READ
)
1120 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter
, EVFILT_READ
);
1122 if (s1
!= ss
->sktv4
&& s1
!= ss
->sktv6
)
1124 LogMsg("myKQSocketCallBack: native socket %d", s1
);
1125 LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss
->sktv4
, ss
->sktv6
);
1130 LogMsg("myKQSocketCallBack: socket %d is no longer readable (EOF)", s1
);
1131 if (s1
== ss
->sktv4
)
1133 ss
->sktv4EOF
= mDNStrue
;
1134 KQueueSet(ss
->sktv4
, EV_DELETE
, EVFILT_READ
, &ss
->kqsv4
);
1136 else if (s1
== ss
->sktv6
)
1138 ss
->sktv6EOF
= mDNStrue
;
1139 KQueueSet(ss
->sktv6
, EV_DELETE
, EVFILT_READ
, &ss
->kqsv6
);
1146 mDNSAddr senderAddr
, destAddr
= zeroAddr
;
1147 mDNSIPPort senderPort
;
1148 struct sockaddr_storage from
;
1149 socklen_t fromlen
= sizeof(from
);
1150 char packetifname
[IF_NAMESIZE
] = "";
1152 recvlen
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
1155 recvfrom_errno
= errno
;
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
++;
1163 if (from
.ss_family
== AF_INET
)
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);
1171 else if (from
.ss_family
== AF_INET6
)
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);
1181 LogMsg("myKQSocketCallBack from is unknown address family %d", from
.ss_family
);
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
;
1190 if (intf
->Exists
&& !strcmp(intf
->ifinfo
.ifname
, packetifname
))
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.
1201 InterfaceID
= intf
->ifinfo
.InterfaceID
;
1202 else if (mDNSAddrIsDNSMulticast(&destAddr
))
1207 InterfaceID
= FindMyInterface(&destAddr
);
1210 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1211 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
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
;
1221 m
->p
->UDPProxyCallback(&m
->p
->UDPProxy
, &m
->imsg
.m
, (unsigned char*)&m
->imsg
+ recvlen
, &senderAddr
,
1222 senderPort
, &destAddr
, ss
->port
, InterfaceID
, NULL
);
1226 mDNSCoreReceive(m
, &m
->imsg
.m
, (unsigned char*)&m
->imsg
+ recvlen
, &senderAddr
, senderPort
, &destAddr
, ss
->port
, InterfaceID
);
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
;
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
)
1239 LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
1244 if (recvlen
< 0 && (recvfrom_errno
!= EWOULDBLOCK
|| count
== 0))
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;
1257 struct timeval timeout
;
1260 FD_SET(s1
, &readfds
);
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.");
1281 sleep(1); // After logging this error, rate limit so we don't flood syslog
1285 mDNSlocal
void doTcpSocketCallback(TCPSocket
*sock
)
1287 mDNSBool c
= !sock
->connected
;
1288 if (!sock
->connected
&& sock
->err
== mStatus_NoError
)
1290 sock
->connected
= mDNStrue
;
1292 sock
->callback(sock
, sock
->context
, c
, sock
->err
);
1293 // Note: the callback may call CloseConnection here, which frees the context structure!
1296 #ifndef NO_SECURITYFRAMEWORK
1298 mDNSlocal OSStatus
tlsWriteSock(SSLConnectionRef connection
, const void *data
, size_t *dataLength
)
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
); }
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
);
1311 mDNSlocal OSStatus
tlsReadSock(SSLConnectionRef connection
, void *data
, size_t *dataLength
)
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
); }
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
);
1324 mDNSlocal OSStatus
tlsSetupSock(TCPSocket
*sock
, SSLProtocolSide pside
, SSLConnectionType ctype
)
1326 char domname_cstr
[MAX_ESCAPED_DOMAIN_NAME
];
1328 #pragma clang diagnostic push
1329 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1330 sock
->tlsContext
= SSLCreateContext(kCFAllocatorDefault
, pside
, ctype
);
1331 if (!sock
->tlsContext
)
1333 LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
1334 return(mStatus_UnknownErr
);
1337 mStatus err
= SSLSetIOFuncs(sock
->tlsContext
, tlsReadSock
, tlsWriteSock
);
1340 LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err
);
1344 err
= SSLSetConnection(sock
->tlsContext
, (SSLConnectionRef
) sock
);
1347 LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err
);
1351 // Set the default ciphersuite configuration
1352 err
= SSLSetSessionConfig(sock
->tlsContext
, CFSTR("default"));
1355 LogMsg("ERROR: tlsSetupSock: SSLSetSessionConfig failed with error code: %d", err
);
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])
1363 LogMsg("ERROR: tlsSetupSock: hostname NULL");
1368 ConvertDomainNameToCString(sock
->hostname
, domname_cstr
);
1369 err
= SSLSetPeerDomainName(sock
->tlsContext
, domname_cstr
, strlen(domname_cstr
));
1372 LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr
, err
);
1375 #pragma clang diagnostic pop
1379 if (sock
->tlsContext
)
1380 CFRelease(sock
->tlsContext
);
1384 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1385 mDNSlocal
void doSSLHandshake(TCPSocket
*sock
)
1387 mStatus err
= SSLHandshake(sock
->tlsContext
);
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
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
1401 dispatch_async(dispatch_get_main_queue(), ^{
1403 LogInfo("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
1405 if (sock
->handshake
== handshake_to_be_closed
)
1407 LogInfo("SSLHandshake completed after close");
1408 mDNSPlatformTCPCloseConnection(sock
);
1412 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1413 else LogMsg("doSSLHandshake: sock->fd is -1");
1415 if (err
== errSSLWouldBlock
)
1416 sock
->handshake
= handshake_required
;
1421 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
1422 CFRelease(sock
->tlsContext
);
1423 sock
->tlsContext
= NULL
;
1426 sock
->err
= err
? mStatus_ConnFailed
: 0;
1427 sock
->handshake
= handshake_completed
;
1429 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
1430 doTcpSocketCallback(sock
);
1434 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
1438 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1439 mDNSlocal
void *doSSLHandshake(TCPSocket
*sock
)
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
1448 debugf("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
1450 if (sock
->handshake
== handshake_to_be_closed
)
1452 LogInfo("SSLHandshake completed after close");
1453 mDNSPlatformTCPCloseConnection(sock
);
1457 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, &sock
->kqEntry
);
1458 else LogMsg("doSSLHandshake: sock->fd is -1");
1460 if (err
== errSSLWouldBlock
)
1461 sock
->handshake
= handshake_required
;
1466 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
1467 CFRelease(sock
->tlsContext
);
1468 sock
->tlsContext
= NULL
;
1471 sock
->err
= err
? mStatus_ConnFailed
: 0;
1472 sock
->handshake
= handshake_completed
;
1474 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
1475 doTcpSocketCallback(sock
);
1479 debugf("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
1480 KQueueUnlock("doSSLHandshake");
1483 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1485 mDNSlocal
void spawnSSLHandshake(TCPSocket
* sock
)
1487 debugf("spawnSSLHandshake %p: entry", sock
);
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
);
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
);});
1497 debugf("spawnSSLHandshake %p: done for %d", sock
, sock
->fd
);
1500 #endif /* NO_SECURITYFRAMEWORK */
1502 mDNSlocal
void tcpKQSocketCallback(__unused
int fd
, short filter
, void *context
, __unused mDNSBool encounteredEOF
)
1504 TCPSocket
*sock
= context
;
1505 sock
->err
= mStatus_NoError
;
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
)
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
)
1517 LogInfo("ERROR: TCPConnectCallback called with write event when socket is connected.");
1522 socklen_t len
= (socklen_t
)sizeof(result
);
1523 if (getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, &result
, &len
) < 0)
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
;
1533 sock
->err
= mStatus_ConnFailed
;
1534 if (result
== EHOSTUNREACH
|| result
== EADDRNOTAVAIL
|| result
== ENETDOWN
)
1536 LogInfo("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
1537 sock
->fd
, result
, strerror(result
));
1541 LogMsg("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
1542 sock
->fd
, result
, strerror(result
));
1547 KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_WRITE
, &sock
->kqEntry
);
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
))
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
;
1562 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1564 #ifndef NO_SECURITYFRAMEWORK
1565 // Don't try to set up TLS if the connect failed.
1566 if (sock
->err
== mStatus_NoError
) {
1569 sock
->setup
= mDNStrue
;
1570 #pragma clang diagnostic push
1571 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1572 sock
->err
= tlsSetupSock(sock
, kSSLClientSide
, kSSLStreamType
);
1575 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock
->err
);
1578 #pragma clang diagnostic pop
1580 if (sock
->handshake
== handshake_required
)
1582 spawnSSLHandshake(sock
);
1585 else if (sock
->handshake
== handshake_in_progress
|| sock
->handshake
== handshake_to_be_closed
)
1589 else if (sock
->handshake
!= handshake_completed
)
1592 sock
->err
= mStatus_UnknownErr
;
1593 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock
->handshake
);
1596 #else /* NO_SECURITYFRAMEWORK */
1597 sock
->err
= mStatus_UnsupportedErr
;
1598 #endif /* NO_SECURITYFRAMEWORK */
1601 doTcpSocketCallback(sock
);
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
)
1607 dispatch_queue_t queue
= dispatch_get_main_queue();
1608 dispatch_source_t source
;
1609 if (flags
== EV_DELETE
)
1611 if (filter
== EVFILT_READ
)
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
);
1618 else if (filter
== EVFILT_WRITE
)
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
);
1626 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter
);
1629 if (flags
!= EV_ADD
) LogMsg("KQueueSet: Invalid flags %d", flags
);
1631 if (filter
== EVFILT_READ
)
1633 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, fd
, 0, queue
);
1635 else if (filter
== EVFILT_WRITE
)
1637 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE
, fd
, 0, queue
);
1641 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter
);
1644 if (!source
) return -1;
1645 dispatch_source_set_event_handler(source
, ^{
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
);
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
1656 TriggerEventCompletion();
1659 dispatch_source_set_cancel_handler(source
, ^{
1660 if (entryRef
->fdClosed
)
1662 //LogMsg("CancelHandler: closing fd %d", fd);
1666 dispatch_resume(source
);
1667 if (filter
== EVFILT_READ
)
1668 entryRef
->readSource
= source
;
1670 entryRef
->writeSource
= source
;
1675 mDNSexport
void KQueueLock()
1678 mDNSexport
void KQueueUnlock(const char const *task
)
1680 (void)task
; //unused
1684 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, const KQueueEntry
*const entryRef
)
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;
1691 mDNSexport
void KQueueLock()
1693 mDNS
*const m
= &mDNSStorage
;
1694 pthread_mutex_lock(&m
->p
->BigMutex
);
1695 m
->p
->BigMutexStartTime
= mDNSPlatformRawTime();
1698 mDNSexport
void KQueueUnlock(const char* task
)
1700 mDNS
*const m
= &mDNSStorage
;
1701 mDNSs32 end
= mDNSPlatformRawTime();
1703 if (end
- m
->p
->BigMutexStartTime
>= WatchDogReportingThreshold
)
1705 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_WARNING
,
1706 "WARNING: " PUB_S
" took %d ms to complete", task
, end
- m
->p
->BigMutexStartTime
);
1709 pthread_mutex_unlock(&m
->p
->BigMutex
);
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
));
1717 mDNSexport
void mDNSPlatformCloseFD(KQueueEntry
*kq
, int fd
)
1719 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1723 dispatch_source_cancel(kq
->readSource
);
1724 kq
->readSource
= mDNSNULL
;
1726 if (kq
->writeSource
)
1728 dispatch_source_cancel(kq
->writeSource
);
1729 kq
->writeSource
= mDNSNULL
;
1731 // Close happens in the cancellation handler
1732 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd
);
1733 kq
->fdClosed
= mDNStrue
;
1740 mDNSlocal mStatus
SetupTCPSocket(TCPSocket
*sock
, mDNSAddr_Type addrtype
, mDNSIPPort
*port
, mDNSBool useBackgroundTrafficClass
)
1745 if (!mDNSPosixTCPSocketSetup(&skt
, addrtype
, port
, &sock
->port
))
1747 if (skt
!= -1) close(skt
);
1748 return mStatus_UnknownErr
;
1751 // for TCP sockets, the traffic class is set once and not changed
1752 setTrafficClass(skt
, useBackgroundTrafficClass
);
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
;
1763 return mStatus_NoError
;
1766 mDNSexport TCPSocket
*mDNSPlatformTCPSocket(TCPSocketFlags flags
, mDNSAddr_Type addrtype
, mDNSIPPort
*port
, domainname
*hostname
, mDNSBool useBackgroundTrafficClass
)
1769 mDNSu32 lowWater
= 16384;
1770 size_t len
= sizeof (TCPSocket
);
1772 len
+= sizeof (domainname
);
1775 TCPSocket
*sock
= (TCPSocket
*) callocL("TCPSocket/mDNSPlatformTCPSocket", len
);
1776 if (!sock
) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL
); }
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
);
1785 err
= SetupTCPSocket(sock
, addrtype
, port
, useBackgroundTrafficClass
);
1789 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock
->fd
, errno
, strerror(errno
));
1790 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1794 if (setsockopt(sock
->fd
, IPPROTO_TCP
, TCP_NOTSENT_LOWAT
, &lowWater
, sizeof lowWater
) < 0)
1796 LogMsg("mDNSPlatformTCPSocket: TCP_NOTSENT_LOWAT returned %d", errno
);
1797 mDNSPlatformTCPCloseConnection(sock
);
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
;
1813 mDNSexport mStatus
mDNSPlatformTCPConnect(TCPSocket
*sock
, const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
, TCPConnectionCallback callback
, void *context
)
1815 mStatus err
= mStatus_NoError
;
1816 struct sockaddr_storage ss
;
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
;
1825 if (dst
->type
== mDNSAddrType_IPv4
)
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
;
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
;
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
))
1848 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1852 if (fcntl(sock
->fd
, F_SETFL
, fcntl(sock
->fd
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
1854 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1855 return mStatus_UnknownErr
;
1858 // We bind to the interface and all subsequent packets including the SYN will be sent out
1859 // on this interface
1861 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
1865 NetworkInterfaceInfoOSX
*info
= IfindexToInterfaceInfoOSX(InterfaceID
);
1866 if (dst
->type
== mDNSAddrType_IPv4
)
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
; }
1872 (void)InterfaceID
; // Unused
1873 (void)info
; // Unused
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
; }
1882 (void)InterfaceID
; // Unused
1883 (void)info
; // Unused
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)
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
));
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
;
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.
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
)
1914 sock
->callback
= callback
;
1915 sock
->context
= context
;
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
1921 if (!sock
->callback
) {
1922 // Watch for incoming data
1923 if (KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, &sock
->kqEntry
))
1925 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1926 return mStatus_UnknownErr
;
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
;
1938 return mStatus_NoError
;
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
)
1948 mStatus err
= mStatus_NoError
;
1950 TCPSocket
*sock
= (TCPSocket
*) callocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(*sock
));
1951 if (!sock
) return(mDNSNULL
);
1954 sock
->flags
= flags
;
1956 if (flags
& kTCPSocketFlags_UseTLS
)
1958 #ifndef NO_SECURITYFRAMEWORK
1959 #pragma clang diagnostic push
1960 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1962 if (!ServerCerts
) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err
= mStatus_UnknownErr
; goto exit
; }
1964 err
= tlsSetupSock(sock
, kSSLServerSide
, kSSLStreamType
);
1965 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err
); goto exit
; }
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
1971 err
= mStatus_UnsupportedErr
;
1972 #endif /* NO_SECURITYFRAMEWORK */
1974 #ifndef NO_SECURITYFRAMEWORK
1978 if (err
) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock
); return(mDNSNULL
); }
1982 mDNSlocal
void tcpListenCallback(int fd
, __unused
short filter
, void *context
, __unused mDNSBool encounteredEOF
)
1984 TCPListener
*listener
= context
;
1987 sock
= mDNSPosixDoTCPListenCallback(fd
, listener
->addressType
, listener
->socketFlags
,
1988 listener
->callback
, listener
->context
);
1990 if (sock
!= mDNSNULL
)
1992 KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, &sock
->kqEntry
);
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
;
2005 mDNSexport TCPListener
*mDNSPlatformTCPListen(mDNSAddr_Type addrtype
, mDNSIPPort
*port
, mDNSAddr
*addr
,
2006 TCPSocketFlags socketFlags
, mDNSBool reuseAddr
, int queueLength
,
2007 TCPAcceptedCallback callback
, void *context
)
2012 if (!mDNSPosixTCPListen(&fd
, addrtype
, port
, addr
, reuseAddr
, queueLength
)) {
2019 // Allocate a listener structure
2020 ret
= (TCPListener
*) mDNSPlatformMemAllocateClear(sizeof *ret
);
2021 if (ret
== mDNSNULL
)
2023 LogMsg("mDNSPlatformTCPListen: no memory for TCPListener struct.");
2028 ret
->callback
= callback
;
2029 ret
->context
= context
;
2030 ret
->socketFlags
= socketFlags
;
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
;
2045 mDNSexport mDNSu16
mDNSPlatformGetUDPPort(UDPSocket
*sock
)
2052 port
= sock
->ss
.port
.NotAnInteger
;
2057 mDNSlocal
void CloseSocketSet(KQSocketSet
*ss
)
2059 if (ss
->sktv4
!= -1)
2061 mDNSPlatformCloseFD(&ss
->kqsv4
, ss
->sktv4
);
2064 if (ss
->sktv6
!= -1)
2066 mDNSPlatformCloseFD(&ss
->kqsv6
, ss
->sktv6
);
2069 if (ss
->closeFlag
) *ss
->closeFlag
= 1;
2072 mDNSexport
void mDNSPlatformTCPCloseConnection(TCPSocket
*sock
)
2076 #ifndef NO_SECURITYFRAMEWORK
2077 if (sock
->tlsContext
)
2079 if (sock
->handshake
== handshake_in_progress
) // SSLHandshake thread using this sock (esp. tlsContext)
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
;
2087 #pragma clang diagnostic push
2088 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2089 SSLClose(sock
->tlsContext
);
2090 CFRelease(sock
->tlsContext
);
2091 sock
->tlsContext
= NULL
;
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
);
2101 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock
);
2105 mDNSexport
long mDNSPlatformReadTCP(TCPSocket
*sock
, void *buf
, unsigned long buflen
, mDNSBool
*closed
)
2108 *closed
= mDNSfalse
;
2110 // We can get here if the caller set up a TCP connection but didn't check the status when it got the
2112 if (!sock
->connected
) {
2113 return mStatus_DefunctConnection
;
2116 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
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
);
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
; }
2135 #endif /* NO_SECURITYFRAMEWORK */
2139 nread
= mDNSPosixReadTCP(sock
->fd
, buf
, buflen
, closed
);
2145 mDNSexport
long mDNSPlatformWriteTCP(TCPSocket
*sock
, const char *msg
, unsigned long len
)
2149 if (!sock
->connected
) {
2150 return mStatus_DefunctConnection
;
2153 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
2155 #ifndef NO_SECURITYFRAMEWORK
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
);
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
2166 if (!err
) nsent
= (long)processed
;
2167 else if (err
== errSSLWouldBlock
) nsent
= 0;
2168 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err
); nsent
= -1; }
2171 #endif /* NO_SECURITYFRAMEWORK */
2175 nsent
= mDNSPosixWriteTCP(sock
->fd
, msg
, len
);
2180 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
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
2191 mDNSexport mDNSBool
mDNSPlatformTCPWritable(TCPSocket
*sock
)
2194 struct kevent kin
, kout
;
2200 LogMsg("ERROR: kqueue failed: %m");
2205 EV_SET(&kin
, sock
->fd
, EVFILT_WRITE
, EV_ADD
, 0, 0, 0);
2206 count
= kevent(kfd
, &kin
, 1, &kout
, 1, &ts
);
2208 if (count
== 1 && (int)kout
.ident
== sock
->fd
&& kout
.filter
== EVFILT_WRITE
)
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
)
2219 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
2220 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
2222 const int twofivefive
= 255;
2223 mStatus err
= mStatus_NoError
;
2224 char *errstr
= mDNSNULL
;
2228 cp
->closeFlag
= mDNSNULL
;
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
); }
2233 // set default traffic class
2234 setTrafficClass(skt
, mDNSfalse
);
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
))
2242 err
= setsockopt(skt
, SOL_SOCKET
, SO_RECV_ANYIF
, &on
, sizeof(on
));
2243 if (err
< 0) { errstr
= "setsockopt - SO_RECV_ANYIF"; goto fail
; }
2245 #endif // SO_RECV_ANYIF
2247 // ... with a shared UDP port, if it's for multicast receiving
2248 if (mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSSameIPPort(port
, NATPMPAnnouncementPort
))
2250 err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
2251 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
2254 // Don't want to wake from sleep for inbound packets on the mDNS sockets
2255 if (mDNSSameIPPort(port
, MulticastDNSPort
))
2258 if (setsockopt(skt
, SOL_SOCKET
, SO_NOWAKEFROMSLEEP
, &nowake
, sizeof(nowake
)) == -1)
2259 LogInfo("SetupSocket: SO_NOWAKEFROMSLEEP failed %s", strerror(errno
));
2262 if (sa_family
== AF_INET
)
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
; }
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
; }
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
; }
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
; }
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
; }
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
;
2293 else if (sa_family
== AF_INET6
)
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
; }
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
; }
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
; }
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
; }
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
; }
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
; }
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
; }
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
));
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
;
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
2346 k
->KQcallback
= myKQSocketCallBack
;
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
;
2354 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
2356 return(mStatus_NoError
);
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
));
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
)
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.");
2376 mDNSPlatformCloseFD(k
, skt
);
2380 mDNSexport UDPSocket
*mDNSPlatformUDPSocket(const mDNSIPPort requestedport
)
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
;
2392 p
->ss
.proxy
= mDNSfalse
;
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
);
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; }
2405 } while (err
== EADDRINUSE
&& randomizePort
&& i
);
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
);
2425 mDNSexport
void mDNSPlatformUDPClose(UDPSocket
*sock
)
2427 CloseSocketSet(&sock
->ss
);
2428 freeL("UDPSocket", sock
);
2432 mDNSexport mDNSBool
mDNSPlatformUDPSocketEncounteredEOF(const UDPSocket
*sock
)
2434 return (sock
->ss
.sktv4EOF
|| sock
->ss
.sktv6EOF
);
2437 #if COMPILER_LIKES_PRAGMA_MARK
2439 #pragma mark - BPF Raw packet sending/receiving
2442 #if APPLE_OSX_mDNSResponder
2444 mDNSexport
void mDNSPlatformSendRawPacket(const void *const msg
, const mDNSu8
*const end
, mDNSInterfaceID InterfaceID
)
2446 if (!InterfaceID
) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2447 NetworkInterfaceInfoOSX
*info
;
2449 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
2452 LogMsg("mDNSPlatformSendRawPacket: Invalid interface index %p", InterfaceID
);
2455 if (info
->BPF_fd
< 0)
2456 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info
->ifinfo
.ifname
, info
->BPF_fd
);
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
));
2465 mDNSexport
void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr
*const tpa
, const mDNSEthAddr
*const tha
, mDNSInterfaceID InterfaceID
)
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
);
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
);
2483 mDNSlocal
void CloseBPF(NetworkInterfaceInfoOSX
*const i
)
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
);
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
);
2500 if (i
->BPF_mcfd
>= 0) { close(i
->BPF_mcfd
); i
->BPF_mcfd
= -1; }
2503 mDNSlocal
void bpf_callback_common(NetworkInterfaceInfoOSX
*info
)
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
;
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
);
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
2525 if (errno
== EAGAIN
)
2527 LogMsg("bpf_callback got EAGAIN bailing");
2530 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info
->ifinfo
.ifname
, info
->BPF_fd
, errno
, strerror(errno
));
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
);
2548 KQueueUnlock("bpf_callback");
2550 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2551 mDNSlocal
void bpf_callback_dispatch(NetworkInterfaceInfoOSX
*const info
)
2553 bpf_callback_common(info
);
2556 mDNSlocal
void bpf_callback(const CFSocketRef cfs
, const CFSocketCallBackType CallBackType
, const CFDataRef address
, const void *const data
, void *const context
)
2562 bpf_callback_common((NetworkInterfaceInfoOSX
*)context
);
2566 mDNSexport
void mDNSPlatformSendKeepalive(mDNSAddr
*sadd
, mDNSAddr
*dadd
, mDNSIPPort
*lport
, mDNSIPPort
*rport
, mDNSu32 seq
, mDNSu32 ack
, mDNSu16 win
)
2568 LogMsg("mDNSPlatformSendKeepalive called\n");
2569 mDNSSendKeepalive(sadd
->ip
.v6
.b
, dadd
->ip
.v6
.b
, lport
->NotAnInteger
, rport
->NotAnInteger
, seq
, ack
, win
);
2572 mDNSexport mStatus
mDNSPlatformClearSPSData(void)
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
);
2579 spsAddressKey
= SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, CFSTR("BonjourSleepProxyAddress"));
2580 if (spsAddressKey
!= NULL
)
2582 CFArrayRef keyList
= SCDynamicStoreCopyKeyList(addrStore
, spsAddressKey
);
2583 if (keyList
!= NULL
)
2585 if (SCDynamicStoreSetMultiple(addrStore
, NULL
, keyList
, NULL
) == false)
2586 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr( spsAddressKey
, kCFStringEncodingASCII
), SCErrorString(SCError()));
2588 if (keyList
) CFRelease(keyList
);
2590 ownerOPTRecKey
= SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, CFSTR("BonjourSleepProxyOPTRecord"));
2591 if(ownerOPTRecKey
!= NULL
)
2593 CFArrayRef keyList
= SCDynamicStoreCopyKeyList(addrStore
, ownerOPTRecKey
);
2594 if (keyList
!= NULL
)
2596 if (SCDynamicStoreSetMultiple(optStore
, NULL
, keyList
, NULL
) == false)
2597 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr(ownerOPTRecKey
, kCFStringEncodingASCII
), SCErrorString(SCError()));
2599 if (keyList
) CFRelease(keyList
);
2602 if (addrStore
) CFRelease(addrStore
);
2603 if (optStore
) CFRelease(optStore
);
2604 if (spsAddressKey
) CFRelease(spsAddressKey
);
2605 if (ownerOPTRecKey
) CFRelease(ownerOPTRecKey
);
2606 return KERN_SUCCESS
;
2609 mDNSlocal
int getMACAddress(int family
, v6addr_t raddr
, v6addr_t gaddr
, int *gfamily
, ethaddr_t eth
)
2613 struct rt_msghdr m_rtm
;
2617 struct rt_msghdr
*rtm
= &(m_rtmsg
.m_rtm
);
2618 char *cp
= m_rtmsg
.m_space
;
2619 int seq
= 6367, sock
, i
;
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
;
2627 #define NEXTADDR(w, s, len) \
2628 if (rtm->rtm_addrs & (w)) \
2630 bcopy((char *)s, cp, len); \
2634 bzero(&sins
, sizeof(struct sockaddr_storage
));
2635 bzero(&sdl_m
, sizeof(struct sockaddr_dl
));
2636 bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
2638 sock
= socket(PF_ROUTE
, SOCK_RAW
, 0);
2641 const int socket_errno
= errno
;
2642 LogMsg("getMACAddress: Can not open the socket - %s", strerror(socket_errno
));
2643 return socket_errno
;
2646 rtm
->rtm_addrs
|= RTA_DST
| RTA_GATEWAY
;
2647 rtm
->rtm_type
= RTM_GET
;
2649 rtm
->rtm_version
= RTM_VERSION
;
2650 rtm
->rtm_seq
= ++seq
;
2652 sdl_m
.sdl_len
= sizeof(sdl_m
);
2653 sdl_m
.sdl_family
= AF_LINK
;
2654 if (family
== AF_INET
)
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
);
2662 else if (family
== AF_INET6
)
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
);
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
;
2674 if (write(sock
, (char *)&m_rtmsg
, rlen
) < 0)
2676 const int write_errno
= errno
;
2677 LogMsg("getMACAddress: writing to routing socket: %s", strerror(write_errno
));
2684 rlen
= read(sock
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
2686 while (rlen
> 0 && (rtm
->rtm_seq
!= seq
|| rtm
->rtm_pid
!= getpid()));
2689 LogMsg("getMACAddress: Read from routing socket failed");
2691 if (family
== AF_INET
)
2693 sin
= (struct sockaddr_in
*) (rtm
+ 1);
2694 sdl
= (struct sockaddr_dl
*) (sin
->sin_len
+ (char *) sin
);
2696 else if (family
== AF_INET6
)
2698 sin6
= (struct sockaddr_in6
*) (rtm
+1);
2699 sdl
= (struct sockaddr_dl
*) (sin6
->sin6_len
+ (char *) sin6
);
2704 LogMsg("getMACAddress: sdl is NULL for family %d", family
);
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
)
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
));
2721 LogMsg("getMACAddress: sin is NULL");
2726 else if (sdl
->sdl_family
== AF_INET6
)
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
));
2735 LogMsg("getMACAddress: sin6 is NULL");
2741 unsigned char *ptr
= (unsigned char *)LLADDR(sdl
);
2742 for (i
= 0; i
< ETHER_ADDR_LEN
; i
++)
2743 (eth
)[i
] = *(ptr
+i
);
2747 return KERN_SUCCESS
;
2750 mDNSlocal
int GetRemoteMacinternal(int family
, v6addr_t raddr
, ethaddr_t eth
)
2759 ret
= getMACAddress(family
, raddr
, gateway
, &gfamily
, eth
);
2762 memcpy(raddr
, gateway
, (gfamily
== AF_INET
) ? 4 : 16);
2767 while ((ret
== -1) && (count
< 5));
2771 mDNSlocal
int StoreSPSMACAddressinternal(int family
, v6addr_t spsaddr
, const char *ifname
)
2774 char spsip
[INET6_ADDRSTRLEN
];
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
;
2784 if ((store
== NULL
) || (ipstore
== NULL
))
2786 LogMsg("StoreSPSMACAddressinternal: Unable to accesss SC Dynamic Store");
2791 // Get the MAC address of the Sleep Proxy Server
2792 memset(eth
, 0, sizeof(eth
));
2793 ret
= GetRemoteMacinternal(family
, spsaddr
, eth
);
2796 LogMsg("StoreSPSMACAddressinternal: Failed to determine the MAC address");
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
);
2805 LogMsg("StoreSPSMACAddressinternal: SPSCreateDict() Could not create CFDictionary dict");
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
)
2815 if( NULL
== inet_ntop(family
, (void *)spsaddr
, spsip
, sizeof(spsip
)))
2817 LogMsg("StoreSPSMACAddressinternal: inet_ntop failed: %s", strerror(errno
));
2822 CFStringRef ipaddr
= CFStringCreateWithCString(NULL
, spsip
, kCFStringEncodingUTF8
);
2823 CFDictionarySetValue(dict
, CFSTR("IPAddress"), ipaddr
);
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
)
2830 if ((ipdict
= SCDynamicStoreCopyValue(ipstore
, entityname
)) != NULL
)
2832 if((addrs
= CFDictionaryGetValue(ipdict
, CFSTR("Addresses"))) != NULL
)
2834 addrs
= CFRetain(addrs
);
2835 CFDictionarySetValue(dict
, CFSTR("RegisteredAddresses"), addrs
);
2839 SCDynamicStoreSetValue(store
, sckey
, dict
);
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
);
2853 mDNSlocal
void mDNSStoreSPSMACAddress(int family
, v6addr_t spsaddr
, char *ifname
)
2861 mDNSPlatformMemCopy(addr
.saddr
, spsaddr
, sizeof(v6addr_t
));
2863 err
= StoreSPSMACAddressinternal(family
, (uint8_t *)addr
.saddr
, ifname
);
2865 LogMsg("mDNSStoreSPSMACAddress : failed");
2868 mDNSexport mStatus
mDNSPlatformStoreSPSMACAddr(mDNSAddr
*spsaddr
, char *ifname
)
2870 int family
= (spsaddr
->type
== mDNSAddrType_IPv4
) ? AF_INET
: AF_INET6
;
2872 LogInfo("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr
, ifname
);
2873 mDNSStoreSPSMACAddress(family
, spsaddr
->ip
.v6
.b
, ifname
);
2875 return KERN_SUCCESS
;
2879 mDNSexport mStatus
mDNSPlatformStoreOwnerOptRecord(char *ifname
, DNSMessage
* msg
, int length
)
2882 CFStringRef sckey
= NULL
;
2883 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:StoreOwnerOPTRecord"), NULL
, NULL
);
2884 CFMutableDictionaryRef dict
= NULL
;
2888 LogMsg("mDNSPlatformStoreOwnerOptRecord: Unable to accesss SC Dynamic Store");
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
);
2898 LogMsg("mDNSPlatformStoreOwnerOptRecord: Could not create CFDictionary dictionary to store OPT Record");
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
);
2908 SCDynamicStoreSetValue(store
, sckey
, dict
);
2911 if (NULL
!= store
) CFRelease(store
);
2912 if (NULL
!= sckey
) CFRelease(sckey
);
2913 if (NULL
!= dict
) CFRelease(dict
);
2917 mDNSlocal
void mDNSGet_RemoteMAC(int family
, v6addr_t raddr
)
2920 IPAddressMACMapping
*addrMapping
;
2921 int kr
= KERN_FAILURE
;
2927 bzero(eth
, sizeof(ethaddr_t
));
2928 mDNSPlatformMemCopy(dst
.addr
, raddr
, sizeof(v6addr_t
));
2930 kr
= GetRemoteMacinternal(family
, (uint8_t *)dst
.addr
, eth
);
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.
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
)
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
2950 addrMapping
->ipaddr
.type
= mDNSAddrType_IPv6
;
2951 mDNSPlatformMemCopy(addrMapping
->ipaddr
.ip
.v6
.b
, raddr
, sizeof(v6addr_t
));
2953 UpdateRMAC(&mDNSStorage
, addrMapping
);
2957 mDNSexport mStatus
mDNSPlatformGetRemoteMacAddr(mDNSAddr
*raddr
)
2959 int family
= (raddr
->type
== mDNSAddrType_IPv4
) ? AF_INET
: AF_INET6
;
2961 LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC");
2962 mDNSGet_RemoteMAC(family
, raddr
->ip
.v6
.b
);
2964 return KERN_SUCCESS
;
2967 mDNSexport mStatus
mDNSPlatformRetrieveTCPInfo(mDNSAddr
*laddr
, mDNSIPPort
*lport
, mDNSAddr
*raddr
, mDNSIPPort
*rport
, mDNSTCPInfo
*mti
)
2971 int family
= (laddr
->type
== mDNSAddrType_IPv4
) ? AF_INET
: AF_INET6
;
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
)
2976 LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__
, error
);
2979 mti
->IntfId
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, intfid
);
2983 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2985 mDNSlocal
int CountProxyTargets(NetworkInterfaceInfoOSX
*x
, int *p4
, int *p6
)
2987 int numv4
= 0, numv6
= 0;
2990 for (rr
= mDNSStorage
.ResourceRecords
; rr
; rr
=rr
->next
)
2991 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2993 if (p4
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv4
, &rr
->AddressProxy
.ip
.v4
);
2997 for (rr
= mDNSStorage
.ResourceRecords
; rr
; rr
=rr
->next
)
2998 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
3000 if (p6
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv6
, &rr
->AddressProxy
.ip
.v6
);
3004 if (p4
) *p4
= numv4
;
3005 if (p6
) *p6
= numv6
;
3006 return(numv4
+ numv6
);
3009 mDNSexport
void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID
)
3011 mDNS
*const m
= &mDNSStorage
;
3012 NetworkInterfaceInfoOSX
*x
;
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;
3017 if (!x
) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID
); return; }
3019 #define MAX_BPF_ADDRS 250
3020 int numv4
= 0, numv6
= 0;
3022 if (CountProxyTargets(x
, &numv4
, &numv6
) > MAX_BPF_ADDRS
)
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
;
3029 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x
->BPF_fd
, x
->ifinfo
.ifname
, &x
->ifinfo
.MAC
, numv4
, numv6
);
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
] =
3035 BPF_STMT(BPF_LD
+ BPF_H
+ BPF_ABS
, 12), // 0 Read Ethertype (bytes 12,13)
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
3040 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
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
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)
3051 // Special filter program to use when there are no address proxy records
3052 static struct bpf_insn nullfilter
[] =
3054 BPF_STMT(BPF_RET
| BPF_K
, 0) // 0 Match no packets and return size 0
3057 struct bpf_program prog
;
3058 if (!numv4
&& !numv6
)
3060 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
3061 if (m
->timenow
== 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
3063 // Cancel any previous ND group memberships we had
3064 if (x
->BPF_mcfd
>= 0)
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
3074 prog
.bf_insns
= nullfilter
;
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;
3084 static const struct bpf_insn rf
= BPF_STMT(BPF_RET
+ BPF_K
, 0); // No match: Return nothing
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)
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)
3093 static const struct bpf_insn r6a
= BPF_STMT(BPF_RET
+ BPF_K
, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
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
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.
3110 // IPSEC capture size notes:
3111 // 8 bytes UDP header
3112 // 4 bytes Non-ESP Marker
3113 // 28 bytes IKE Header
3115 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
3118 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3119 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
3121 mDNSv4Addr a
= rr
->AddressProxy
.ip
.v4
;
3122 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
3123 BPF_SetOffset(pc
, jt
, ret4
);
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];
3130 if (pc
!= chk6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc
, chk6
);
3131 *pc
++ = g6
; // chk6 points here
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);
3137 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3138 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
3140 const mDNSv6Addr
*const a
= &rr
->AddressProxy
.ip
.v6
;
3141 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
3142 BPF_SetOffset(pc
, jt
, ret6
);
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];
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];
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
);
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
);
3163 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr
.ipv6mr_multiaddr
, a
);
3166 if (pc
!= fail
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc
, fail
);
3167 *pc
++ = rf
; // fail points here
3169 if (pc
!= ret4
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc
, ret4
);
3170 *pc
++ = r4a
; // ret4 points here
3175 if (pc
!= ret6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc
, ret6
);
3176 *pc
++ = r6a
; // ret6 points here
3178 // For debugging BPF filter program
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
);
3183 prog
.bf_len
= (u_int
)(pc
- filter
);
3184 prog
.bf_insns
= filter
;
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
);
3191 mDNSexport
void mDNSPlatformReceiveBPF_fd(int fd
)
3193 mDNS
*const m
= &mDNSStorage
;
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
); }
3201 LogSPS("%s using BPF fd %d", i
->ifinfo
.ifname
, fd
);
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
);
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
));
3213 if (i
->BPF_len
> sizeof(m
->imsg
))
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
));
3219 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd
, i
->ifinfo
.ifname
, i
->BPF_len
);
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
));
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));
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));
3232 /* <rdar://problem/10287386>
3233 * make socket non blocking see comments in bpf_callback_common for more info
3235 if (fcntl(fd
, F_SETFL
, fcntl(fd
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
3237 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
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; }
3247 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
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
);
3255 CFSocketContext myCFSocketContext
= { 0, i
, NULL
, NULL
, NULL
};
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
);
3261 mDNSPlatformUpdateProxyList(i
->ifinfo
.InterfaceID
);
3268 #endif // APPLE_OSX_mDNSResponder
3270 #if COMPILER_LIKES_PRAGMA_MARK
3272 #pragma mark - Key Management
3275 #ifndef NO_SECURITYFRAMEWORK
3276 mDNSlocal CFArrayRef
CopyCertChain(SecIdentityRef identity
)
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
);
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
);
3292 SecPolicyRef policy
;
3293 err
= SecPolicySearchCopyNext(searchRef
, &policy
);
3294 if (err
|| !policy
) LogMsg("CopyCertChain: SecPolicySearchCopyNext() returned %d", (int) err
);
3297 CFArrayRef wrappedCert
= CFArrayCreate(NULL
, (const void**) &cert
, 1, &kCFTypeArrayCallBacks
);
3298 if (!wrappedCert
) LogMsg("CopyCertChain: wrappedCert is NULL");
3302 err
= SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
);
3303 if (err
|| !trust
) LogMsg("CopyCertChain: SecTrustCreateWithCertificates() returned %d", (int) err
);
3306 err
= SecTrustEvaluate(trust
, NULL
);
3307 if (err
) LogMsg("CopyCertChain: SecTrustEvaluate() returned %d", (int) err
);
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
);
3316 certChain
= CFArrayCreateMutableCopy(NULL
, 0, rawCertChain
);
3317 if (!certChain
) LogMsg("CopyCertChain: certChain is NULL");
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);
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...
3335 CFRelease(wrappedCert
);
3339 CFRelease(searchRef
);
3341 #pragma clang diagnostic pop
3346 #endif /* NO_SECURITYFRAMEWORK */
3348 mDNSexport mStatus
mDNSPlatformTLSSetupCerts(void)
3350 #ifdef NO_SECURITYFRAMEWORK
3351 return mStatus_UnsupportedErr
;
3353 SecIdentityRef identity
= nil
;
3354 SecIdentitySearchRef srchRef
= nil
;
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
; }
3364 err
= SecIdentitySearchCopyNext(srchRef
, &identity
);
3365 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err
); return err
; }
3366 #pragma clang diagnostic pop
3368 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
3369 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr
; }
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
; }
3375 return mStatus_NoError
;
3376 #endif /* NO_SECURITYFRAMEWORK */
3379 mDNSexport
void mDNSPlatformTLSTearDownCerts(void)
3381 #ifndef NO_SECURITYFRAMEWORK
3382 if (ServerCerts
) { CFRelease(ServerCerts
); ServerCerts
= NULL
; }
3383 #endif /* NO_SECURITYFRAMEWORK */
3387 mDNSlocal
void mDNSDomainLabelFromCFString(CFStringRef cfs
, domainlabel
*const namelabel
);
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
)
3392 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
3393 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
3395 if (cfs
== mDNSNULL
) {
3399 mDNSDomainLabelFromCFString(cfs
, namelabel
);
3404 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
3406 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
3408 if (cfs
== mDNSNULL
) {
3412 mDNSDomainLabelFromCFString(cfs
, namelabel
);
3417 mDNSlocal
void mDNSDomainLabelFromCFString(CFStringRef cfs
, domainlabel
*const namelabel
)
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
;
3424 mDNSexport mDNSBool
DictionaryIsEnabled(CFDictionaryRef dict
)
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
;
3434 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
3436 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
3438 if (sa
->sa_family
== AF_INET
)
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
);
3446 if (sa
->sa_family
== AF_INET6
)
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
);
3460 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
3461 return(mStatus_Invalid
);
3464 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
3466 mDNSEthAddr eth
= zeroEthAddr
;
3468 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
3471 CFDictionaryRef dict
= SCDynamicStoreCopyValue(NULL
, entityname
);
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
);
3480 CFRelease(entityname
);
3486 mDNSlocal
int GetMAC(mDNSEthAddr
*eth
, u_short ifindex
)
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
)
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; }
3500 #ifndef SIOCGIFWAKEFLAGS
3501 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
3504 #ifndef IF_WAKE_ON_MAGIC_PACKET
3505 #define IF_WAKE_ON_MAGIC_PACKET 0x01
3508 #ifndef ifr_wake_flags
3509 #define ifr_wake_flags ifr_ifru.ifru_intval
3514 RegistryEntrySearchCFPropertyAndIOObject( io_registry_entry_t entry
,
3515 const io_name_t plane
,
3517 CFTypeRef
* outProperty
,
3518 io_registry_entry_t
* outEntry
)
3522 IOObjectRetain(entry
);
3525 CFTypeRef ref
= IORegistryEntryCreateCFProperty(entry
, keystr
, kCFAllocatorDefault
, mDNSNULL
);
3528 if (outProperty
) *outProperty
= ref
;
3529 else CFRelease(ref
);
3532 io_registry_entry_t parent
;
3533 kr
= IORegistryEntryGetParentEntry(entry
, plane
, &parent
);
3534 if (kr
!= KERN_SUCCESS
) parent
= mDNSNULL
;
3535 IOObjectRelease(entry
);
3538 if (!entry
) kr
= kIOReturnNoDevice
;
3541 if (outEntry
) *outEntry
= entry
;
3542 else IOObjectRelease(entry
);
3548 mDNSlocal mDNSBool
CheckInterfaceSupport(NetworkInterfaceInfo
*const intf
, const char *key
)
3550 io_service_t service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOBSDNameMatching(kIOMasterPortDefault
, 0, intf
->ifname
));
3553 LogSPS("CheckInterfaceSupport: No service for interface %s", intf
->ifname
);
3557 mDNSBool ret
= mDNSfalse
;
3559 CFStringRef keystr
= CFStringCreateWithCString(NULL
, key
, kCFStringEncodingUTF8
);
3560 kern_return_t kr
= RegistryEntrySearchCFPropertyAndIOObject(service
, kIOServicePlane
, keystr
, mDNSNULL
, mDNSNULL
);
3562 if (kr
== KERN_SUCCESS
) ret
= mDNStrue
;
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
);
3572 IOObjectRelease(service
);
3577 #if !TARGET_OS_WATCH
3578 mDNSlocal mDNSBool
InterfaceSupportsKeepAlive(NetworkInterfaceInfo
*const intf
)
3580 return CheckInterfaceSupport(intf
, mDNS_IOREG_KA_KEY
);
3584 mDNSlocal mDNSBool
NetWakeInterface(NetworkInterfaceInfoOSX
*i
)
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
)
3593 LogRedact(MDNS_LOG_CATEGORY_SPS
, MDNS_LOG_DEBUG
,
3594 "NetWakeInterface: returning false for " PUB_S
, i
->ifinfo
.ifname
);
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
))
3603 LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i
->ifinfo
.ifname
);
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
); }
3611 strlcpy(ifr
.ifr_name
, i
->ifinfo
.ifname
, sizeof(ifr
.ifr_name
));
3612 if (ioctl(s
, SIOCGIFWAKEFLAGS
, &ifr
) < 0)
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;
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
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");
3634 return((ifr
.ifr_wake_flags
& IF_WAKE_ON_MAGIC_PACKET
) != 0);
3635 #endif // TARGET_OS_WATCH
3638 mDNSlocal u_int64_t
getExtendedFlags(const char *ifa_name
)
3643 sockFD
= socket(AF_INET
, SOCK_DGRAM
, 0);
3646 LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno
, strerror(errno
));
3650 ifr
.ifr_addr
.sa_family
= AF_INET
;
3651 strlcpy(ifr
.ifr_name
, ifa_name
, sizeof(ifr
.ifr_name
));
3653 if (ioctl(sockFD
, SIOCGIFEFLAGS
, (caddr_t
)&ifr
) == -1)
3655 LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed for %s, errno = %d (%s)", ifa_name
, errno
, strerror(errno
));
3660 return ifr
.ifr_eflags
;
3663 mDNSlocal mDNSBool
isExcludedInterface(int sockFD
, char * ifa_name
)
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))
3672 LogMsg("isExcludedInterface: excluding %s", ifa_name
);
3676 // Coprocessor interfaces are also excluded.
3679 LogMsg("isExcludedInterface: invalid socket FD passed: %d", sockFD
);
3683 memset(&ifr
, 0, sizeof(struct ifreq
));
3684 strlcpy(ifr
.ifr_name
, ifa_name
, sizeof(ifr
.ifr_name
));
3686 if (ioctl(sockFD
, SIOCGIFFUNCTIONALTYPE
, (caddr_t
)&ifr
) == -1)
3688 LogMsg("isExcludedInterface: SIOCGIFFUNCTIONALTYPE failed, errno = %d (%s)", errno
, strerror(errno
));
3692 if (ifr
.ifr_functional_type
== IFRTYPE_FUNCTIONAL_INTCOPROC
)
3694 LogMsg("isExcludedInterface: excluding coprocessor interface %s", ifa_name
);
3701 #if (TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST)
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
;
3709 mDNSlocal mDNSBool
MobileWiFiLibLoad(void)
3711 static mDNSBool isInitialized
= mDNSfalse
;
3712 static void *MobileWiFiLib_p
= mDNSNULL
;
3713 static const char path
[] = "/System/Library/PrivateFrameworks/MobileWiFi.framework/MobileWiFi";
3717 if (!MobileWiFiLib_p
)
3719 MobileWiFiLib_p
= dlopen(path
, RTLD_LAZY
| RTLD_LOCAL
);
3720 if (!MobileWiFiLib_p
)
3722 LogInfo("MobileWiFiLibLoad: dlopen() failed.");
3727 if (!WiFiManagerClientCreate_p
)
3729 WiFiManagerClientCreate_p
= dlsym(MobileWiFiLib_p
, "WiFiManagerClientCreate");
3730 if (!WiFiManagerClientCreate_p
)
3732 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCreate symbol failed.");
3737 if (!WiFiManagerClientCopyDevices_p
)
3739 WiFiManagerClientCopyDevices_p
= dlsym(MobileWiFiLib_p
, "WiFiManagerClientCopyDevices");
3740 if (!WiFiManagerClientCopyDevices_p
)
3742 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCopyDevices symbol failed.");
3747 if (!WiFiDeviceClientCopyCurrentNetwork_p
)
3749 WiFiDeviceClientCopyCurrentNetwork_p
= dlsym(MobileWiFiLib_p
, "WiFiDeviceClientCopyCurrentNetwork");
3750 if (!WiFiDeviceClientCopyCurrentNetwork_p
)
3752 LogInfo("MobileWiFiLibLoad: load of WiFiDeviceClientCopyCurrentNetwork symbol failed.");
3757 if (!WiFiNetworkIsCarPlay_p
)
3759 WiFiNetworkIsCarPlay_p
= dlsym(MobileWiFiLib_p
, "WiFiNetworkIsCarPlay");
3760 if (!WiFiNetworkIsCarPlay_p
)
3762 LogInfo("MobileWiFiLibLoad: load of WiFiNetworkIsCarPlay symbol failed.");
3767 isInitialized
= mDNStrue
;
3771 return isInitialized
;
3774 #define CARPLAY_DEBUG 0
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
)
3781 static WiFiManagerClientRef manager
= NULL
;
3783 WiFiDeviceClientRef device
;
3784 WiFiNetworkRef network
;
3785 mDNSBool rvalue
= mDNSfalse
;
3787 if (!MobileWiFiLibLoad())
3789 LogInfo("IsCarPlaySSID: MobileWiFiLibLoad() failed!");
3793 // Cache the WiFiManagerClientRef.
3794 if (manager
== NULL
)
3795 manager
= WiFiManagerClientCreate_p(NULL
, kWiFiClientTypeNormal
);
3797 if (manager
== NULL
)
3799 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3803 devices
= WiFiManagerClientCopyDevices_p(manager
);
3805 // If the first call fails, update the cached WiFiManagerClientRef pointer and try again.
3806 if (devices
== NULL
)
3808 LogInfo("IsCarPlaySSID: First call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name
);
3810 // Release the previously cached WiFiManagerClientRef which is apparently now stale.
3812 manager
= WiFiManagerClientCreate_p(NULL
, kWiFiClientTypeNormal
);
3813 if (manager
== NULL
)
3815 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3818 devices
= WiFiManagerClientCopyDevices_p(manager
);
3819 if (devices
== NULL
)
3821 LogInfo("IsCarPlaySSID: Second call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name
);
3826 device
= (WiFiDeviceClientRef
)CFArrayGetValueAtIndex(devices
, 0);
3827 network
= WiFiDeviceClientCopyCurrentNetwork_p(device
);
3828 if (network
!= NULL
)
3830 if (WiFiNetworkIsCarPlay_p(network
))
3832 LogInfo("IsCarPlaySSID: %s is CarPlay hosted", ifa_name
);
3837 LogInfo("IsCarPlaySSID: %s is NOT CarPlay hosted", ifa_name
);
3838 #endif // CARPLAY_DEBUG
3843 LogInfo("IsCarPlaySSID: WiFiDeviceClientCopyCurrentNetwork() returned NULL for %s", ifa_name
);
3850 #else // TARGET_OS_IPHONE
3852 mDNSlocal mDNSBool
IsCarPlaySSID(char *ifa_name
)
3854 (void)ifa_name
; // unused
3856 // OSX WifiManager currently does not implement WiFiNetworkIsCarPlay()
3860 #endif // TARGET_OS_IPHONE
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)
3867 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(const struct ifaddrs
*ifa
, const mDNSs32 utc
)
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
);
3875 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
3876 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
3878 NetworkInterfaceInfoOSX
**p
;
3879 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
3881 if (scope_id
== (*p
)->scope_id
&&
3882 mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) &&
3883 mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
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
);
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
);
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
));
3900 // Determine if multicast state has changed.
3901 const mDNSBool txrx
= MulticastInterface(*p
);
3902 if ((*p
)->ifinfo
.McastTxRx
!= txrx
)
3904 (*p
)->ifinfo
.McastTxRx
= txrx
;
3905 (*p
)->Exists
= MulticastStateChanged
; // State change; need to deregister and reregister this interface
3908 (*p
)->Exists
= mDNStrue
;
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
;
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
)
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
)
3926 if (NetWake
) mDNS_ActivateNetWake_internal (m
, &(*p
)->ifinfo
);
3927 else mDNS_DeactivateNetWake_internal(m
, &(*p
)->ifinfo
);
3931 // Reset the flag if it has changed this time.
3932 (*p
)->ifinfo
.IgnoreIPv4LL
= ((eflags
& IFEF_ARPLL
) != 0) ? mDNSfalse
: mDNStrue
;
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
;
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
;
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
;
3958 i
->ifinfo
.DirectLink
= IsCarPlaySSID(ifa
->ifa_name
);
3960 if (i
->ifinfo
.DirectLink
)
3961 LogInfo("AddInterfaceToList: DirectLink set for %s", ifa
->ifa_name
);
3965 i
->Exists
= mDNStrue
;
3966 i
->Flashing
= mDNSfalse
;
3967 i
->Occulting
= mDNSfalse
;
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
;
3974 if (eflags
& IFEF_AWDL
)
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
;
3983 i
->ifinfo
.SupportsUnicastMDNSResponse
= mDNStrue
;
3985 i
->AppearanceTime
= utc
; // Brand new interface; AppearanceTime is now
3987 i
->ifa_flags
= ifa
->ifa_flags
;
3988 i
->scope_id
= scope_id
;
3990 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
3994 i
->Registered
= mDNSNULL
;
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
);
4009 #if COMPILER_LIKES_PRAGMA_MARK
4011 #pragma mark - Power State & Configuration Change Management
4014 mDNSlocal mStatus
ReorderInterfaceList()
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();
4021 if (state
== mDNSNULL
)
4023 LogMsg("NWI State is NULL!");
4024 return (mStatus_Invalid
);
4027 // Get the count of interfaces
4028 mDNSu32 count
= nwi_state_get_interface_names(state
, mDNSNULL
, 0);
4031 LogMsg("Unable to get the ordered list of interface names");
4032 nwi_state_release(state
);
4033 return (mStatus_Invalid
);
4036 // Get the ordered interface list
4038 const char *names
[count
];
4039 count
= nwi_state_get_interface_names(state
, names
, count
);
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
)
4047 if (strcmp((*ptr
)->ifname
, names
[i
]) == 0)
4049 NetworkInterfaceInfo
*node
= *ptr
;
4050 *ptr
= (*ptr
)->next
;
4051 node
->next
= newList
;
4055 ptr
= &((*ptr
)->next
);
4059 // Get to the end of the list
4060 NetworkInterfaceInfo
*newListEnd
= newList
;
4061 while (newListEnd
!= mDNSNULL
&& newListEnd
->next
!= mDNSNULL
)
4062 newListEnd
= newListEnd
->next
;
4064 // Add any remaing interfaces to the end of the sorted list
4065 if (newListEnd
!= mDNSNULL
)
4066 newListEnd
->next
= m
->HostInterfaces
;
4068 // If we have a valid new list, point to that now
4069 if (newList
!= mDNSNULL
)
4070 m
->HostInterfaces
= newList
;
4072 nwi_state_release(state
);
4073 #endif // PR_30071012_FIXED
4074 return (mStatus_NoError
);
4077 mDNSlocal mStatus
UpdateInterfaceList(mDNSs32 utc
)
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
));
4086 if (m
->SleepState
== SleepState_Sleeping
) ifa
= NULL
;
4088 for (; ifa
; ifa
= ifa
->ifa_next
)
4090 #if LIST_ALL_INTERFACES
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
);
4104 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X ifa_addr is NOT set",
4105 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
);
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);
4125 if (!ifa
->ifa_addr
|| isExcludedInterface(InfoSocket
, ifa
->ifa_name
))
4130 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
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
))
4135 mDNSPlatformMemCopy(m
->PrimaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6);
4137 if (!AWDLInterfaceID
&& (sdl
->sdl_index
> 0))
4139 const uint64_t eflags
= getExtendedFlags(ifa
->ifa_name
);
4140 if (eflags
& IFEF_AWDL
)
4142 AWDLInterfaceID
= (mDNSInterfaceID
)((uintptr_t)sdl
->sdl_index
);
4143 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
,
4144 "UpdateInterfaceList: AWDLInterfaceID = %lu", (unsigned long) AWDLInterfaceID
);
4149 if (ifa
->ifa_flags
& IFF_UP
)
4151 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
4153 if (!ifa
->ifa_netmask
)
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
);
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)
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
);
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)
4172 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
));
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;
4181 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
4182 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
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
);
4193 if (!(ifru_flags6
& (IN6_IFF_TENTATIVE
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
4195 AddInterfaceToList(ifa
, utc
);
4202 if (InfoSocket
>= 0)
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]);
4208 // Set up the nice label
4209 domainlabel nicelabel
;
4211 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
4212 if (nicelabel
.c
[0] == 0)
4214 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname
);
4215 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
4218 // Set up the RFC 1034-compliant label
4219 domainlabel hostlabel
;
4221 GetUserSpecifiedLocalHostName(&hostlabel
);
4222 if (hostlabel
.c
[0] == 0)
4224 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname
);
4225 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
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
);
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
;
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
);
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
;
4249 return(mStatus_NoError
);
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
)
4256 int i
= 0, bits
= 0;
4257 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
4260 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
4261 while (b
& 0x80) { bits
++; b
<<= 1; }
4264 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
4268 mDNSlocal
void mDNSGroupJoinOrLeave(const int sock
, const NetworkInterfaceInfoOSX
*const i
, const mDNSBool join
)
4271 struct group_req gr
;
4272 mDNSPlatformMemZero(&gr
, sizeof(gr
));
4273 gr
.gr_interface
= i
->scope_id
;
4274 switch (i
->sa_family
)
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
;
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
);
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
);
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
);
4302 const int err
= setsockopt(sock
, level
, join
? MCAST_JOIN_GROUP
: MCAST_LEAVE_GROUP
, &gr
, sizeof(gr
));
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
)))
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
);
4320 #define mDNSGroupJoin(SOCK, INTERFACE) mDNSGroupJoinOrLeave(SOCK, INTERFACE, mDNStrue)
4321 #define mDNSGroupLeave(SOCK, INTERFACE) mDNSGroupJoinOrLeave(SOCK, INTERFACE, mDNSfalse)
4323 // Returns count of non-link local V4 addresses registered (why? -- SC)
4324 mDNSlocal
int SetupActiveInterfaces(mDNSs32 utc
)
4326 mDNS
*const m
= &mDNSStorage
;
4327 NetworkInterfaceInfoOSX
*i
;
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
)
4335 NetworkInterfaceInfo
*const n
= &i
->ifinfo
;
4336 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_UNSPEC
);
4338 if (i
->Registered
&& i
->Registered
!= primary
) // Sanity check
4340 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i
->Registered
, primary
);
4341 i
->Registered
= mDNSNULL
;
4346 InterfaceActivationSpeed activationSpeed
;
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
;
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);
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
)
4366 activationSpeed
= FastActivation
;
4367 LogInfo("SetupActiveInterfaces: %s DirectLink interface registering", i
->ifinfo
.ifname
);
4369 #if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
4370 else if (i
->Flashing
&& i
->Occulting
)
4372 activationSpeed
= SlowActivation
;
4377 activationSpeed
= NormalActivation
;
4380 mDNS_RegisterInterface(m
, n
, activationSpeed
);
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)" : "");
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
))
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
)
4402 mDNSGroupLeave(sock
, i
);
4409 if ((i
->sa_family
== AF_INET
) || (i
->sa_family
== AF_INET6
))
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
)
4424 mDNSGroupLeave(sock
, i
);
4426 mDNSGroupJoin(sock
, i
);
4435 mDNSlocal
void MarkAllInterfacesInactive(mDNSs32 utc
)
4437 NetworkInterfaceInfoOSX
*i
;
4438 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
4440 if (i
->Exists
) i
->LastSeen
= utc
;
4441 i
->Exists
= mDNSfalse
;
4445 // Returns count of non-link local V4 addresses deregistered (why? -- SC)
4446 mDNSlocal
int ClearInactiveInterfaces(mDNSs32 utc
)
4448 mDNS
*const m
= &mDNSStorage
;
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
;
4456 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
4458 // If this interface is no longer active, or its InterfaceID is changing, deregister it
4459 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_UNSPEC
);
4462 if (i
->Exists
== 0 || i
->Exists
== MulticastStateChanged
|| i
->Registered
!= primary
)
4464 InterfaceActivationSpeed activationSpeed
;
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)" : "");
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
)
4482 activationSpeed
= FastActivation
;
4483 LogInfo("ClearInactiveInterfaces: %s DirectLink interface deregistering", i
->ifinfo
.ifname
);
4485 #if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
4486 else if (i
->Flashing
&& i
->Occulting
)
4488 activationSpeed
= SlowActivation
;
4493 activationSpeed
= NormalActivation
;
4495 mDNS_DeregisterInterface(m
, &i
->ifinfo
, activationSpeed
);
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.
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.
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
;
4515 // If no longer active, delete interface from list and free memory
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
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
4539 mDNSlocal
void AppendDNameListElem(DNameListElem
***List
, mDNSu32 uid
, domainname
*name
)
4541 DNameListElem
*dnle
= (DNameListElem
*) callocL("DNameListElem/AppendDNameListElem", sizeof(*dnle
));
4542 if (!dnle
) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
4545 dnle
->next
= mDNSNULL
;
4547 AssignDomainName(&dnle
->name
, name
);
4549 *List
= &dnle
->next
;
4553 mDNSlocal
int compare_dns_configs(const void *aa
, const void *bb
)
4555 dns_resolver_t
*a
= *(dns_resolver_t
**)aa
;
4556 dns_resolver_t
*b
= *(dns_resolver_t
**)bb
;
4558 return (a
->search_order
< b
->search_order
) ? -1 : (a
->search_order
== b
->search_order
) ? 0 : 1;
4561 mDNSlocal
void UpdateSearchDomainHash(MD5_CTX
*sdc
, char *domain
, mDNSInterfaceID InterfaceID
)
4563 mDNS
*const m
= &mDNSStorage
;
4565 mDNSu32 scopeid
= 0;
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.
4575 // Note: We have to handle a few of these tricky cases.
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)
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.
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
);
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);
4596 mDNSlocal
void FinalizeSearchDomainHash(MD5_CTX
*sdc
)
4598 mDNS
*const m
= &mDNSStorage
;
4599 mDNSu8 md5_hash
[MD5_LEN
];
4601 MD5_Final(md5_hash
, sdc
);
4603 if (memcmp(md5_hash
, m
->SearchDomainsHash
, MD5_LEN
))
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
);
4612 else { LogInfo("FinalizeSearchDomains: The hash is same"); }
4615 mDNSlocal
void ConfigSearchDomains(dns_resolver_t
*resolver
, mDNSInterfaceID interfaceId
, mDNSu32 scope
, MD5_CTX
*sdc
, uint64_t generation
)
4617 const char *scopeString
= DNSScopeToString(scope
);
4621 if (scope
== kScopeNone
)
4622 interfaceId
= mDNSInterface_Any
;
4624 if (scope
== kScopeNone
|| scope
== kScopeInterfaceID
)
4626 for (j
= 0; j
< resolver
->n_search
; j
++)
4628 if (MakeDomainNameFromDNSNameString(&d
, resolver
->search
[j
]) != NULL
)
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
);
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
);
4646 LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString
, InterfaceNameForID(&mDNSStorage
, interfaceId
));
4650 mDNSlocal mDNSInterfaceID
ConfigParseInterfaceID(mDNSu32 ifindex
)
4652 NetworkInterfaceInfoOSX
*ni
;
4653 mDNSInterfaceID interface
;
4655 for (ni
= mDNSStorage
.p
->InterfaceList
; ni
; ni
= ni
->next
)
4657 if (ni
->ifinfo
.InterfaceID
&& ni
->scope_id
== ifindex
)
4662 interface
= ni
->ifinfo
.InterfaceID
;
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.
4672 LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex
);
4674 // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
4675 interface
= (mDNSInterfaceID
)(unsigned long)ifindex
;
4680 mDNSlocal
void ConfigNonUnicastResolver(dns_resolver_t
*r
)
4682 char *opt
= r
->options
;
4685 if (opt
&& !strncmp(opt
, "mdns", strlen(opt
)))
4687 if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
))
4689 LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r
->domain
);
4692 mDNS_AddMcastResolver(&mDNSStorage
, &d
, mDNSInterface_Any
, r
->timeout
);
4696 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
4697 mDNSlocal
void ConfigDNSServers(dns_resolver_t
*r
, mDNSInterfaceID interfaceID
, mDNSu32 scope
, mDNSu32 resGroupID
)
4700 if (!r
->domain
|| (*r
->domain
== '\0'))
4704 else if (!MakeDomainNameFromDNSNameString(&domain
, r
->domain
))
4706 LogMsg("ConfigDNSServers: bad domain %s", r
->domain
);
4709 // Parse the resolver specific attributes that affects all the DNS servers.
4710 const int32_t serviceID
= (scope
== kScopeServiceID
) ? r
->service_identifier
: 0;
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
;
4721 const mDNSBool isCell
= mDNSfalse
;
4724 const mDNSIPPort port
= (r
->port
!= 0) ? mDNSOpaque16fromIntVal(r
->port
) : UnicastDNSPort
;
4725 for (int32_t i
= 0; i
< r
->n_nameserver
; i
++)
4727 const int family
= r
->nameserver
[i
]->sa_family
;
4728 if ((family
!= AF_INET
) && (family
!= AF_INET6
)) continue;
4731 if (SetupAddr(&saddr
, r
->nameserver
[i
]))
4733 LogMsg("ConfigDNSServers: Bad address");
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
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
);
4749 LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s",
4750 DNSScopeToString(scope
), &s
->addr
, mDNSVal16(s
->port
), domain
.c
);
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.
4759 // "resolver" has entries that should only be used for unscoped questions.
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)
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)
4767 mDNSlocal
void ConfigResolvers(dns_config_t
*config
, mDNSu32 scope
, mDNSBool setsearch
, mDNSBool setservers
, MD5_CTX
*sdc
)
4770 dns_resolver_t
**resolver
;
4772 const char *scopeString
= DNSScopeToString(scope
);
4773 mDNSInterfaceID interface
;
4778 resolver
= config
->resolver
;
4779 nresolvers
= config
->n_resolver
;
4781 case kScopeInterfaceID
:
4782 resolver
= config
->scoped_resolver
;
4783 nresolvers
= config
->n_scoped_resolver
;
4785 case kScopeServiceID
:
4786 resolver
= config
->service_specific_resolver
;
4787 nresolvers
= config
->n_service_specific_resolver
;
4792 qsort(resolver
, nresolvers
, sizeof(dns_resolver_t
*), compare_dns_configs
);
4794 for (i
= 0; i
< nresolvers
; i
++)
4796 dns_resolver_t
*r
= resolver
[i
];
4798 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString
, i
, r
->domain
, r
->n_nameserver
);
4800 interface
= mDNSInterface_Any
;
4802 // Parse the interface index
4803 if (r
->if_index
!= 0)
4805 interface
= ConfigParseInterfaceID(r
->if_index
);
4810 ConfigSearchDomains(resolver
[i
], interface
, scope
, sdc
, config
->generation
);
4812 // Parse other scoped resolvers for search lists
4817 if (r
->port
== 5353 || r
->n_nameserver
== 0)
4819 ConfigNonUnicastResolver(r
);
4821 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
4824 ConfigDNSServers(r
, interface
, scope
, mDNS_GetNextResolverGroupID());
4830 #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
4831 mDNSlocal mDNSBool
QuestionValidForDNSTrigger(const DNSQuestion
*q
)
4835 debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4838 if (mDNSOpaque16IsZero(q
->TargetQID
))
4840 debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4843 // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
4845 if (q
->LOAddressAnswers
)
4847 debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
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
)
4858 mDNS
*const m
= &mDNSStorage
;
4859 if (!QuestionValidForDNSTrigger(q
))
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
)
4867 LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q
->qname
.c
, DNSTypeName(q
->qtype
));
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
)
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
));
4881 #endif // MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
4883 mDNSlocal
void AckConfigd(dns_config_t
*config
)
4885 mDNS_CheckLock(&mDNSStorage
);
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");
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
)
4897 mDNS
*const m
= &mDNSStorage
;
4898 mDNSBool trigger
= mDNSfalse
;
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.
4911 timenow
= m
->timenow
;
4912 if (m
->p
->DNSTrigger
&& (timenow
- m
->p
->DNSTrigger
) < DNS_TRIGGER_INTERVAL
)
4914 if (!m
->p
->v4answers
|| !m
->p
->v6answers
)
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
);
4923 if (v4q
!= NULL
&& QuestionValidForDNSTrigger(v4q
))
4925 int old
= m
->p
->v4answers
;
4927 m
->p
->v4answers
= 1;
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.
4934 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow
- m
->p
->DNSTrigger
),
4935 v4q
->qname
.c
, DNSTypeName(v4q
->qtype
));
4939 if (v6q
!= NULL
&& QuestionValidForDNSTrigger(v6q
))
4941 int old
= m
->p
->v6answers
;
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.
4949 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow
- m
->p
->DNSTrigger
),
4950 v6q
->qname
.c
, DNSTypeName(v6q
->qtype
));
4956 dns_config_t
*config
= dns_configuration_copy();
4962 dns_configuration_free(config
);
4966 LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
4970 #endif // MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
4972 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
4973 mDNSlocal
void SetupActiveDirectoryDomain(dns_config_t
*config
)
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])
4980 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain
, config
->resolver
[0]->domain
);
4984 ActiveDirectoryPrimaryDomain
.c
[0] = 0;
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
))
4992 SetupAddr(&ActiveDirectoryPrimaryDomainServer
, config
->resolver
[0]->nameserver
[0]);
4996 AssignConstStringDomainName(&ActiveDirectoryPrimaryDomain
, "");
4997 ActiveDirectoryPrimaryDomainLabelCount
= 0;
4998 ActiveDirectoryPrimaryDomainServer
= zeroAddr
;
5003 mDNSlocal
void SetupDDNSDomains(domainname
*const fqdn
, DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
)
5006 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NULL
5009 CFDictionaryRef ddnsdict
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_DynamicDNS
);
5014 CFArrayRef fqdnArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("HostNames"));
5015 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
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
))
5021 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
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)");
5028 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
5035 CFArrayRef regArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("RegistrationDomains"));
5036 if (regArray
&& CFArrayGetCount(regArray
) > 0)
5038 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
5039 if (regDict
&& DictionaryIsEnabled(regDict
))
5041 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
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)");
5049 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf
);
5050 AppendDNameListElem(&RegDomains
, 0, &d
);
5058 CFArrayRef browseArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("BrowseDomains"));
5061 for (i
= 0; i
< CFArrayGetCount(browseArray
); i
++)
5063 CFDictionaryRef browseDict
= CFArrayGetValueAtIndex(browseArray
, i
);
5064 if (browseDict
&& DictionaryIsEnabled(browseDict
))
5066 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
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)");
5074 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf
);
5075 AppendDNameListElem(&BrowseDomains
, 0, &d
);
5082 CFRelease(ddnsdict
);
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
)
5090 mDNS
*const m
= &mDNSStorage
;
5091 MD5_CTX sdc
; // search domain context
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
;
5098 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
5099 setservers
? " setservers" : "",
5100 setsearch
? " setsearch" : "",
5101 fqdn
? " fqdn" : "",
5102 RegDomains
? " RegDomains" : "",
5103 BrowseDomains
? " BrowseDomains" : "");
5105 if (setsearch
) MD5_Init(&sdc
);
5107 // Add the inferred address-based configuration discovery domains
5108 // (should really be in core code I think, not platform-specific)
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
;
5117 saddr
.sin_addr
.s_addr
= *(in_addr_t
*)&m
->Router
.ip
.v4
;
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);
5127 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
5129 !(ifa
->ifa_flags
& IFF_LOOPBACK
) &&
5130 !SetupAddr(&a
, ifa
->ifa_addr
) &&
5131 !mDNSv4AddressIsLinkLocal(&a
.ip
.v4
) )
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
);
5145 ifa
= ifa
->ifa_next
;
5149 #ifndef MDNS_NO_DNSINFO
5150 if (setservers
|| setsearch
)
5152 dns_config_t
*config
= dns_configuration_copy();
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");
5164 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config
->n_resolver
, config
->generation
, m
->p
->LastConfigGeneration
);
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.
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.
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
)
5184 if (setservers
&& !m
->p
->if_interface_changed
&& m
->p
->LastConfigGeneration
== config
->generation
)
5187 LogInfo("mDNSPlatformSetDNSConfig(setservers): generation number %llu same, not processing", config
->generation
);
5188 dns_configuration_free(config
);
5189 SetupDDNSDomains(fqdn
, RegDomains
, BrowseDomains
);
5192 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
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
;
5201 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
5202 SetupActiveDirectoryDomain(config
);
5204 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
5205 if (setservers
) Querier_ApplyDNSConfig(config
);
5207 ConfigResolvers(config
, kScopeNone
, setsearch
, setservers
, &sdc
);
5208 ConfigResolvers(config
, kScopeInterfaceID
, setsearch
, setservers
, &sdc
);
5209 ConfigResolvers(config
, kScopeServiceID
, setsearch
, setservers
, &sdc
);
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
--)
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
);
5219 for (server
= m
->DNSServers
; server
; server
= server
->next
)
5221 if ((((uintptr_t)server
->interface
) == ifIndex
) && !(server
->flags
& DNSServerFlag_Delete
))
5228 mdns_retain(monitor
);
5229 CFArrayRemoveValueAtIndex(m
->p
->InterfaceMonitors
, i
);
5230 mdns_interface_monitor_invalidate(monitor
);
5231 mdns_release(monitor
);
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.
5241 // Note: We have to set the generation number here when we are acking.
5242 // For every DNS configuration change, we do the following:
5244 // 1) Copy dns configuration, handle search domains change
5245 // 2) Copy dns configuration, handle dns server change
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
5251 m
->p
->LastConfigGeneration
= config
->generation
;
5252 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers
, setsearch
);
5255 dns_configuration_free(config
);
5256 if (setsearch
) FinalizeSearchDomainHash(&sdc
);
5259 #endif // MDNS_NO_DNSINFO
5260 SetupDDNSDomains(fqdn
, RegDomains
, BrowseDomains
);
5265 mDNSexport mStatus
mDNSPlatformGetPrimaryInterface(mDNSAddr
*v4
, mDNSAddr
*v6
, mDNSAddr
*r
)
5269 CFDictionaryRef dict
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_IPv4
);
5272 r
->type
= mDNSAddrType_IPv4
;
5273 r
->ip
.v4
= zerov4Addr
;
5274 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
5277 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
5278 LogMsg("Could not convert router to CString");
5281 struct sockaddr_in saddr
;
5282 saddr
.sin_len
= sizeof(saddr
);
5283 saddr
.sin_family
= AF_INET
;
5285 inet_aton(buf
, &saddr
.sin_addr
);
5286 *(in_addr_t
*)&r
->ip
.v4
= saddr
.sin_addr
.s_addr
;
5289 string
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
5292 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
5293 struct ifaddrs
*ifa
= myGetIfAddrs(1);
5294 *v4
= *v6
= zeroAddr
;
5296 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
5298 LogMsg("Could not convert router to CString");
5301 // find primary interface in list
5302 while (ifa
&& (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
) || !HavePrimaryGlobalv6
))
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
;
5310 mDNSAddr tmp6
= zeroAddr
;
5311 if (!strcmp(buf
, ifa
->ifa_name
))
5313 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
5315 if (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
))
5316 SetupAddr(v4
, ifa
->ifa_addr
);
5318 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
5320 SetupAddr(&tmp6
, ifa
->ifa_addr
);
5321 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
5323 HavePrimaryGlobalv6
= mDNStrue
;
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])
5333 SetupAddr(&tmp6
, ifa
->ifa_addr
);
5334 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1)
5338 ifa
= ifa
->ifa_next
;
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
5347 return mStatus_NoError
;
5350 mDNSexport
void mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
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
);
5360 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
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).
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
);
5378 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
5379 if (StatusVals
[0] == NULL
) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status
);
5382 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
5385 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
5388 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
5391 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig
, mDNSNULL
, StateDict
);
5392 CFRelease(StateDict
);
5394 CFRelease(StateVals
[0]);
5396 CFRelease(HostVals
[0]);
5398 CFRelease(StatusVals
[0]);
5400 CFRelease(HostKeys
[0]);
5404 // MUST be called holding the lock
5405 mDNSlocal
void SetDomainSecrets_internal(mDNS
*m
)
5407 #ifdef NO_SECURITYFRAMEWORK
5409 LogMsg("Note: SetDomainSecrets: no keychain support");
5412 LogInfo("SetDomainSecrets");
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);
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; }
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
);
5435 CFIndex ArrayCount
= CFArrayGetCount(secrets
);
5436 // Iterate through the secrets
5437 for (i
= 0; i
< ArrayCount
; ++i
)
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; }
5448 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
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';
5460 if (!strncmp(stringbuf
, dnsprefix
, strlen(dnsprefix
)))
5461 offset
= strlen(dnsprefix
);
5464 if (!MakeDomainNameFromDNSNameString(&domain
, stringbuf
+ offset
)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf
); continue; }
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';
5474 if (!MakeDomainNameFromDNSNameString(&keyname
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf
); continue; }
5476 // Get key data (kmDNSKcKey)
5477 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcKey
);
5478 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
5480 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data
));
5483 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
5484 stringbuf
[CFDataGetLength(data
)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
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
))
5492 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data
));
5495 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)hostbuf
);
5496 hostbuf
[CFDataGetLength(data
)] = '\0';
5498 domainname hostname
;
5501 hptr
= strchr(hostbuf
, ':');
5503 port
.NotAnInteger
= 0;
5510 while(hptr
&& *hptr
!= 0)
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';
5519 port
.NotAnInteger
= p
[0] << 8 | p
[1];
5521 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
5522 hptr
= strchr(hostbuf
, '@');
5527 if (!MakeDomainNameFromDNSNameString(&hostname
, hptr
)) { LogMsg("SetDomainSecrets: bad host name %s", hptr
); continue; }
5529 DomainAuthInfo
*FoundInList
;
5530 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
5531 if (SameDomainName(&FoundInList
->domain
, &domain
)) break;
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]));
5538 // If didn't find desired domain in the list, make a new entry
5542 ptr
= (DomainAuthInfo
*) callocL("DomainAuthInfo", sizeof(*ptr
));
5543 if (!ptr
) { LogMsg("SetDomainSecrets: No memory"); continue; }
5546 if (mDNS_SetSecretForDomain(m
, ptr
, &domain
, &keyname
, stringbuf
, &hostname
, &port
) == mStatus_BadParamErr
)
5548 if (!FoundInList
) mDNSPlatformMemFree(ptr
); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
5552 ConvertDomainNameToCString(&domain
, stringbuf
);
5553 CFStringRef cfs
= CFStringCreateWithCString(NULL
, stringbuf
, kCFStringEncodingUTF8
);
5554 if (cfs
) { CFArrayAppendValue(sa
, cfs
); CFRelease(cfs
); }
5559 if (!privateDnsArray
|| !CFEqual(privateDnsArray
, sa
))
5561 if (privateDnsArray
)
5562 CFRelease(privateDnsArray
);
5564 privateDnsArray
= sa
;
5565 CFRetain(privateDnsArray
);
5566 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, mDNSNULL
, privateDnsArray
);
5570 CheckSuppressUnusableQuestions(m
);
5572 #endif /* NO_SECURITYFRAMEWORK */
5575 mDNSexport
void SetDomainSecrets(mDNS
*m
)
5578 // Don't get secrets for BTMM if running in debug mode
5579 if (!IsDebugSocketInUse())
5581 SetDomainSecrets_internal(m
);
5584 mDNSlocal
void SetLocalDomains(void)
5586 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
5587 if (!sa
) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
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"));
5596 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig
, mDNSNULL
, sa
);
5600 #if !MDNSRESPONDER_SUPPORTS(APPLE, NO_WAKE_FOR_NET_ACCESS)
5601 mDNSlocal
void GetCurrentPMSetting(const CFStringRef name
, mDNSs32
*val
)
5603 CFDictionaryRef dict
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_PowerSettings
);
5606 LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
5610 CFNumberRef number
= CFDictionaryGetValue(dict
, name
);
5611 if ((number
== NULL
) || CFGetTypeID(number
) != CFNumberGetTypeID() || !CFNumberGetValue(number
, kCFNumberSInt32Type
, val
))
5618 #if APPLE_OSX_mDNSResponder
5620 static CFMutableDictionaryRef spsStatusDict
= NULL
;
5621 static const CFStringRef kMetricRef
= CFSTR("Metric");
5623 mDNSlocal
void SPSStatusPutNumber(CFMutableDictionaryRef dict
, const mDNSu8
* const ptr
, CFStringRef key
)
5625 mDNSu8 tmp
= (ptr
[0] - '0') * 10 + ptr
[1] - '0';
5626 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt8Type
, &tmp
);
5628 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
5631 CFDictionarySetValue(dict
, key
, num
);
5636 mDNSlocal CFMutableDictionaryRef
SPSCreateDict(const mDNSu8
* const ptr
)
5638 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
5639 if (!dict
) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict
; }
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
);
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"));
5653 mDNSu32 tmp
= SPSMetric(ptr
);
5654 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tmp
);
5656 LogMsg("SPSCreateDict: Could not create CFNumber");
5659 CFDictionarySetValue(dict
, kMetricRef
, num
);
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
; }
5671 CFDictionarySetValue(dict
, CFSTR("PrettyName"), spsname
);
5679 mDNSlocal CFComparisonResult
CompareSPSEntries(const void *val1
, const void *val2
, void *context
)
5682 return CFNumberCompare((CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val1
, kMetricRef
),
5683 (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val2
, kMetricRef
),
5687 mDNSlocal
void UpdateSPSStatus(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
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>");
5693 mDNS_UpdateAllowSleep(m
);
5696 if (answer
&& SPSMetric(answer
->rdata
->u
.name
.c
) > 999999) return; // Ignore instances with invalid names
5700 spsStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
5701 if (!spsStatusDict
) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
5704 CFStringRef ifname
= CFStringCreateWithCString(NULL
, info
->ifname
, kCFStringEncodingUTF8
);
5705 if (!ifname
) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
5707 CFMutableArrayRef array
= NULL
;
5709 if (!CFDictionaryGetValueIfPresent(spsStatusDict
, ifname
, (const void**) &array
))
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
5717 if (!array
) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info
->ifname
); CFRelease(ifname
); return; }
5719 if (!answer
) // special call that means the question has been stopped (because the interface is going away)
5720 CFArrayRemoveAllValues(array
);
5723 CFMutableDictionaryRef dict
= SPSCreateDict(answer
->rdata
->u
.name
.c
);
5724 if (!dict
) { CFRelease(ifname
); return; }
5728 if (!CFArrayContainsValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), dict
))
5731 for (i
=0; i
<CFArrayGetCount(array
); i
++)
5732 if (CompareSPSEntries(CFArrayGetValueAtIndex(array
, i
), dict
, NULL
) != kCFCompareLessThan
)
5734 CFArrayInsertValueAtIndex(array
, i
, dict
);
5736 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info
->ifname
, answer
->rdata
->u
.name
.c
);
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
);
5748 if (!m
->ShutdownTime
) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState
, info
->ifname
, array
);
5753 mDNSlocal mDNSs32
GetSystemSleepTimerSetting(void)
5756 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL
, NULL
);
5758 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5761 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_PowerSettings
);
5764 CFNumberRef number
= CFDictionaryGetValue(dict
, CFSTR("System Sleep Timer"));
5765 if (number
!= NULL
) CFNumberGetValue(number
, kCFNumberSInt32Type
, &val
);
5773 mDNSlocal
void SetSPS(mDNS
*const m
)
5776 // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
5777 mDNSu8 sps
= (OfferSleepProxyService
&& GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware
: 0;
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;
5783 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
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
;
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
;
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.
5798 NetworkInterfaceInfo
*intf
= mDNSNULL
;
5799 mDNSEthAddr bssid
= zeroEthAddr
;
5800 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
5802 if (intf
->InterfaceID
== AWDLInterfaceID
) continue;
5803 bssid
= GetBSSID(intf
->ifname
);
5804 if (!mDNSSameEthAddress(&bssid
, &zeroEthAddr
))
5806 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
5812 #endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI
5814 mDNSCoreBeSleepProxyServer(m
, sps
, SPMetricPortability
, SPMetricMarginalPower
, SPMetricTotalPower
, SPMetricFeatures
);
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.
5822 { // commands from the daemon to the driver
5823 cmd_mDNSOffloadRR
= 21, // give the mdns update buffer to the driver
5826 typedef union { void *ptr
; mDNSOpaque64 sixtyfourbits
; } FatPtr
;
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)
5841 #include <IOKit/IOKitLib.h>
5842 #include <dns_util.h>
5844 mDNSlocal mDNSu32
GetPortArray(int trans
, mDNSIPPort
*portarray
)
5846 mDNS
*const m
= &mDNSStorage
;
5847 const domainlabel
*const tp
= (trans
== mDNSTransport_UDP
) ? (const domainlabel
*)"\x4_udp" : (const domainlabel
*)"\x4_tcp";
5851 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
5853 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainLabel(ThirdLabel(rr
->resrec
.name
)->c
, tp
->c
))
5860 for (i
= 0; i
< count
; i
++)
5861 if (mDNSSameIPPort(portarray
[i
], rr
->resrec
.rdata
->u
.srv
.port
))
5864 // Add it into the port list only if it not already present in the list
5866 portarray
[count
++] = rr
->resrec
.rdata
->u
.srv
.port
;
5873 #if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
5874 mDNSlocal mDNSBool
SupportsTCPKeepAlive()
5876 IOReturn ret
= kIOReturnSuccess
;
5877 CFTypeRef obj
= NULL
;
5878 mDNSBool supports
= mDNSfalse
;
5880 ret
= IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj
);
5881 if ((kIOReturnSuccess
== ret
) && (obj
!= NULL
))
5883 supports
= (obj
== kCFBooleanTrue
)? mDNStrue
: mDNSfalse
;
5886 LogSPS("%s: The hardware %s TCP Keep Alive", __func__
, (supports
? "supports" : "does not support"));
5890 mDNSlocal mDNSBool
OnBattery(void)
5892 CFTypeRef powerInfo
= IOPSCopyPowerSourcesInfo();
5893 CFTypeRef powerSrc
= IOPSGetProvidingPowerSourceType(powerInfo
);
5894 mDNSBool result
= mDNSfalse
;
5896 if (powerInfo
!= NULL
)
5898 result
= CFEqual(CFSTR(kIOPSBatteryPowerValue
), powerSrc
);
5899 CFRelease(powerInfo
);
5901 LogSPS("%s: The system is on %s", __func__
, (result
)? "Battery" : "AC Power");
5906 #define TfrRecordToNIC(RR) \
5907 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
5909 mDNSlocal mDNSu32
CountProxyRecords(uint32_t *const numbytes
, mDNSBool TCPKAOnly
, mDNSBool supportsTCPKA
)
5911 mDNS
*const m
= &mDNSStorage
;
5914 mDNSBool isKeepAliveRecord
= mDNSfalse
;
5918 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
5920 if (!(rr
->AuthFlags
& AuthFlagsWakeOnly
) && rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
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
))
5929 (void) TCPKAOnly
; // unused
5930 (void) supportsTCPKA
; // unused
5932 if (TfrRecordToNIC(rr
))
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
));
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
)
5949 mDNS
*const m
= &mDNSStorage
;
5950 mDNSu8
*p
= msg
->data
;
5951 const mDNSu8
*const limit
= p
+ *numbytes
;
5952 InitializeDNSMessage(&msg
->h
, zeroID
, zeroID
);
5957 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
5959 if (!(rr
->AuthFlags
& AuthFlagsWakeOnly
) && rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
5961 #if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
5962 const mDNSBool isKeepAliveRecord
= mDNS_KeepaliveRecord(&rr
->resrec
);
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
))
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
)
5975 if (UpdateKeepaliveRData(m
, rr
, intf
, mDNSfalse
, mDNSNULL
) != mStatus_NoError
)
5977 LogSPS("GetProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m
, rr
));
5980 // Offload only Valid Keepalive records
5981 if (!mDNSValidKeepAliveRecord(rr
))
5987 (void) intf
; // unused
5988 (void) TCPKAOnly
; // unused
5989 (void) supportsTCPKA
; // unused
5991 if (TfrRecordToNIC(rr
))
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
));
6005 *numbytes
= (mDNSu32
)(p
- msg
->data
);
6006 if (outRecordCount
) *outRecordCount
= count
;
6009 mDNSexport mDNSBool
SupportsInNICProxy(NetworkInterfaceInfo
*const intf
)
6011 if(!UseInternalSleepProxy
)
6013 LogMsg("SupportsInNICProxy: Internal Sleep Proxy is disabled");
6016 return CheckInterfaceSupport(intf
, mDNS_IOREG_KEY
);
6019 // Called with the lock held
6020 mDNSexport mStatus
ActivateLocalProxy(NetworkInterfaceInfo
*const intf
, mDNSBool offloadKeepAlivesOnly
, mDNSBool
*keepaliveOnly
)
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
));
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
)
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());
6039 TCPKAOnly
= mDNStrue
;
6042 (void)offloadKeepAlivesOnly
; // Unused.
6044 if (!service
) { LogMsg("ActivateLocalProxy: No service for interface %s", intf
->ifname
); return(mStatus_UnknownErr
); }
6047 IOObjectGetClass(service
, n1
);
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
);
6056 IOObjectGetClass(parent
, n2
);
6057 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf
->ifname
, n1
, n2
);
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
);
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
);
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
);
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
;
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
);
6090 if (msg
&& cmd
.rrRecords
.ptr
)
6092 GetProxyRecords(msg
, &cmd
.rrBufferSize
, cmd
.rrRecords
.ptr
, &cmd
.numRRRecords
, intf
, TCPKAOnly
, supportsTCPKA
);
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
);
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
;
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
);
6111 IOObjectRelease(parent
);
6113 *keepaliveOnly
= (TCPKAOnly
&& supportsTCPKA
) ? mDNStrue
: mDNSfalse
;
6117 #endif // APPLE_OSX_mDNSResponder
6119 mDNSlocal mDNSu8
SystemWakeForNetworkAccess(void)
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
);
6126 mDNSu8 ret
= (mDNSu8
)mDNS_NoWake
;
6128 if (DisableSleepProxyClient
)
6130 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
6134 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val
);
6136 ret
= (mDNSu8
)(val
!= 0) ? mDNS_WakeOnAC
: mDNS_NoWake
;
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
6145 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret
);
6150 mDNSlocal mDNSBool
SystemSleepOnlyIfWakeOnLAN(void)
6153 // PrioritizeNetworkReachabilityOverSleep has been deprecated.
6154 // GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
6155 // Statically set the PrioritizeNetworkReachabilityOverSleep value to 1 for AppleTV
6158 return val
!= 0 ? mDNStrue
: mDNSfalse
;
6161 mDNSlocal mDNSBool
IsAppleNetwork(mDNS
*const m
)
6163 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
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
)
6170 if (s
->addr
.ip
.v4
.b
[0] == 17)
6172 LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s
->domain
.c
, &s
->addr
);
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
)
6184 mDNS
*const m
= &mDNSStorage
;
6186 if (!m
->NetworkChanged
|| m
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) > 0)
6188 m
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
6189 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
, "SetNetworkChanged: Scheduling in %d ticks", delay
);
6193 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
,
6194 "SetNetworkChanged: *NOT* increasing delay from %d to %d", m
->NetworkChanged
- m
->timenow
, delay
);
6198 // Called with KQueueLock & mDNS lock
6199 mDNSlocal
void SetKeyChainTimer(mDNSs32 delay
)
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)
6205 m
->p
->KeyChainTimer
= NonZeroTime(m
->timenow
+ delay
);
6206 LogInfo("SetKeyChainTimer: %d", delay
);
6210 mDNSexport
void mDNSMacOSXNetworkChanged(void)
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
6219 // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring
6220 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
6223 mDNSBool tentative
= mDNSfalse
;
6224 struct ifaddrs
*ifa
= myGetIfAddrs(1);
6227 if (ifa
->ifa_addr
&& ifa
->ifa_addr
->sa_family
== AF_INET6
)
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)
6239 if (ifr6
.ifr_ifru
.ifru_flags6
& IN6_IFF_TENTATIVE
)
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
6250 ifa
= ifa
->ifa_next
;
6256 SetNetworkChanged(mDNSPlatformOneSecond
/ 2);
6260 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
,
6261 "*** Network Configuration Change *** No IPv6 address TENTATIVE, will continue");
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();
6273 #if APPLE_OSX_mDNSResponder
6276 NetworkInterfaceInfoOSX
*i
;
6277 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
6279 if (!m
->SPSSocket
) // Not being Sleep Proxy Server; close any open BPF fds
6281 if (i
->BPF_fd
>= 0 && CountProxyTargets(i
, mDNSNULL
, mDNSNULL
) == 0)
6284 else // else, we're Sleep Proxy Server; open BPF fds
6286 if (i
->Exists
&& (i
->Registered
== i
) && SPSInterface(i
) && i
->BPF_fd
== -1)
6288 LogMsg("%s mDNSMacOSXNetworkChanged: requesting BPF", i
->ifinfo
.ifname
);
6295 #endif // APPLE_OSX_mDNSResponder
6297 uDNS_SetupDNSConfig(m
);
6298 mDNS_ConfigChanged(m
);
6300 if (IsAppleNetwork(m
) != mDNS_McastTracingEnabled
)
6302 mDNS_McastTracingEnabled
= mDNS_McastTracingEnabled
? mDNSfalse
: mDNStrue
;
6303 LogInfo("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled
? "Enabled" : "Disabled");
6309 // Copy the fourth slash-delimited element from either:
6310 // State:/Network/Interface/<bsdname>/IPv4
6312 // Setup:/Network/Service/<servicename>/Interface
6313 mDNSlocal CFStringRef
CopyNameFromKey(CFStringRef key
)
6316 CFStringRef name
= NULL
;
6318 a
= CFStringCreateArrayBySeparatingStrings(NULL
, key
, CFSTR("/"));
6319 if (a
&& CFArrayGetCount(a
) == 5) name
= CFRetain(CFArrayGetValueAtIndex(a
, 3));
6320 if (a
!= NULL
) CFRelease(a
);
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
)
6329 CFDictionaryRef dict
= NULL
;
6330 CFMutableArrayRef a
;
6331 const void **keys
= NULL
, **vals
= NULL
;
6332 CFStringRef pattern
= NULL
;
6333 CFIndex i
, ic
, j
, jc
;
6336 jc
= CFArrayGetCount(inkeys
);
6337 if (jc
<= 0) goto done
;
6339 a
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6340 if (a
== NULL
) goto done
;
6342 // Setup:/Network/Service/[^/]+/Interface
6343 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetInterface
);
6344 if (pattern
== NULL
) goto done
;
6345 CFArrayAppendValue(a
, pattern
);
6348 // Setup:/Network/Service/[^/]+/IPv4
6349 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetIPv4
);
6350 if (pattern
== NULL
) goto done
;
6351 CFArrayAppendValue(a
, pattern
);
6354 dict
= SCDynamicStoreCopyMultiple(NULL
, NULL
, a
);
6359 LogMsg("ChangedKeysHaveIPv4LL: No dictionary");
6363 ic
= CFDictionaryGetCount(dict
);
6366 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
6370 vals
= (const void **) mDNSPlatformMemAllocate(sizeof(void *) * (mDNSu32
)ic
);
6371 keys
= (const void **) mDNSPlatformMemAllocate(sizeof(void *) * (mDNSu32
)ic
);
6372 CFDictionaryGetKeysAndValues(dict
, keys
, vals
);
6374 // For each key we were given...
6375 for (j
= 0; j
< jc
; j
++)
6377 CFStringRef key
= CFArrayGetValueAtIndex(inkeys
, j
);
6378 CFStringRef ifname
= NULL
;
6382 // It would be nice to use a regex here
6383 if (!CFStringHasPrefix(key
, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key
, kSCEntNetIPv4
)) continue;
6385 if ((ifname
= CopyNameFromKey(key
)) == NULL
) continue;
6386 if (mDNS_LoggingEnabled
)
6388 if (!CFStringGetCString(ifname
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
6389 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf
);
6392 // Loop over the interfaces to find matching the ifname, and see if that one has kSCValNetIPv4ConfigMethodLinkLocal
6393 for (i
= 0; i
< ic
; i
++)
6395 CFDictionaryRef ipv4dict
;
6397 CFStringRef serviceid
;
6398 CFStringRef configmethod
;
6400 if (!CFStringHasSuffix(keys
[i
], kSCEntNetInterface
)) continue;
6402 if (CFDictionaryGetTypeID() != CFGetTypeID(vals
[i
])) continue;
6404 if ((name
= CFDictionaryGetValue(vals
[i
], kSCPropNetInterfaceDeviceName
)) == NULL
) continue;
6406 if (!CFEqual(ifname
, name
)) continue;
6408 if ((serviceid
= CopyNameFromKey(keys
[i
])) == NULL
) continue;
6409 if (mDNS_LoggingEnabled
)
6411 if (!CFStringGetCString(serviceid
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
6412 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf
);
6415 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceid
, kSCEntNetIPv4
);
6416 CFRelease(serviceid
);
6417 if (pattern
== NULL
) continue;
6419 ipv4dict
= CFDictionaryGetValue(dict
, pattern
);
6421 if (!ipv4dict
|| CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict
)) continue;
6423 configmethod
= CFDictionaryGetValue(ipv4dict
, kSCPropNetIPv4ConfigMethod
);
6424 if (!configmethod
) continue;
6426 if (mDNS_LoggingEnabled
)
6428 if (!CFStringGetCString(configmethod
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
6429 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf
);
6432 if (CFEqual(configmethod
, kSCValNetIPv4ConfigMethodLinkLocal
)) { found
++; break; }
6439 if (vals
!= NULL
) mDNSPlatformMemFree(vals
);
6440 if (keys
!= NULL
) mDNSPlatformMemFree(keys
);
6441 if (dict
!= NULL
) CFRelease(dict
);
6446 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
6448 (void)store
; // Parameter not used
6449 mDNS
*const m
= (mDNS
*const)context
;
6453 //mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
6454 const mDNSs32 delay
= (mDNSPlatformOneSecond
+ 39) / 40; // 25 ms delay
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
);
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
6471 for (CFIndex i
= 0; i
< c
; i
++)
6473 CFStringRef key
= CFArrayGetValueAtIndex(changedKeys
, i
);
6475 // Only look at keys with prefix "State:/Network/Interface/"
6476 if (!CFStringHasPrefix(key
, NetworkChangedKey_StateInterfacePrefix
))
6479 // And suffix "IPv6" or "IPv4".
6480 if (!CFStringHasSuffix(key
, kSCEntNetIPv6
) && !CFStringHasSuffix(key
, kSCEntNetIPv4
))
6483 labels
= CFStringCreateArrayBySeparatingStrings(NULL
, key
, CFSTR("/"));
6486 n
= CFArrayGetCount(labels
);
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.
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
)))
6499 LogInfo("NetworkChanged: interface %s qualifies for reduced change handling delay", buf
);
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
6512 if (mDNS_LoggingEnabled
)
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
);
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) " : "",
6531 c_ddns
? " + SetKeyChainTimer" : "");
6534 SetNetworkChanged(delay
);
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.
6542 SetKeyChainTimer(delay
);
6544 // Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
6547 KQueueUnlock("NetworkChanged");
6550 #if APPLE_OSX_mDNSResponder
6551 mDNSlocal
void RefreshSPSStatus(const void *key
, const void *value
, void *context
)
6556 CFStringRef ifnameStr
= (CFStringRef
)key
;
6557 CFArrayRef array
= (CFArrayRef
)value
;
6558 if (!CFStringGetCString(ifnameStr
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
6561 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf
, CFArrayGetCount(array
));
6562 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState
, buf
, value
);
6566 mDNSlocal
void DynamicStoreReconnected(SCDynamicStoreRef store
, void *info
)
6568 mDNS
*const m
= (mDNS
*const)info
;
6571 KQueueLock(); // serialize with KQueueLoop()
6573 LogInfo("DynamicStoreReconnected: Reconnected");
6575 // State:/Network/MulticastDNS
6578 // State:/Network/DynamicDNS
6580 mDNSPlatformDynDNSHostNameStatusChanged(&m
->FQDN
, 1);
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.
6586 // State:/Network/PrivateDNS
6587 if (privateDnsArray
)
6588 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, mDNSNULL
, privateDnsArray
);
6590 #if APPLE_OSX_mDNSResponder
6591 // State:/Network/Interface/en0/SleepProxyServers
6593 CFDictionaryApplyFunction(spsStatusDict
, RefreshSPSStatus
, NULL
);
6595 KQueueUnlock("DynamicStoreReconnected");
6598 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
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
);
6608 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
6609 if (!keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
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
; }
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
; }
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
);
6632 SCDynamicStoreSetDisconnectCallBack(store
, DynamicStoreReconnected
);
6633 m
->p
->Store
= store
;
6638 if (store
) CFRelease(store
);
6641 if (patterns
) CFRelease(patterns
);
6642 if (pattern2
) CFRelease(pattern2
);
6643 if (pattern1
) CFRelease(pattern1
);
6644 if (keys
) CFRelease(keys
);
6650 mDNSlocal
void mDNSSetPacketFilterRules(char * ifname
, const ResourceRecord
*const excludeRecord
)
6652 mDNS
*const m
= &mDNSStorage
;
6654 pfArray_t portArray
;
6655 pfArray_t protocolArray
;
6658 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6660 if ((rr
->resrec
.rrtype
== kDNSServiceType_SRV
)
6661 && ((rr
->ARType
== AuthRecordAnyIncludeP2P
) || (rr
->ARType
== AuthRecordAnyIncludeAWDLandP2P
)))
6665 if (count
>= PFPortArraySize
)
6667 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize
, ARDisplayString(m
, rr
));
6671 if (excludeRecord
&& IdenticalResourceRecord(&rr
->resrec
, excludeRecord
))
6673 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m
, rr
));
6677 LogMsg("mDNSSetPacketFilterRules: found %s", ARDisplayString(m
, rr
));
6679 portArray
[count
] = rr
->resrec
.rdata
->u
.srv
.port
.NotAnInteger
;
6681 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
6682 p
= rr
->resrec
.name
->c
;
6684 // Skip to App Protocol
6688 // Skip to Transport Protocol
6692 if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_tcp"))
6694 protocolArray
[count
] = IPPROTO_TCP
;
6696 else if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_udp"))
6698 protocolArray
[count
] = IPPROTO_UDP
;
6702 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
6703 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m
, rr
));
6709 mDNSPacketFilterControl(PF_SET_RULES
, ifname
, count
, portArray
, protocolArray
);
6712 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
6713 mDNSexport
void mDNSUpdatePacketFilter(const ResourceRecord
*const excludeRecord
)
6715 mDNS
*const m
= &mDNSStorage
;
6717 NetworkInterfaceInfo
*intf
= GetFirstActiveInterface(m
->HostInterfaces
);
6720 if (strncmp(intf
->ifname
, "p2p", 3) == 0)
6722 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf
->ifname
);
6723 mDNSSetPacketFilterRules(intf
->ifname
, excludeRecord
);
6726 intf
= GetFirstActiveInterface(intf
->next
);
6729 #else // !TARGET_OS_OSX
6730 // Currently no packet filter setup required on embedded platforms.
6731 mDNSexport
void mDNSUpdatePacketFilter(const ResourceRecord
*const excludeRecord
)
6733 (void) excludeRecord
; // unused
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
)
6740 char ifname
[IFNAMSIZ
];
6741 mDNSu32 interfaceIndex
;
6743 snprintf(ifname
, IFNAMSIZ
, "%s%d", ptr
->if_name
, ptr
->if_unit
);
6744 interfaceIndex
= if_nametoindex(ifname
);
6746 if (!interfaceIndex
)
6748 LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname
);
6752 LogInfo("newMasterElected: KEV_DL_MASTER_ELECTED received on ifname = %s, interfaceIndex = %d", ifname
, interfaceIndex
);
6755 // An ssth array of all zeroes indicates the peer has no services registered.
6756 mDNSlocal mDNSBool
allZeroSSTH(struct opaque_presence_indication
*op
)
6759 int *intp
= (int *) op
->ssth
;
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
6765 if (MAX_SSTH_SIZE
% sizeof(int))
6767 LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE
);
6771 for (i
= 0; i
< (int)(MAX_SSTH_SIZE
/ sizeof(int)); i
++, intp
++)
6779 // Mark records from this peer for deletion from the cache.
6780 mDNSlocal
void removeCachedPeerRecords(mDNSu32 ifindex
, mDNSAddr
*ap
, bool purgeNow
)
6782 mDNS
*const m
= &mDNSStorage
;
6786 NetworkInterfaceInfoOSX
*infoOSX
;
6787 mDNSInterfaceID InterfaceID
;
6789 // Using mDNSPlatformInterfaceIDfromInterfaceIndex() would lead to recursive
6790 // locking issues, see: <rdar://problem/21332983>
6791 infoOSX
= IfindexToInterfaceInfoOSX((mDNSInterfaceID
)(uintptr_t)ifindex
);
6794 LogInfo("removeCachedPeerRecords: interface %d not yet active", ifindex
);
6797 InterfaceID
= infoOSX
->ifinfo
.InterfaceID
;
6799 FORALL_CACHERECORDS(slot
, cg
, cr
)
6801 if ((InterfaceID
== cr
->resrec
.InterfaceID
) && mDNSSameAddress(ap
, & cr
->sourceAddress
))
6803 LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
6804 DNSTypeName(cr
->resrec
.rrtype
), cr
->resrec
.name
->c
);
6807 mDNS_PurgeCacheResourceRecord(m
, cr
);
6809 mDNS_Reconfirm_internal(m
, cr
, 0); // use default minimum reconfirm time
6814 // Handle KEV_DL_NODE_PRESENCE event.
6815 mDNSlocal
void nodePresence(struct kev_dl_node_presence
* p
)
6817 struct opaque_presence_indication
*op
= (struct opaque_presence_indication
*) p
->node_service_info
;
6819 LogInfo("nodePresence: IPv6 address: %.16a, SUI %d", p
->sin6_node_address
.sin6_addr
.s6_addr
, op
->SUI
);
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
))
6827 peerAddr
.type
= mDNSAddrType_IPv6
;
6828 peerAddr
.ip
.v6
= *(mDNSv6Addr
*)&p
->sin6_node_address
.sin6_addr
;
6830 LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer");
6831 removeCachedPeerRecords(p
->sdl_node_address
.sdl_index
, & peerAddr
, false);
6835 // Handle KEV_DL_NODE_ABSENCE event.
6836 mDNSlocal
void nodeAbsence(struct kev_dl_node_absence
* p
)
6840 peerAddr
.type
= mDNSAddrType_IPv6
;
6841 peerAddr
.ip
.v6
= *(mDNSv6Addr
*)&p
->sin6_node_address
.sin6_addr
;
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);
6847 mDNSlocal
void SysEventCallBack(int s1
, short __unused filter
, void *context
, __unused mDNSBool encounteredEOF
)
6849 mDNS
*const m
= (mDNS
*const)context
;
6853 struct { struct kern_event_msg k
; char extra
[256]; } msg
;
6854 ssize_t bytes
= recv(s1
, &msg
, sizeof(msg
), 0);
6856 LogMsg("SysEventCallBack: recv error %ld errno %d (%s)", (long)bytes
, errno
, strerror(errno
));
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" :
6890 if (msg
.k
.event_code
== KEV_DL_NODE_PRESENCE
)
6891 nodePresence((struct kev_dl_node_presence
*) &msg
.k
.event_data
);
6893 if (msg
.k
.event_code
== KEV_DL_NODE_ABSENCE
)
6894 nodeAbsence((struct kev_dl_node_absence
*) &msg
.k
.event_data
);
6896 if (msg
.k
.event_code
== KEV_DL_MASTER_ELECTED
)
6897 newMasterElected((struct net_event_data
*) &msg
.k
.event_data
);
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.
6905 if (msg
.k
.event_code
== KEV_DL_WAKEFLAGS_CHANGED
|| msg
.k
.event_code
== KEV_DL_LINK_ON
)
6906 SetNetworkChanged(mDNSPlatformOneSecond
* 2);
6909 // For p2p interfaces, need to open the advertised service port in the firewall.
6910 if (msg
.k
.event_code
== KEV_DL_IF_ATTACHED
)
6912 struct net_event_data
* p
;
6913 p
= (struct net_event_data
*) &msg
.k
.event_data
;
6915 if (strncmp(p
->if_name
, "p2p", 3) == 0)
6917 char ifname
[IFNAMSIZ
];
6918 snprintf(ifname
, IFNAMSIZ
, "%s%d", p
->if_name
, p
->if_unit
);
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
);
6922 mDNSSetPacketFilterRules(ifname
, NULL
);
6926 // For p2p interfaces, need to clear the firewall rules on interface detach
6927 if (msg
.k
.event_code
== KEV_DL_IF_DETACHED
)
6929 struct net_event_data
* p
;
6930 p
= (struct net_event_data
*) &msg
.k
.event_data
;
6932 if (strncmp(p
->if_name
, "p2p", 3) == 0)
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
);
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
);
6940 mDNSPacketFilterControl(PF_CLEAR_RULES
, ifname
, 0, portArray
, protocolArray
);
6949 mDNSlocal mStatus
WatchForSysEvents(mDNS
*const m
)
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
); }
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
);
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
);
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
);
6970 return(mStatus_NoError
);
6973 #ifndef NO_SECURITYFRAMEWORK
6974 mDNSlocal OSStatus
KeychainChanged(SecKeychainEvent keychainEvent
, SecKeychainCallbackInfo
*info
, void *context
)
6976 LogInfo("*** Keychain Changed ***");
6977 mDNS
*const m
= (mDNS
*const)context
;
6979 OSStatus err
= SecKeychainCopyDefault(&skc
);
6982 if (info
->keychain
== skc
)
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
);
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
);
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
);
7001 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
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
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.
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.
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
);
7024 KQueueUnlock("KeychainChanged");
7034 mDNSlocal
void PowerOn(mDNS
*const m
)
7036 mDNSCoreMachineSleep(m
, false); // Will set m->SleepState = SleepState_Awake;
7038 if (m
->p
->WakeAtUTC
)
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)
7044 LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m
->p
->WakeAtUTC
- utc
);
7046 else if (utc
- m
->p
->WakeAtUTC
> 30)
7048 LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc
- m
->p
->WakeAtUTC
);
7050 else if (IsAppleTV())
7052 LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc
- m
->p
->WakeAtUTC
);
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
;
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");
7068 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
7070 mDNS
*const m
= (mDNS
*const)refcon
;
7072 (void)service
; // Parameter not used
7073 debugf("PowerChanged %X %lX", messageType
, messageArgument
);
7075 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
7076 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
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();
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);
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
7095 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m
->SleepState
);
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
7102 SetNetworkChanged(mDNSPlatformOneSecond
* 2);
7106 case kIOMessageSystemWillRestart
: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
7107 case kIOMessageSystemWillPowerOn
: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
7109 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
7110 if (m
->SleepState
!= SleepState_Sleeping
)
7112 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m
->SleepState
);
7113 m
->SleepState
= SleepState_Sleeping
;
7114 mDNSMacOSXNetworkChanged();
7118 default: LogSPS("PowerChanged unknown message %X", messageType
); break;
7121 if (messageType
== kIOMessageSystemWillSleep
)
7122 m
->p
->SleepCookie
= (long)messageArgument
;
7123 else if (messageType
== kIOMessageCanSystemSleep
)
7124 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
7126 KQueueUnlock("PowerChanged Sleep/Wake");
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
)
7134 mDNS
*const m
= (mDNS
*const)refcon
;
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" : "");
7144 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
7145 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
7147 if (eventDescriptor
& kIOPMSystemPowerStateCapabilityCPU
)
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.
7155 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m
->SleepLimit
, m
->SleepState
);
7156 IOPMConnectionAcknowledgeEvent(connection
, (IOPMConnectionMessageToken
)m
->p
->SleepCookie
);
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
)
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.
7167 SetNetworkChanged(mDNSPlatformOneSecond
* 2);
7170 IOPMConnectionAcknowledgeEvent(connection
, token
);
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
);
7178 //mDNSMacOSXNetworkChanged(m);
7179 mDNSCoreMachineSleep(m
, true);
7180 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
7181 m
->p
->SleepCookie
= token
;
7184 KQueueUnlock("SnowLeopardPowerChanged Sleep/Wake");
7188 #if COMPILER_LIKES_PRAGMA_MARK
7190 #pragma mark - /etc/hosts support
7193 // Implementation Notes
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
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
7205 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
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
7211 #define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
7213 mDNSexport
void FreeEtcHosts(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
7218 if (result
== mStatus_MemFree
)
7220 LogInfo("FreeEtcHosts: %s", ARDisplayString(m
, rr
));
7221 freeL("etchosts", rr
);
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
)
7231 mDNSInterfaceID InterfaceID
= mDNSInterface_LocalOnly
;
7236 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
7241 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
7245 if (sa
&& sa
->sa_family
!= AF_INET
&& sa
->sa_family
!= AF_INET6
)
7247 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa
->sa_family
);
7254 mDNSu32 ifindex
= if_nametoindex(ifname
);
7257 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain
->c
, ifname
);
7260 InterfaceID
= (mDNSInterfaceID
)(uintptr_t)ifindex
;
7264 rrtype
= (sa
->sa_family
== AF_INET
? kDNSType_A
: kDNSType_AAAA
);
7266 rrtype
= kDNSType_CNAME
;
7268 // Check for duplicates. See whether we parsed an entry before like this ?
7269 namehash
= DomainNameHashValue(domain
);
7270 ag
= AuthGroupForName(auth
, namehash
, domain
);
7276 if (rr
->resrec
.rrtype
== rrtype
)
7278 if (rrtype
== kDNSType_A
)
7281 ip
.NotAnInteger
= ((struct sockaddr_in
*)sa
)->sin_addr
.s_addr
;
7282 if (mDNSSameIPv4Address(rr
->resrec
.rdata
->u
.ipv4
, ip
) && InterfaceID
== rr
->resrec
.InterfaceID
)
7284 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address and InterfaceID for name %##s ID %d", domain
->c
, IIDPrintable(InterfaceID
));
7288 else if (rrtype
== kDNSType_AAAA
)
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
)
7297 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address and InterfaceID for name %##s ID %d", domain
->c
, IIDPrintable(InterfaceID
));
7301 else if (rrtype
== kDNSType_CNAME
)
7303 if (SameDomainName(&rr
->resrec
.rdata
->u
.name
, cname
))
7305 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname
->c
, domain
->c
);
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
);
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
;
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];
7333 rr
->resrec
.rdlength
= DomainNameLength(cname
);
7334 rr
->resrec
.rdata
->u
.name
.c
[0] = 0;
7335 AssignDomainName(&rr
->resrec
.rdata
->u
.name
, cname
);
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
);
7344 mDNSlocal
int EtcHostsParseOneName(int start
, int length
, char *buffer
, char **name
)
7349 for (i
= start
; i
< length
; i
++)
7351 if (buffer
[i
] == '#')
7353 if (buffer
[i
] != ' ' && buffer
[i
] != ',' && buffer
[i
] != '\t')
7357 // Found the start of a name, find the end and null terminate
7358 for (i
++; i
< length
; i
++)
7360 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t')
7372 mDNSlocal
void mDNSMacOSXParseEtcHostsLine(char *buffer
, int length
, AuthHash
*auth
)
7376 char *ifname
= NULL
;
7383 //Ignore leading whitespaces and tabs
7384 while (*buffer
== ' ' || *buffer
== '\t')
7390 // Find the end of the address string
7391 for (i
= 0; i
< length
; i
++)
7393 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t' || buffer
[i
] == '%')
7395 if (buffer
[i
] == '%')
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)
7409 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
7415 // Parse the interface
7416 ifname
= &buffer
[ifStart
];
7417 for (i
= ifStart
+ 1; i
< length
; i
++)
7419 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t')
7427 i
= EtcHostsParseOneName(i
+ 1, length
, buffer
, &name1
);
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
))
7433 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1
);
7434 freeaddrinfo(gairesults
);
7437 mDNSMacOSXCreateEtcHostsEntry(&name1d
, gairesults
->ai_addr
, mDNSNULL
, ifname
, auth
);
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.
7446 if (!MakeDomainNameFromDNSNameString(&first
, name1
))
7448 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1
);
7449 freeaddrinfo(gairesults
);
7452 mDNSMacOSXCreateEtcHostsEntry(&first
, gairesults
->ai_addr
, mDNSNULL
, ifname
, auth
);
7454 // /etc/hosts alias discussion:
7456 // If the /etc/hosts has an entry like this
7458 // ip_address cname [aliases...]
7459 // 1.2.3.4 sun star bright
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")
7464 // To achieve this, we need to add the entry like this:
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.
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
7480 i
= EtcHostsParseOneName(i
+ 1, length
, buffer
, &name2
);
7484 if ((aliasIndex
) && (*buffer
== *name2
))
7485 break; // break out of the loop if we wrap around
7487 if (!MakeDomainNameFromDNSNameString(&name2d
, name2
))
7489 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2
);
7490 freeaddrinfo(gairesults
);
7493 // Ignore if it points to itself
7494 if (!SameDomainName(&first
, &name2d
))
7496 if (!mDNSMacOSXCreateEtcHostsEntry(&name2d
, mDNSNULL
, &first
, ifname
, auth
))
7498 freeaddrinfo(gairesults
);
7504 LogInfo("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names first %##s, name2 %##s", first
.c
, name2d
.c
);
7508 else if (!aliasIndex
)
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
);
7517 freeaddrinfo(gairesults
);
7520 mDNSlocal
void mDNSMacOSXParseEtcHosts(int fd
, AuthHash
*auth
)
7523 char buf
[ETCHOSTS_BUFSIZE
];
7527 if (fd
== -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
7529 fp
= fopen("/etc/hosts", "r");
7530 if (!fp
) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
7534 good
= (fgets(buf
, ETCHOSTS_BUFSIZE
, fp
) != NULL
);
7537 // skip comment and empty lines
7538 if (buf
[0] == '#' || buf
[0] == '\r' || buf
[0] == '\n')
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')
7546 buf
[len
- 1] = '\0';
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.
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')
7559 buf
[len
- 1] = '\0';
7563 if (!len
) //Sanity Check: len should never be zero
7565 LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
7568 mDNSMacOSXParseEtcHostsLine(buf
, (int)len
, auth
);
7573 mDNSlocal
void mDNSMacOSXUpdateEtcHosts(mDNS
*const m
);
7575 mDNSlocal
int mDNSMacOSXGetEtcHostsFD(void)
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;
7584 // First time through? just schedule ourselves on the main queue and we'll do the work later
7587 etcq
= dispatch_get_main_queue();
7590 // Do this work on the queue, not here - solves potential synchronization issues
7591 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
7596 if (hostssrc
) return (int)dispatch_source_get_handle(hostssrc
);
7599 int fd
= open("/etc/hosts", O_RDONLY
);
7601 #ifdef __DISPATCH_GROUP__
7602 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
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
; }
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
);
7617 dispatch_source_set_event_handler(etcsrc
,
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)
7623 dispatch_source_cancel(etcsrc
);
7624 dispatch_release(etcsrc
);
7626 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
7629 if ((flags
& DISPATCH_VNODE_WRITE
) != 0 && hostssrc
== NULL
)
7631 mDNSMacOSXUpdateEtcHosts(m
);
7634 dispatch_source_set_cancel_handler(etcsrc
, ^{close(fd
);});
7635 dispatch_resume(etcsrc
);
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; }
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
)
7651 dispatch_source_set_event_handler(hostssrc
,
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)
7657 dispatch_source_cancel(hostssrc
);
7658 dispatch_release(hostssrc
);
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
7668 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
7671 if ((flags
& DISPATCH_VNODE_WRITE
) != 0)
7673 mDNSMacOSXUpdateEtcHosts(m
);
7676 dispatch_source_set_cancel_handler(hostssrc
, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd
); close(fd
);});
7677 dispatch_resume(hostssrc
);
7679 // Cleanup /etc source, no need to watch it if we already have /etc/hosts
7682 dispatch_source_cancel(etcsrc
);
7683 dispatch_release(etcsrc
);
7687 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
7688 return hostssrc
? (int)dispatch_source_get_handle(hostssrc
) : -1;
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
)
7703 FORALL_CACHERECORDS(slot
, cg
, cr
)
7706 if (cr
->resrec
.InterfaceID
) continue;
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
))
7713 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m
, cr
));
7714 mDNS_PurgeCacheResourceRecord(m
, cr
);
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
)
7722 mDNS
*const m
= &mDNSStorage
;
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
)
7730 for (rr
= ag
->members
; rr
; rr
= rrnext
)
7735 mDNSBool found
= mDNSfalse
;
7736 ag1
= AuthGroupForRecord(&m
->rrauth
, &rr
->resrec
);
7737 if (ag1
&& ag1
->members
)
7739 if (!primary
) primary
= ag1
->members
;
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
)
7751 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m
, rr1
));
7762 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m
, rr
));
7765 RemoveAuthRecord(m
, newhosts
, rr
);
7766 // if there is no primary, point to self
7767 rr
->RRSet
= (primary
? primary
: rr
);
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
));
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
)
7782 mDNS
*const m
= &mDNSStorage
;
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
)
7790 mDNSBool found
= mDNSfalse
;
7794 if (rr
->RecordCallback
!= FreeEtcHosts
) continue;
7795 ag1
= AuthGroupForRecord(newhosts
, &rr
->resrec
);
7801 if (IdenticalResourceRecord(&rr1
->resrec
, &rr
->resrec
))
7803 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m
, rr
));
7810 // there is no corresponding record in newhosts for the same name. This means
7811 // we should delete this from the core.
7816 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m
, rr
));
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
)
7823 AuthRecord
*new_primary
= rr
->next
;
7824 AuthRecord
*r
= new_primary
;
7829 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m
, r
));
7830 r
->RRSet
= new_primary
;
7832 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m
, r
), r
->resrec
.name
);
7836 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m
, rr
));
7837 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
7843 mDNSlocal
void UpdateEtcHosts(mDNS
*const m
, void *context
)
7845 AuthHash
*newhosts
= (AuthHash
*)context
;
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
);
7855 mDNSlocal
void FreeNewHosts(AuthHash
*newhosts
)
7858 AuthGroup
*ag
, *agnext
;
7859 AuthRecord
*rr
, *rrnext
;
7861 for (slot
= 0; slot
< AUTH_HASH_SLOTS
; slot
++)
7862 for (ag
= newhosts
->rrauth_hash
[slot
]; ag
; ag
= agnext
)
7865 for (rr
= ag
->members
; rr
; rr
= rrnext
)
7868 freeL("etchosts", rr
);
7870 freeL("AuthGroups", ag
);
7874 mDNSlocal
void mDNSMacOSXUpdateEtcHosts(mDNS
*const m
)
7878 // As we will be modifying the core, we can only have one thread running at
7879 // any point in time.
7882 mDNSPlatformMemZero(&newhosts
, sizeof(AuthHash
));
7884 // Get the file desecriptor (will trigger us to start watching for changes)
7885 int fd
= mDNSMacOSXGetEtcHostsFD();
7888 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd
);
7889 mDNSMacOSXParseEtcHosts(fd
, &newhosts
);
7891 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
7893 // Optimization: Detect whether /etc/hosts changed or not.
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.
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
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.
7908 // Add the new entries to the core if not already present in the core
7909 if (!EtcHostsAddNewEntries(&newhosts
, mDNStrue
))
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
))
7915 LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
7916 FreeNewHosts(&newhosts
);
7918 KQueueUnlock("/etc/hosts changed");
7923 // This will flush the cache, stop and start the query so that the queries
7924 // can look at the /etc/hosts again
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.
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
7940 mDNSCoreRestartAddressQueries(m
, mDNSfalse
, FlushAllCacheRecords
, UpdateEtcHosts
, &newhosts
);
7941 FreeNewHosts(&newhosts
);
7943 KQueueUnlock("/etc/hosts changed");
7946 #if COMPILER_LIKES_PRAGMA_MARK
7948 #pragma mark - Initialization & Teardown
7951 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
7952 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
7953 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
7954 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
7956 // Major version 13 is 10.9.x
7957 mDNSexport
void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
7959 int major
= 0, minor
= 0;
7960 char letter
= 0, prodname
[256]="<Unknown>", prodvers
[256]="<Unknown>", buildver
[256]="<Unknown>";
7961 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
7964 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
7965 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
7966 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
7968 CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
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
);
7978 LogMsg("Note: No Major Build Version number found; assuming 13");
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);
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')
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)
8001 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
8003 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
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
));
8014 if (err
) LogMsg("No unicast UDP responses");
8015 else debugf("Unicast UDP responses okay");
8019 mDNSlocal
void CreatePTRRecord(const domainname
*domain
)
8022 const domainname
*pname
= (domainname
*)"\x9" "localhost";
8024 rr
= (AuthRecord
*) callocL("localhosts", sizeof(*rr
));
8025 if (rr
== NULL
) return;
8027 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, kHostNameTTL
, kDNSRecordTypeKnownUnique
, AuthRecordLocalOnly
, mDNSNULL
, mDNSNULL
);
8028 AssignDomainName(&rr
->namestorage
, domain
);
8030 rr
->resrec
.rdlength
= DomainNameLength(pname
);
8031 rr
->resrec
.rdata
->u
.name
.c
[0] = 0;
8032 AssignDomainName(&rr
->resrec
.rdata
->u
.name
, pname
);
8034 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
8035 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
8036 mDNS_Register(&mDNSStorage
, rr
);
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
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)
8050 MakeDomainNameFromDNSNameString(&name
, "1.0.0.127.in-addr.arpa.");
8051 CreatePTRRecord(&name
);
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
);
8057 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
8058 mDNSlocal
void setSameDomainLabelPointer(void);
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)
8071 #if MDNSRESPONDER_SUPPORTS(APPLE, IGNORE_HOSTS_FILE)
8072 mDNSlocal mStatus
RegisterLocalOnlyAddressRecord(const domainname
*const name
, mDNSu16 type
, const void *rdata
, mDNSu16 rdlength
)
8077 if (rdlength
!= 4) return (mStatus_BadParamErr
);
8081 if (rdlength
!= 16) return (mStatus_BadParamErr
);
8085 return (mStatus_BadParamErr
);
8088 AuthRecord
*rr
= (AuthRecord
*) callocL("etchosts", sizeof(*rr
));
8089 if (!rr
) return (mStatus_NoMemoryErr
);
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
);
8095 const mStatus err
= mDNS_Register_internal(&mDNSStorage
, rr
);
8098 LogMsg("RegisterLocalOnlyAddressRecord: mDNS_Register error %d registering %s", err
, ARDisplayString(&mDNSStorage
, rr
));
8099 freeL("etchosts", rr
);
8104 mDNSlocal
void RegisterLocalOnlyARecord(const domainname
*const name
, const mDNSv4Addr
*const addr
)
8106 RegisterLocalOnlyAddressRecord(name
, kDNSType_A
, addr
->b
, (mDNSu16
)sizeof(mDNSv4Addr
));
8109 mDNSlocal
void RegisterLocalOnlyAAAARecord(const domainname
*const name
, const mDNSv6Addr
*const addr
)
8111 RegisterLocalOnlyAddressRecord(name
, kDNSType_AAAA
, addr
->b
, (mDNSu16
)sizeof(mDNSv6Addr
));
8113 #endif // MDNSRESPONDER_SUPPORTS(APPLE, IGNORE_HOSTS_FILE)
8115 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
8119 char HINFO_SWstring
[256] = "";
8120 mDNSMacOSXSystemBuildNumber(HINFO_SWstring
);
8122 #if APPLE_OSX_mDNSResponder
8123 setSameDomainLabelPointer();
8126 err
= mDNSHelperInit();
8130 // Store mDNSResponder Platform
8133 m
->mDNS_plat
= platform_OSX
;
8138 m
->mDNS_plat
= platform_Atv
;
8140 m
->mDNS_plat
= platform_iOS
;
8144 m
->mDNS_plat
= platform_NonApple
;
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.
8150 for (i
=0; i
<100; i
++)
8152 domainlabel testlabel
;
8154 GetUserSpecifiedLocalHostName(&testlabel
);
8155 if (testlabel
.c
[0]) break;
8159 m
->hostlabel
.c
[0] = 0;
8161 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
8162 GetRandomUUIDLocalHostname(&m
->RandomizedHostname
);
8164 int get_model
[2] = { CTL_HW
, HW_MODEL
};
8165 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
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
;
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
));
8179 if (mDNSPlatformInit_CanReceiveUnicast())
8180 m
->CanReceiveUnicastOn5353
= mDNStrue
;
8182 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
8183 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
8184 if (hlen
+ slen
< 254)
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
);
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";
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
));
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
));
8213 m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
8215 if (m
->p
->permanentsockets
.sktv6
>= 0)
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
;
8223 m
->p
->InterfaceList
= mDNSNULL
;
8224 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
8225 m
->p
->InterfaceMonitors
= NULL
;
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
;
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
); }
8256 err
= WatchForNetworkChanges(m
);
8257 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err
); return(err
); }
8259 err
= WatchForSysEvents(m
);
8260 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err
); return(err
); }
8262 mDNSs32 utc
= mDNSPlatformUTC();
8263 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
8265 UpdateInterfaceList(utc
);
8266 SetupActiveInterfaces(utc
);
8267 ReorderInterfaceList();
8269 // Explicitly ensure that our Keychain operations utilize the system domain.
8270 #ifndef NO_SECURITYFRAMEWORK
8271 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
8275 SetDomainSecrets(m
);
8279 #ifndef NO_SECURITYFRAMEWORK
8280 err
= SecKeychainAddCallback(KeychainChanged
, kSecAddEventMask
|kSecDeleteEventMask
|kSecUpdateEventMask
, m
);
8281 if (err
) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err
); return(err
); }
8284 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_IPHONE
8285 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
8288 IOReturn iopmerr
= IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU
, &c
);
8289 if (iopmerr
) LogMsg("IOPMConnectionCreate failed %d", iopmerr
);
8292 iopmerr
= IOPMConnectionSetNotification(c
, m
, SnowLeopardPowerChanged
);
8293 if (iopmerr
) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr
);
8296 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8297 IOPMConnectionSetDispatchQueue(c
, dispatch_get_main_queue());
8298 LogInfo("IOPMConnectionSetDispatchQueue is now running");
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 */
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
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); }
8314 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8315 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, dispatch_get_main_queue());
8317 CFRunLoopAddSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
8318 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
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
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
);
8347 SSLqueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
8349 if (SSLqueue
== mDNSNULL
) LogMsg("dispatch_queue_create: SSL queue NULL");
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:
8356 // 127.0.0.1 localhost
8357 // 255.255.255.255 broadcasthost
8360 if (!IsAppleInternalBuild())
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
;
8367 // Register localhost 127.0.0.1 A record.
8369 RegisterLocalOnlyARecord(localHostName
, &localHostV4
);
8371 // Register broadcasthost 255.255.255.255 A record.
8373 RegisterLocalOnlyARecord(broadcastHostName
, &onesIPv4Addr
);
8375 // Register localhost ::1 AAAA record.
8377 mDNSPlatformMemZero(&localHostV6
, sizeof(localHostV6
));
8378 localHostV6
.b
[15] = 1;
8379 RegisterLocalOnlyAAAARecord(localHostName
, &localHostV6
);
8384 mDNSMacOSXUpdateEtcHosts(m
);
8386 SetupLocalHostRecords();
8388 #if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
8389 dso_transport_init();
8392 #if MDNSRESPONDER_SUPPORTS(APPLE, ANALYTICS)
8393 dnssd_analytics_init();
8396 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
8397 if (os_feature_enabled(mDNSResponder
, bonjour_privacy
))
8403 return(mStatus_NoError
);
8406 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
8409 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
8412 // Adding interfaces will use this flag, so set it now.
8413 m
->DivertMulticastAdvertisements
= !m
->AdvertiseLocalAddresses
;
8415 #if APPLE_OSX_mDNSResponder
8416 m
->SPSBrowseCallback
= UpdateSPSStatus
;
8417 #endif // APPLE_OSX_mDNSResponder
8419 mStatus result
= mDNSPlatformInit_setup(m
);
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
)
8425 mDNSCoreInitComplete(m
, mStatus_NoError
);
8426 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
8427 initializeD2DPlugins(m
);
8433 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
8435 if (m
->p
->PowerConnection
)
8437 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8438 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, NULL
);
8440 CFRunLoopRemoveSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
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;
8452 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8453 if (!SCDynamicStoreSetDispatchQueue(m
->p
->Store
, NULL
))
8454 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
8456 CFRunLoopRemoveSource(CFRunLoopGetMain(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
8457 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
8458 CFRelease(m
->p
->StoreRLS
);
8459 m
->p
->StoreRLS
= NULL
;
8461 CFRelease(m
->p
->Store
);
8467 CFRunLoopRemoveSource(CFRunLoopGetMain(), m
->p
->PMRLS
, kCFRunLoopDefaultMode
);
8468 CFRunLoopSourceInvalidate(m
->p
->PMRLS
);
8469 CFRelease(m
->p
->PMRLS
);
8473 if (m
->p
->SysEventNotifier
>= 0) { close(m
->p
->SysEventNotifier
); m
->p
->SysEventNotifier
= -1; }
8474 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
8475 terminateD2DPlugins();
8478 mDNSs32 utc
= mDNSPlatformUTC();
8479 MarkAllInterfacesInactive(utc
);
8480 ClearInactiveInterfaces(utc
);
8481 CloseSocketSet(&m
->p
->permanentsockets
);
8483 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
8484 if (m
->p
->InterfaceMonitors
)
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
++)
8491 mdns_interface_monitor_invalidate((mdns_interface_monitor_t
) CFArrayGetValueAtIndex(monitors
, i
));
8493 CFRelease(monitors
);
8498 #if COMPILER_LIKES_PRAGMA_MARK
8500 #pragma mark - General Platform Support Layer functions
8503 mDNSexport mDNSu32
mDNSPlatformRandomNumber(void)
8505 return(arc4random());
8508 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
8509 mDNSexport mDNSu32 mDNSPlatformClockDivisor
= 0;
8511 mDNSexport mStatus
mDNSPlatformTimeInit(void)
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
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
);
8537 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
8539 if (mDNSPlatformClockDivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
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)
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”.");
8557 last_mach_absolute_time
= this_mach_absolute_time
;
8559 return((mDNSs32
)(this_mach_absolute_time
/ mDNSPlatformClockDivisor
));
8562 mDNSexport mDNSs32
mDNSPlatformUTC(void)
8564 return (mDNSs32
)time(NULL
);
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 *))
8578 return (qsort(base
, nel
, width
, compar
));
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
); }
8586 mDNSexport
void mDNSPlatformSetAllowSleep(mDNSBool allowSleep
, const char *reason
)
8588 mDNS
*const m
= &mDNSStorage
;
8589 if (allowSleep
&& m
->p
->IOPMAssertion
)
8591 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__
);
8592 IOPMAssertionRelease(m
->p
->IOPMAssertion
);
8593 m
->p
->IOPMAssertion
= 0;
8595 else if (!allowSleep
)
8597 #ifdef kIOPMAssertionTypeNoIdleSleep
8598 if (m
->p
->IOPMAssertion
)
8600 IOPMAssertionRelease(m
->p
->IOPMAssertion
);
8601 m
->p
->IOPMAssertion
= 0;
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__
);
8612 mDNSexport
void mDNSPlatformPreventSleep(mDNSu32 timeout
, const char *reason
)
8614 mDNS
*const m
= &mDNSStorage
;
8615 if (m
->p
->IOPMAssertion
)
8617 LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout
, reason
);
8620 #ifdef kIOPMAssertionTypeNoIdleSleep
8622 #if TARGET_OS_IPHONE
8624 return; // No need for maintenance wakes on non-AppleTV embedded devices.
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
);
8634 CFDictionarySetValue(assertionProperties
, kIOPMAssertionTypeKey
, kIOPMAssertPreventUserIdleSystemSleep
);
8636 CFDictionarySetValue(assertionProperties
, kIOPMAssertionTypeKey
, kIOPMAssertMaintenanceActivity
);
8638 CFDictionarySetValue(assertionProperties
, kIOPMAssertionTimeoutKey
, Timeout_num
);
8639 CFDictionarySetValue(assertionProperties
, kIOPMAssertionNameKey
, str
);
8641 IOPMAssertionCreateWithProperties(assertionProperties
, (IOPMAssertionID
*)&m
->p
->IOPMAssertion
);
8643 CFRelease(Timeout_num
);
8644 CFRelease(assertionProperties
);
8645 LogSPS("Got an idle sleep assertion for %d seconds for %s", timeout
, reason
);
8649 mDNSexport
void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID
, char *EthAddr
, char *IPAddr
, int iteration
)
8651 if (GetInterfaceSupportsWakeOnLANPacket(InterfaceID
))
8656 ifindex
= mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage
, InterfaceID
, mDNStrue
);
8659 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex
);
8662 mDNSSendWakeupPacket(ifindex
, EthAddr
, IPAddr
, iteration
);
8666 mDNSexport mDNSBool
mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID
)
8668 NetworkInterfaceInfoOSX
*info
;
8670 if (InterfaceID
== mDNSInterface_P2P
)
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
)
8678 if ( (InterfaceID
== mDNSInterface_Any
)
8679 || (InterfaceID
== mDNSInterfaceMark
)
8680 || (InterfaceID
== mDNSInterface_LocalOnly
))
8683 // Compare to cached AWDL interface ID.
8684 if (AWDLInterfaceID
&& (InterfaceID
== AWDLInterfaceID
))
8687 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
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
);
8695 return (mDNSBool
) info
->D2DInterface
;
8698 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
8699 mDNSexport mDNSBool
mDNSPlatformInterfaceIsAWDL(const mDNSInterfaceID interfaceID
)
8701 return ((AWDLInterfaceID
&& (interfaceID
== AWDLInterfaceID
)) ? mDNStrue
: mDNSfalse
);
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
)
8709 // For an explicit match to a valid interface ID, return true.
8710 if (rr
->resrec
.InterfaceID
== InterfaceID
)
8713 // Only filtering records for D2D type interfaces, return true for all other interface types.
8714 if (!mDNSPlatformInterfaceIsD2D(InterfaceID
))
8717 // If it's an AWDL interface the record must be explicitly marked to include AWDL.
8718 if (InterfaceID
== AWDLInterfaceID
)
8720 if (rr
->ARType
== AuthRecordAnyIncludeAWDL
|| rr
->ARType
== AuthRecordAnyIncludeAWDLandP2P
)
8726 // Send record if it is explicitly marked to include all other P2P type interfaces.
8727 if (rr
->ARType
== AuthRecordAnyIncludeP2P
|| rr
->ARType
== AuthRecordAnyIncludeAWDLandP2P
)
8730 // Don't send the record over this interface.
8734 // Filter questions send over P2P (D2D) type interfaces.
8735 mDNSexport mDNSBool
mDNSPlatformValidQuestionForInterface(DNSQuestion
*q
, const NetworkInterfaceInfo
*intf
)
8737 // For an explicit match to a valid interface ID, return true.
8738 if (q
->InterfaceID
== intf
->InterfaceID
)
8741 // Only filtering questions for D2D type interfaces
8742 if (!mDNSPlatformInterfaceIsD2D(intf
->InterfaceID
))
8745 // If it's an AWDL interface the question must be explicitly marked to include AWDL.
8746 if (intf
->InterfaceID
== AWDLInterfaceID
)
8748 if (q
->flags
& kDNSServiceFlagsIncludeAWDL
)
8754 // Sent question if it is explicitly marked to include all other P2P type interfaces.
8755 if (q
->flags
& kDNSServiceFlagsIncludeP2P
)
8758 // Don't send the question over this interface.
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
)
8767 if (!rr
->InterfaceID
|| (rr
->InterfaceID
== q
->InterfaceID
))
8770 if ((rr
->InterfaceID
== AWDLInterfaceID
) && !(q
->flags
& kDNSServiceFlagsIncludeAWDL
))
8776 // formating time to RFC 4034 format
8777 mDNSexport
void mDNSPlatformFormatTime(unsigned long te
, mDNSu8
*buf
, int bufsize
)
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
);
8787 mDNSexport mDNSs32
mDNSPlatformGetPID()
8792 // Schedule a function asynchronously on the main queue
8793 mDNSexport
void mDNSPlatformDispatchAsync(mDNS
*const m
, void *context
, AsyncDispatchFunc func
)
8795 // KQueueLock/Unlock is used for two purposes
8797 // 1. We can't be running along with the KQueue thread and hence acquiring the lock
8798 // serializes the access to the "core"
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(), ^{
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();
8816 // definitions for device-info record construction
8817 #define DEVINFO_MODEL "model="
8818 #define DEVINFO_MODEL_LEN sizeof_string(DEVINFO_MODEL)
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
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')
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))
8833 // Initialize device-info TXT record contents and return total length of record data.
8834 mDNSexport mDNSu32
initializeDeviceInfoTXT(mDNS
*m
, mDNSu8
*ptr
)
8836 mDNSu8
*bufferStart
= ptr
;
8837 mDNSu8 len
= m
->HIHardware
.c
[0] < MAX_MODEL_NAME_LEN
? m
->HIHardware
.c
[0] : MAX_MODEL_NAME_LEN
;
8839 *ptr
= DEVINFO_MODEL_LEN
+ len
; // total length of DEVINFO_MODEL string plus the hardware name string
8841 mDNSPlatformMemCopy(ptr
, DEVINFO_MODEL
, DEVINFO_MODEL_LEN
);
8842 ptr
+= DEVINFO_MODEL_LEN
;
8843 mDNSPlatformMemCopy(ptr
, m
->HIHardware
.c
+ 1, len
);
8846 // only include this string for OSX
8849 char ver_num
[VER_NUM_LEN
+ 1]; // version digits + null written by snprintf
8850 *ptr
= OSX_VER_LEN
+ VER_NUM_LEN
; // length byte
8852 mDNSPlatformMemCopy(ptr
, OSX_VER
, 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
);
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
)
8865 *ptr
= MODEL_COLOR_LEN
+ len
; // length byte
8868 if (color_type
== util_enclosure_color_rgb
) {
8869 mDNSPlatformMemCopy(ptr
, MODEL_RGB_COLOR
, MODEL_COLOR_LEN
);
8871 mDNSPlatformMemCopy(ptr
, MODEL_INDEX_COLOR
, MODEL_COLOR_LEN
);
8873 ptr
+= MODEL_COLOR_LEN
;
8875 mDNSPlatformMemCopy(ptr
, color
, len
);
8880 return (mDNSu32
)(ptr
- bufferStart
);
8883 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
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
;
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]
8894 #if __arm64__ || __arm__
8895 #include <arm_neon.h>
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
8919 mDNSlocal mDNSBool
vectorSameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
8921 const int len
= *a
++;
8923 if (len
> MAX_DOMAIN_LABEL
)
8925 fprintf(stderr
, "v: Malformed label (too long)\n");
8934 uint32_t len_count
= len
;
8936 uint8x16_t vA
, vB
, vARotated
, vBRotated
, vMaskA
, vMaskB
;
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__
8943 uint32x2_t vtemp32d
;
8947 while(len_count
> 15)
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.
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.
8967 vA
= vceqq_u8(vA
, vB
);
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
)
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);
8986 //0x0001fffe + 0x0001fffe + 0x0001fffe + 0x0001fffe = 0x0007fff8U when all same.
8987 if(sum
!= 0x0007fff8U
)
8996 uint8x8_t vAd
, vBd
, vARotatedd
, vBRotatedd
, vMaskAd
, vMaskBd
;
8998 uint8x8_t v32d
= vdup_n_u8(32);
8999 uint8x8_t v37d
= vdup_n_u8(37);
9000 uint8x8_t v101d
= vdup_n_u8(101);
9002 while(len_count
> 7)
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.
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.
9022 vAd
= vceq_u8(vAd
, vBd
);
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
)
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);
9040 //0x0001fffe + 0x0001fffe = 0x0003fffc when all same.
9041 if(sum
!= 0x0003fffcU
)
9050 while(len_count
> 0)
9055 ac
+= upper_to_lower_case_table
[ac
];
9056 bc
+= upper_to_lower_case_table
[bc
];
9068 // Use vectorized implementation if it is supported on this platform.
9069 mDNSlocal
void setSameDomainLabelPointer(void)
9071 if(_cpu_capabilities
& kHasNeon
)
9074 SameDomainLabelPointer
= vectorSameDomainLabel
;
9075 LogMsg("setSameDomainLabelPointer: using vector code");
9078 LogMsg("setSameDomainLabelPointer: using scalar code");
9080 #endif // __arm64__ || __arm__
9083 #include <smmintrin.h>
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
9107 mDNSlocal mDNSBool
vectorSameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
9109 const int len
= *a
++;
9111 if (len
> MAX_DOMAIN_LABEL
)
9113 fprintf(stderr
, "v: Malformed label (too long)\n");
9122 uint32_t len_count
= len
;
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
);
9132 __m128i vA
, vB
, vARotated
, vBRotated
, vMaskA
, vMaskB
;
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)
9139 vA
= _mm_loadu_si128((__m128i
*)a
);
9140 vB
= _mm_loadu_si128((__m128i
*)b
);
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.
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.
9157 vA
= _mm_cmpeq_epi8(vA
, vB
);
9159 //Return if any different.
9160 is_equal
= _mm_movemask_epi8(vA
);
9161 is_equal
= is_equal
& 0xffff;
9162 if(is_equal
!= 0xffff)
9170 while(len_count
> 0)
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
];
9180 //Return if a & b are different.
9191 // Use vectorized implementation if it is supported on this platform.
9192 mDNSlocal
void setSameDomainLabelPointer(void)
9194 if(_cpu_capabilities
& kHasSSE4_1
)
9197 SameDomainLabelPointer
= vectorSameDomainLabel
;
9198 LogMsg("setSameDomainLabelPointer: using vector code");
9201 LogMsg("setSameDomainLabelPointer: using scalar code");
9203 #endif // __x86_64__
9205 // Original SameDomainLabel() implementation.
9206 mDNSlocal mDNSBool
scalarSameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
9209 const int len
= *a
++;
9211 if (len
> MAX_DOMAIN_LABEL
)
9212 { debugf("Malformed label (too long)"); return(mDNSfalse
); }
9214 if (len
!= *b
++) return(mDNSfalse
);
9215 for (i
=0; i
<len
; i
++)
9219 if (mDNSIsUpperCase(ac
)) ac
+= 'a' - 'A';
9220 if (mDNSIsUpperCase(bc
)) bc
+= 'a' - 'A';
9221 if (ac
!= bc
) return(mDNSfalse
);
9226 mDNSexport mDNSBool
SameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
9228 return (*SameDomainLabelPointer
)(a
, b
);
9231 #endif // APPLE_OSX_mDNSResponder
9233 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
9234 mDNSexport
void GetRandomUUIDLabel(domainlabel
*label
)
9237 uuid_string_t uuidStr
;
9238 uuid_generate_random(uuid
);
9239 uuid_unparse_lower(uuid
, uuidStr
);
9240 MakeDomainLabelFromLiteralString(label
, uuidStr
);
9243 mDNSexport
void GetRandomUUIDLocalHostname(domainname
*hostname
)
9245 domainlabel uuidLabel
;
9246 GetRandomUUIDLabel(&uuidLabel
);
9248 AppendDomainLabel(hostname
, &uuidLabel
);
9249 AppendLiteralLabelString(hostname
, "local");
9253 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
9254 mDNSexport
void uDNSMetricsClear(uDNSMetrics
*const metrics
)
9256 if (metrics
->originalQName
)
9258 mDNSPlatformMemFree(metrics
->originalQName
);
9259 metrics
->originalQName
= mDNSNULL
;
9261 mDNSPlatformMemZero(metrics
, (mDNSu32
)sizeof(*metrics
));
9266 #include "../unittests/mdns_macosx_ut.c"