1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2018 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 #include "CryptoSupport.h"
38 #include <stdarg.h> // For va_list support
39 #include <stdlib.h> // For arc4random
41 #include <net/if_types.h> // For IFT_ETHER
42 #include <net/if_dl.h>
43 #include <net/bpf.h> // For BIOCSETIF etc.
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <sys/sysctl.h>
48 #include <sys/event.h>
50 #include <sys/ioctl.h>
51 #include <time.h> // platform support for UTC time
52 #include <arpa/inet.h> // for inet_aton
54 #include <netdb.h> // for getaddrinfo
55 #include <sys/sockio.h> // for SIOCGIFEFLAGS
57 #include <netinet/in.h> // For IP_RECVTTL
59 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
62 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
63 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
64 #include <netinet6/in6_var.h> // For IN6_IFF_TENTATIVE etc.
66 #include <netinet/tcp.h>
68 #include <DebugServices.h>
73 #include <IOKit/IOKitLib.h>
74 #include <IOKit/IOMessage.h>
76 #include <IOKit/ps/IOPowerSources.h>
77 #include <IOKit/ps/IOPowerSourcesPrivate.h>
78 #include <IOKit/ps/IOPSKeys.h>
80 #include <mach/mach_error.h>
81 #include <mach/mach_port.h>
82 #include <mach/mach_time.h>
84 #include "P2PPacketFilter.h"
86 #include <SystemConfiguration/SCPrivate.h>
89 #include <MobileWiFi/WiFiManagerClient.h> // For WiFiManagerClientRef etc, declarations.
91 #include <os/variant_private.h> // For os_variant_has_internal_diagnostics().
92 #endif // TARGET_OS_IPHONE
94 // Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
95 #include <Kernel/IOKit/apple80211/apple80211_var.h>
96 #include <network_information.h> // for nwi_state
98 #if MDNSRESPONDER_BTMM_SUPPORT
102 #if APPLE_OSX_mDNSResponder
103 #include <ne_session.h> // for ne_session_set_socket_attributes()
106 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
107 #include <IOKit/platform/IOPlatformSupportPrivate.h>
108 #endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
111 #include "unittest.h"
114 #define kInterfaceSpecificOption "interface="
116 #define mDNS_IOREG_KEY "mDNS_KEY"
117 #define mDNS_IOREG_VALUE "2009-07-30"
118 #define mDNS_IOREG_KA_KEY "mDNS_Keepalive"
119 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
121 #define DARK_WAKE_TIME 16 // Time we hold an idle sleep assertion for maintenance after a wake notification
123 // cache the InterfaceID of the AWDL interface
124 mDNSInterfaceID AWDLInterfaceID
;
126 // ***************************************************************************
129 #if COMPILER_LIKES_PRAGMA_MARK
130 #pragma mark - Globals
133 // By default we don't offer sleep proxy service
134 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
135 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
136 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
137 mDNSexport
int OfferSleepProxyService
= 0;
138 mDNSexport
int DisableSleepProxyClient
= 0;
139 mDNSexport
int UseInternalSleepProxy
= 1; // Set to non-zero to use internal (in-NIC) Sleep Proxy
141 mDNSexport
int OSXVers
, iOSVers
;
142 mDNSexport
int KQueueFD
;
144 #ifndef NO_SECURITYFRAMEWORK
145 static CFArrayRef ServerCerts
;
146 OSStatus
SSLSetAllowAnonymousCiphers(SSLContextRef context
, Boolean enable
);
147 #endif /* NO_SECURITYFRAMEWORK */
149 static CFStringRef NetworkChangedKey_IPv4
;
150 static CFStringRef NetworkChangedKey_IPv6
;
151 static CFStringRef NetworkChangedKey_Hostnames
;
152 static CFStringRef NetworkChangedKey_Computername
;
153 static CFStringRef NetworkChangedKey_DNS
;
154 static CFStringRef NetworkChangedKey_StateInterfacePrefix
;
155 static CFStringRef NetworkChangedKey_DynamicDNS
= CFSTR("Setup:/Network/DynamicDNS");
156 static CFStringRef NetworkChangedKey_PowerSettings
= CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
157 #if MDNSRESPONDER_BTMM_SUPPORT
158 static CFStringRef NetworkChangedKey_BackToMyMac
= CFSTR("Setup:/Network/BackToMyMac");
159 static CFStringRef NetworkChangedKey_BTMMConnectivity
= CFSTR("State:/Network/Connectivity");
162 static char HINFO_HWstring_buffer
[32];
163 static char *HINFO_HWstring
= "Device";
164 static int HINFO_HWstring_prefixlen
= 6;
166 mDNSexport
int WatchDogReportingThreshold
= 250;
168 dispatch_queue_t SSLqueue
;
170 #if TARGET_OS_EMBEDDED
171 #define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
174 #if APPLE_OSX_mDNSResponder
175 static mDNSu8 SPMetricPortability
= 99;
176 static mDNSu8 SPMetricMarginalPower
= 99;
177 static mDNSu8 SPMetricTotalPower
= 99;
178 static mDNSu8 SPMetricFeatures
= 1; /* The current version supports TCP Keep Alive Feature */
179 mDNSexport domainname ActiveDirectoryPrimaryDomain
;
180 mDNSexport
int ActiveDirectoryPrimaryDomainLabelCount
;
181 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer
;
182 #endif // APPLE_OSX_mDNSResponder
184 // Don't send triggers too often. We arbitrarily limit it to three minutes.
185 #define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
187 // Used by AutoTunnel
188 const char btmmprefix
[] = "btmmdns:";
189 const char dnsprefix
[] = "dns:";
191 // String Array used to write list of private domains to Dynamic Store
192 static CFArrayRef privateDnsArray
= NULL
;
194 // ***************************************************************************
197 #if COMPILER_LIKES_PRAGMA_MARK
199 #pragma mark - Utility Functions
202 // We only attempt to send and receive multicast packets on interfaces that are
203 // (a) flagged as multicast-capable
204 // (b) *not* flagged as point-to-point (e.g. modem)
205 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
206 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
207 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
209 #if BONJOUR_ON_DEMAND
210 #define MulticastInterface(i) ((i)->m->BonjourEnabled && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
212 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
214 #define SPSInterface(i) ((i)->ifinfo.McastTxRx && !((i)->ifa_flags & IFF_LOOPBACK) && !(i)->D2DInterface)
216 mDNSexport
void NotifyOfElusiveBug(const char *title
, const char *msg
) // Both strings are UTF-8 text
218 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
221 // Determine if we're at Apple (17.*.*.*)
222 NetworkInterfaceInfoOSX
*i
;
223 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
224 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& i
->ifinfo
.ip
.ip
.v4
.b
[0] == 17)
227 return; // If not at Apple, don't show the alert
231 LogMsg("NotifyOfElusiveBug: %s", title
);
232 LogMsg("NotifyOfElusiveBug: %s", msg
);
234 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
235 // To avoid this, we don't try to display alerts in the first three minutes after boot.
236 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180))
238 LogMsg("Suppressing notification early in boot: %d", mDNSPlatformRawTime());
242 #ifndef NO_CFUSERNOTIFICATION
243 static int notifyCount
= 0; // To guard against excessive display of warning notifications
247 mDNSNotify(title
, msg
);
249 #endif /* NO_CFUSERNOTIFICATION */
253 // Write a syslog message and display an alert, then if ForceAlerts is set, generate a stack trace
254 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
255 mDNSexport
void LogMemCorruption(const char *format
, ...)
259 va_start(ptr
,format
);
260 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
262 LogMsg("!!!! %s !!!!", buffer
);
263 NotifyOfElusiveBug("Memory Corruption", buffer
);
265 *(volatile long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
270 // Like LogMemCorruption above, but only display the alert if ForceAlerts is set and we're going to generate a stack trace
271 #if APPLE_OSX_mDNSResponder
272 mDNSexport
void LogFatalError(const char *format
, ...)
276 va_start(ptr
,format
);
277 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
279 LogMsg("!!!! %s !!!!", buffer
);
281 NotifyOfElusiveBug("Fatal Error. See /Library/Logs/DiagnosticReports", buffer
);
282 *(volatile long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
287 // Returns true if it is an AppleTV based hardware running iOS, false otherwise
288 mDNSlocal mDNSBool
IsAppleTV(void)
290 #if TARGET_OS_EMBEDDED
291 static mDNSBool sInitialized
= mDNSfalse
;
292 static mDNSBool sIsAppleTV
= mDNSfalse
;
293 CFStringRef deviceClass
= NULL
;
297 deviceClass
= (CFStringRef
) MGCopyAnswer(kMGQDeviceClass
, NULL
);
300 if(CFEqual(deviceClass
, kMGDeviceClassAppleTV
))
301 sIsAppleTV
= mDNStrue
;
302 CFRelease(deviceClass
);
304 sInitialized
= mDNStrue
;
309 #endif // TARGET_OS_EMBEDDED
312 mDNSlocal
struct ifaddrs
*myGetIfAddrs(int refresh
)
314 static struct ifaddrs
*ifa
= NULL
;
327 mDNSlocal
void DynamicStoreWrite(int key
, const char* subkey
, uintptr_t value
, signed long valueCnt
)
329 CFStringRef sckey
= NULL
;
330 Boolean release_sckey
= FALSE
;
331 CFDataRef bytes
= NULL
;
332 CFPropertyListRef plist
= NULL
;
334 switch ((enum mDNSDynamicStoreSetConfigKey
)key
)
336 case kmDNSMulticastConfig
:
337 sckey
= CFSTR("State:/Network/" kDNSServiceCompMulticastDNS
);
339 case kmDNSDynamicConfig
:
340 sckey
= CFSTR("State:/Network/DynamicDNS");
342 case kmDNSPrivateConfig
:
343 sckey
= CFSTR("State:/Network/" kDNSServiceCompPrivateDNS
);
345 case kmDNSBackToMyMacConfig
:
346 sckey
= CFSTR("State:/Network/BackToMyMac");
348 case kmDNSSleepProxyServersState
:
350 CFMutableStringRef tmp
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
351 CFStringAppend(tmp
, CFSTR("State:/Network/Interface/"));
352 CFStringAppendCString(tmp
, subkey
, kCFStringEncodingUTF8
);
353 CFStringAppend(tmp
, CFSTR("/SleepProxyServers"));
354 sckey
= CFStringCreateCopy(kCFAllocatorDefault
, tmp
);
355 release_sckey
= TRUE
;
359 case kmDNSDebugState
:
360 sckey
= CFSTR("State:/Network/mDNSResponder/DebugState");
363 LogMsg("unrecognized key %d", key
);
366 if (NULL
== (bytes
= CFDataCreateWithBytesNoCopy(NULL
, (void *)value
,
367 valueCnt
, kCFAllocatorNull
)))
369 LogMsg("CFDataCreateWithBytesNoCopy of value failed");
372 if (NULL
== (plist
= CFPropertyListCreateWithData(NULL
, bytes
, kCFPropertyListImmutable
, NULL
, NULL
)))
374 LogMsg("CFPropertyListCreateWithData of bytes failed");
379 SCDynamicStoreSetValue(NULL
, sckey
, plist
);
386 if (release_sckey
&& sckey
)
390 mDNSexport
void mDNSDynamicStoreSetConfig(int key
, const char *subkey
, CFPropertyListRef value
)
392 CFPropertyListRef valueCopy
;
393 char *subkeyCopy
= NULL
;
397 // We need to copy the key and value before we dispatch off the block below as the
398 // caller will free the memory once we return from this function.
399 valueCopy
= CFPropertyListCreateDeepCopy(NULL
, value
, kCFPropertyListImmutable
);
402 LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
407 int len
= strlen(subkey
);
408 subkeyCopy
= mDNSPlatformMemAllocate(len
+ 1);
411 LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
412 CFRelease(valueCopy
);
415 mDNSPlatformMemCopy(subkeyCopy
, subkey
, len
);
419 dispatch_async(dispatch_get_main_queue(), ^{
420 CFWriteStreamRef stream
= NULL
;
421 CFDataRef bytes
= NULL
;
425 if (NULL
== (stream
= CFWriteStreamCreateWithAllocatedBuffers(NULL
, NULL
)))
427 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
430 CFWriteStreamOpen(stream
);
431 ret
= CFPropertyListWrite(valueCopy
, stream
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
434 LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
437 if (NULL
== (bytes
= CFWriteStreamCopyProperty(stream
, kCFStreamPropertyDataWritten
)))
439 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
442 CFWriteStreamClose(stream
);
445 DynamicStoreWrite(key
, subkeyCopy
? subkeyCopy
: "", (uintptr_t)CFDataGetBytePtr(bytes
), CFDataGetLength(bytes
));
448 CFRelease(valueCopy
);
451 CFWriteStreamClose(stream
);
457 mDNSPlatformMemFree(subkeyCopy
);
459 KQueueUnlock("mDNSDynamicStoreSetConfig");
463 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
464 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(const char *ifname
, int type
)
466 NetworkInterfaceInfoOSX
*i
;
467 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
468 if (i
->Exists
&& !strcmp(i
->ifinfo
.ifname
, ifname
) &&
469 ((type
== AF_UNSPEC
) ||
470 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
471 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
))) return(i
);
475 mDNSlocal
int myIfIndexToName(u_short ifindex
, char *name
)
478 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
479 if (ifa
->ifa_addr
&& ifa
->ifa_addr
->sa_family
== AF_LINK
)
480 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== ifindex
)
481 { strlcpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
485 mDNSexport NetworkInterfaceInfoOSX
*IfindexToInterfaceInfoOSX(mDNSInterfaceID ifindex
)
487 mDNS
*const m
= &mDNSStorage
;
488 mDNSu32 scope_id
= (mDNSu32
)(uintptr_t)ifindex
;
489 NetworkInterfaceInfoOSX
*i
;
491 // Don't get tricked by inactive interfaces
492 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
493 if (i
->Registered
&& i
->scope_id
== scope_id
) return(i
);
498 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS
*const m
, mDNSu32 ifindex
)
501 if (ifindex
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
502 if (ifindex
== kDNSServiceInterfaceIndexP2P
) return(mDNSInterface_P2P
);
503 if (ifindex
== kDNSServiceInterfaceIndexBLE
) return(mDNSInterface_BLE
);
504 if (ifindex
== kDNSServiceInterfaceIndexAny
) return(mDNSNULL
);
506 NetworkInterfaceInfoOSX
* ifi
= IfindexToInterfaceInfoOSX((mDNSInterfaceID
)(uintptr_t)ifindex
);
509 // Not found. Make sure our interface list is up to date, then try again.
510 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex
);
511 mDNSMacOSXNetworkChanged();
512 ifi
= IfindexToInterfaceInfoOSX((mDNSInterfaceID
)(uintptr_t)ifindex
);
515 if (!ifi
) return(mDNSNULL
);
517 return(ifi
->ifinfo
.InterfaceID
);
521 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS
*const m
, mDNSInterfaceID id
, mDNSBool suppressNetworkChange
)
523 NetworkInterfaceInfoOSX
*i
;
524 if (id
== mDNSInterface_Any
) return(0);
525 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
526 if (id
== mDNSInterface_Unicast
) return(0);
527 if (id
== mDNSInterface_P2P
) return(kDNSServiceInterfaceIndexP2P
);
528 if (id
== mDNSInterface_BLE
) return(kDNSServiceInterfaceIndexBLE
);
530 mDNSu32 scope_id
= (mDNSu32
)(uintptr_t)id
;
532 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
533 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
534 if (i
->scope_id
== scope_id
) return(i
->scope_id
);
536 // If we are supposed to suppress network change, return "id" back
537 if (suppressNetworkChange
) return scope_id
;
539 // Not found. Make sure our interface list is up to date, then try again.
540 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id
);
541 mDNSMacOSXNetworkChanged();
542 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
543 if (i
->scope_id
== scope_id
) return(i
->scope_id
);
548 #if COMPILER_LIKES_PRAGMA_MARK
550 #pragma mark - UDP & TCP send & receive
553 mDNSlocal mDNSBool
AddrRequiresPPPConnection(const struct sockaddr
*addr
)
555 mDNSBool result
= mDNSfalse
;
556 SCNetworkConnectionFlags flags
;
557 CFDataRef remote_addr
;
558 CFMutableDictionaryRef options
;
559 SCNetworkReachabilityRef ReachRef
= NULL
;
561 options
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
562 remote_addr
= CFDataCreate(NULL
, (const UInt8
*)addr
, addr
->sa_len
);
563 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, remote_addr
);
564 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionServerBypass
, kCFBooleanTrue
);
565 ReachRef
= SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault
, options
);
567 CFRelease(remote_addr
);
571 LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions");
574 if (!SCNetworkReachabilityGetFlags(ReachRef
, &flags
))
576 LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags");
579 result
= flags
& kSCNetworkFlagsConnectionRequired
;
587 // Set traffic class for socket
588 mDNSlocal
void setTrafficClass(int socketfd
, mDNSBool useBackgroundTrafficClass
)
592 if (useBackgroundTrafficClass
)
593 traffic_class
= SO_TC_BK_SYS
;
595 traffic_class
= SO_TC_CTL
;
597 (void) setsockopt(socketfd
, SOL_SOCKET
, SO_TRAFFIC_CLASS
, (void *)&traffic_class
, sizeof(traffic_class
));
601 // Run the unit test main
604 mDNSlocal
int mDNSPlatformGetSocktFd(void *sockCxt
, mDNSTransport_Type transType
, mDNSAddr_Type addrType
)
606 if (transType
== mDNSTransport_UDP
)
608 UDPSocket
* sock
= (UDPSocket
*) sockCxt
;
609 return (addrType
== mDNSAddrType_IPv4
) ? sock
->ss
.sktv4
: sock
->ss
.sktv6
;
611 else if (transType
== mDNSTransport_TCP
)
613 TCPSocket
* sock
= (TCPSocket
*) sockCxt
;
614 return (addrType
== mDNSAddrType_IPv4
) ? sock
->ss
.sktv4
: sock
->ss
.sktv6
;
618 LogInfo("mDNSPlatformGetSocktFd: invalid transport %d", transType
);
619 return kInvalidSocketRef
;
623 mDNSexport
void mDNSPlatformSetSocktOpt(void *sockCxt
, mDNSTransport_Type transType
, mDNSAddr_Type addrType
, const DNSQuestion
*q
)
626 char unenc_name
[MAX_ESCAPED_DOMAIN_NAME
];
628 // verify passed-in arguments exist and that sockfd is valid
629 if (q
== mDNSNULL
|| sockCxt
== mDNSNULL
|| (sockfd
= mDNSPlatformGetSocktFd(sockCxt
, transType
, addrType
)) < 0)
634 if (setsockopt(sockfd
, SOL_SOCKET
, SO_DELEGATED
, &q
->pid
, sizeof(q
->pid
)) == -1)
635 LogMsg("mDNSPlatformSetSocktOpt: Delegate PID failed %s for PID %d", strerror(errno
), q
->pid
);
639 if (setsockopt(sockfd
, SOL_SOCKET
, SO_DELEGATED_UUID
, &q
->uuid
, sizeof(q
->uuid
)) == -1)
640 LogMsg("mDNSPlatformSetSocktOpt: Delegate UUID failed %s", strerror(errno
));
643 // set the domain on the socket
644 ConvertDomainNameToCString(&q
->qname
, unenc_name
);
645 if (!(ne_session_set_socket_attributes(sockfd
, unenc_name
, NULL
)))
646 LogInfo("mDNSPlatformSetSocktOpt: ne_session_set_socket_attributes()-> setting domain failed for %s", unenc_name
);
649 if (setsockopt(sockfd
, SOL_SOCKET
, SO_NOWAKEFROMSLEEP
, &nowake
, sizeof(nowake
)) == -1)
650 LogInfo("mDNSPlatformSetSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno
));
654 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
655 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
656 // OR send via our primary v4 unicast socket
657 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
658 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
659 mDNSInterfaceID InterfaceID
, UDPSocket
*src
, const mDNSAddr
*dst
,
660 mDNSIPPort dstPort
, mDNSBool useBackgroundTrafficClass
)
662 NetworkInterfaceInfoOSX
*info
= mDNSNULL
;
663 struct sockaddr_storage to
;
665 mStatus result
= mStatus_NoError
;
670 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
673 // We may not have registered interfaces with the "core" as we may not have
674 // seen any interface notifications yet. This typically happens during wakeup
675 // where we might try to send DNS requests (non-SuppressUnusable questions internal
676 // to mDNSResponder) before we receive network notifications.
677 LogInfo("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID
);
678 return mStatus_BadParamErr
;
682 char *ifa_name
= InterfaceID
? info
->ifinfo
.ifname
: "unicast";
684 if (dst
->type
== mDNSAddrType_IPv4
)
686 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
687 sin_to
->sin_len
= sizeof(*sin_to
);
688 sin_to
->sin_family
= AF_INET
;
689 sin_to
->sin_port
= dstPort
.NotAnInteger
;
690 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
691 s
= (src
? src
->ss
: m
->p
->permanentsockets
).sktv4
;
693 if (!mDNSAddrIsDNSMulticast(dst
))
696 const mDNSu32 ifindex
= info
? info
->scope_id
: IFSCOPE_NONE
;
697 setsockopt(s
, IPPROTO_IP
, IP_BOUND_IF
, &ifindex
, sizeof(ifindex
));
699 static int displayed
= 0;
700 if (displayed
< 1000)
703 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
709 #ifdef IP_MULTICAST_IFINDEX
710 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IFINDEX
, &info
->scope_id
, sizeof(info
->scope_id
));
711 // We get an error when we compile on a machine that supports this option and run the binary on
712 // a different machine that does not support it
715 if (errno
!= ENOPROTOOPT
) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno
);
716 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
717 if (err
< 0 && !m
->NetworkChanged
)
718 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
721 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
722 if (err
< 0 && !m
->NetworkChanged
)
723 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
727 else if (dst
->type
== mDNSAddrType_IPv6
)
729 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
730 sin6_to
->sin6_len
= sizeof(*sin6_to
);
731 sin6_to
->sin6_family
= AF_INET6
;
732 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
733 sin6_to
->sin6_flowinfo
= 0;
734 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
735 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
736 s
= (src
? src
->ss
: m
->p
->permanentsockets
).sktv6
;
737 if (info
&& mDNSAddrIsDNSMulticast(dst
)) // Specify outgoing interface
739 err
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
742 const int setsockopt_errno
= errno
;
744 if (if_indextoname(info
->scope_id
, name
) != NULL
)
745 LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err
, setsockopt_errno
, strerror(setsockopt_errno
));
747 LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info
->scope_id
);
751 if (info
) // Specify outgoing interface for non-multicast destination
753 if (!mDNSAddrIsDNSMulticast(dst
))
755 if (info
->scope_id
== 0)
756 LogInfo("IPV6_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info
, ifa_name
);
758 setsockopt(s
, IPPROTO_IPV6
, IPV6_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
766 LogFatalError("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
767 return mStatus_BadParamErr
;
771 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
772 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
774 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
775 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
777 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
778 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
779 if (s
< 0) return(mStatus_Invalid
);
781 // switch to background traffic class for this message if requested
782 if (useBackgroundTrafficClass
)
783 setTrafficClass(s
, useBackgroundTrafficClass
);
785 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
786 sendto_errno
= (err
< 0) ? errno
: 0;
788 // set traffic class back to default value
789 if (useBackgroundTrafficClass
)
790 setTrafficClass(s
, mDNSfalse
);
794 static int MessageCount
= 0;
795 LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
796 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, sendto_errno
, strerror(sendto_errno
), (mDNSu32
)(m
->timenow
));
797 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
799 if ((sendto_errno
== EHOSTUNREACH
) || (sendto_errno
== ENETUNREACH
)) return(mStatus_HostUnreachErr
);
800 if ((sendto_errno
== EHOSTDOWN
) || (sendto_errno
== ENETDOWN
)) return(mStatus_TransientErr
);
802 // Don't report EHOSTUNREACH in the first three minutes after boot
803 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
804 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
805 if (sendto_errno
== EHOSTUNREACH
&& (mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(mStatus_TransientErr
);
806 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
807 if (sendto_errno
== EADDRNOTAVAIL
&& m
->NetworkChanged
) return(mStatus_TransientErr
);
808 if (sendto_errno
== EHOSTUNREACH
|| sendto_errno
== EADDRNOTAVAIL
|| sendto_errno
== ENETDOWN
)
809 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
810 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, sendto_errno
, strerror(sendto_errno
), (mDNSu32
)(m
->timenow
));
814 if (MessageCount
< 50) // Cap and ensure NO spamming of LogMsgs
815 LogMsg("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
816 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, sendto_errno
, strerror(sendto_errno
), (mDNSu32
)(m
->timenow
), MessageCount
);
817 else // If logging is enabled, remove the cap and log aggressively
818 LogInfo("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
819 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, sendto_errno
, strerror(sendto_errno
), (mDNSu32
)(m
->timenow
), MessageCount
);
822 result
= mStatus_UnknownErr
;
828 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
829 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
831 static unsigned int numLogMessages
= 0;
832 struct iovec databuffers
= { (char *)buffer
, max
};
835 struct cmsghdr
*cmPtr
;
836 char ancillary
[1024];
838 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
840 // Set up the message
841 msg
.msg_name
= (caddr_t
)from
;
842 msg
.msg_namelen
= *fromlen
;
843 msg
.msg_iov
= &databuffers
;
845 msg
.msg_control
= (caddr_t
)&ancillary
;
846 msg
.msg_controllen
= sizeof(ancillary
);
850 n
= recvmsg(s
, &msg
, 0);
853 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
856 if (msg
.msg_flags
& MSG_CTRUNC
)
858 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
861 *fromlen
= msg
.msg_namelen
;
863 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
865 if (numLogMessages
++ < 100)
867 LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %ld msg.msg_controllen %lu < sizeof(struct cmsghdr) %lu",
868 s
, (long)n
, (unsigned long)msg
.msg_controllen
, (unsigned long)sizeof(struct cmsghdr
));
872 // Parse each option out of the ancillary data.
873 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
875 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
876 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
878 dstaddr
->type
= mDNSAddrType_IPv4
;
879 dstaddr
->ip
.v4
= *(mDNSv4Addr
*)CMSG_DATA(cmPtr
);
880 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
882 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
884 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
885 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
887 mDNSPlatformMemCopy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
888 ifname
[sdl
->sdl_nlen
] = 0;
889 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
892 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
893 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
894 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
896 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
897 dstaddr
->type
= mDNSAddrType_IPv6
;
898 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
899 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
901 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
902 *ttl
= *(int*)CMSG_DATA(cmPtr
);
909 // What is this for, and why does it use xor instead of a simple quality check? -- SC
910 mDNSlocal mDNSInterfaceID
FindMyInterface(const mDNSAddr
*addr
)
912 NetworkInterfaceInfo
*intf
;
914 if (addr
->type
== mDNSAddrType_IPv4
)
916 for (intf
= mDNSStorage
.HostInterfaces
; intf
; intf
= intf
->next
)
918 if (intf
->ip
.type
== addr
->type
&& intf
->McastTxRx
)
920 if ((intf
->ip
.ip
.v4
.NotAnInteger
^ addr
->ip
.v4
.NotAnInteger
) == 0)
922 return(intf
->InterfaceID
);
928 if (addr
->type
== mDNSAddrType_IPv6
)
930 for (intf
= mDNSStorage
.HostInterfaces
; intf
; intf
= intf
->next
)
932 if (intf
->ip
.type
== addr
->type
&& intf
->McastTxRx
)
934 if (((intf
->ip
.ip
.v6
.l
[0] ^ addr
->ip
.v6
.l
[0]) == 0) &&
935 ((intf
->ip
.ip
.v6
.l
[1] ^ addr
->ip
.v6
.l
[1]) == 0) &&
936 ((intf
->ip
.ip
.v6
.l
[2] ^ addr
->ip
.v6
.l
[2]) == 0) &&
937 (((intf
->ip
.ip
.v6
.l
[3] ^ addr
->ip
.v6
.l
[3]) == 0)))
939 return(intf
->InterfaceID
);
944 return(mDNSInterface_Any
);
947 mDNSexport
void myKQSocketCallBack(int s1
, short filter
, void *context
, mDNSBool encounteredEOF
)
949 KQSocketSet
*const ss
= (KQSocketSet
*)context
;
950 mDNS
*const m
= ss
->m
;
951 int err
= 0, count
= 0, closed
= 0;
953 if (filter
!= EVFILT_READ
)
954 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter
, EVFILT_READ
);
956 if (s1
!= ss
->sktv4
&& s1
!= ss
->sktv6
)
958 LogMsg("myKQSocketCallBack: native socket %d", s1
);
959 LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss
->sktv4
, ss
->sktv6
);
964 LogMsg("myKQSocketCallBack: socket %d is no longer readable (EOF)", s1
);
967 ss
->sktv4EOF
= mDNStrue
;
968 KQueueSet(ss
->sktv4
, EV_DELETE
, EVFILT_READ
, &ss
->kqsv4
);
970 else if (s1
== ss
->sktv6
)
972 ss
->sktv6EOF
= mDNStrue
;
973 KQueueSet(ss
->sktv6
, EV_DELETE
, EVFILT_READ
, &ss
->kqsv6
);
980 mDNSAddr senderAddr
, destAddr
= zeroAddr
;
981 mDNSIPPort senderPort
;
982 struct sockaddr_storage from
;
983 size_t fromlen
= sizeof(from
);
984 char packetifname
[IF_NAMESIZE
] = "";
986 err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
989 if ((destAddr
.type
== mDNSAddrType_IPv4
&& (destAddr
.ip
.v4
.b
[0] & 0xF0) == 0xE0) ||
990 (destAddr
.type
== mDNSAddrType_IPv6
&& (destAddr
.ip
.v6
.b
[0] == 0xFF))) m
->p
->num_mcasts
++;
993 if (from
.ss_family
== AF_INET
)
995 struct sockaddr_in
*s
= (struct sockaddr_in
*)&from
;
996 senderAddr
.type
= mDNSAddrType_IPv4
;
997 senderAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
998 senderPort
.NotAnInteger
= s
->sin_port
;
999 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1001 else if (from
.ss_family
== AF_INET6
)
1003 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
1004 senderAddr
.type
= mDNSAddrType_IPv6
;
1005 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
1006 senderPort
.NotAnInteger
= sin6
->sin6_port
;
1007 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1011 LogMsg("myKQSocketCallBack from is unknown address family %d", from
.ss_family
);
1015 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1016 mDNSInterfaceID InterfaceID
= mDNSNULL
;
1017 NetworkInterfaceInfoOSX
*intf
= m
->p
->InterfaceList
;
1020 if (intf
->Exists
&& !strcmp(intf
->ifinfo
.ifname
, packetifname
))
1025 // When going to sleep we deregister all our interfaces, but if the machine
1026 // takes a few seconds to sleep we may continue to receive multicasts
1027 // during that time, which would confuse mDNSCoreReceive, because as far
1028 // as it's concerned, we should have no active interfaces any more.
1029 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1031 InterfaceID
= intf
->ifinfo
.InterfaceID
;
1032 else if (mDNSAddrIsDNSMulticast(&destAddr
))
1037 InterfaceID
= FindMyInterface(&destAddr
);
1040 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1041 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
1043 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
1044 // loop when that happens, or we may try to read from an invalid FD. We do this by
1045 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
1046 // if it closes the socketset.
1047 ss
->closeFlag
= &closed
;
1051 m
->p
->UDPProxyCallback(&m
->p
->UDPProxy
, &m
->imsg
.m
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
,
1052 senderPort
, &destAddr
, ss
->port
, InterfaceID
, NULL
);
1056 mDNSCoreReceive(m
, &m
->imsg
.m
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, ss
->port
, InterfaceID
);
1059 // if we didn't close, we can safely dereference the socketset, and should to
1060 // reset the closeFlag, since it points to something on the stack
1061 if (!closed
) ss
->closeFlag
= mDNSNULL
;
1064 // If a client application's sockets are marked as defunct
1065 // sockets we have delegated to it with SO_DELEGATED will also go defunct.
1066 // We get an ENOTCONN error for defunct sockets and should just close the socket in that case.
1067 if (err
< 0 && errno
== ENOTCONN
)
1069 LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
1074 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
1076 // Something is busted here.
1077 // kqueue says there is a packet, but myrecvfrom says there is not.
1078 // Try calling select() to get another opinion.
1079 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1080 // All of this is racy, as data may have arrived after the call to select()
1081 static unsigned int numLogMessages
= 0;
1082 const int save_errno
= errno
;
1086 socklen_t solen
= sizeof(int);
1088 struct timeval timeout
;
1091 FD_SET(s1
, &readfds
);
1093 timeout
.tv_usec
= 0;
1094 selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
1095 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
1096 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
1097 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
1098 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
1099 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
1100 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno
);
1101 if (numLogMessages
++ < 100)
1102 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1103 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
1104 if (numLogMessages
> 5)
1105 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1106 "Congratulations, you've reproduced an elusive bug.\r"
1107 "Please send email to radar-3387020@group.apple.com.)\r"
1108 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1110 sleep(1); // After logging this error, rate limit so we don't flood syslog
1114 mDNSlocal
void doTcpSocketCallback(TCPSocket
*sock
)
1116 mDNSBool c
= !sock
->connected
;
1117 sock
->connected
= mDNStrue
;
1118 sock
->callback(sock
, sock
->context
, c
, sock
->err
);
1119 // Note: the callback may call CloseConnection here, which frees the context structure!
1122 #ifndef NO_SECURITYFRAMEWORK
1124 mDNSlocal OSStatus
tlsWriteSock(SSLConnectionRef connection
, const void *data
, size_t *dataLength
)
1126 int ret
= send(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1127 if (ret
>= 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1128 if (ret
>= 0) { *dataLength
= ret
; return(noErr
); }
1130 if (errno
== EAGAIN
) return(errSSLWouldBlock
);
1131 if (errno
== ENOENT
) return(errSSLClosedGraceful
);
1132 if (errno
== EPIPE
|| errno
== ECONNRESET
) return(errSSLClosedAbort
);
1133 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket
*)connection
)->fd
, errno
, strerror(errno
));
1134 return(errSSLClosedAbort
);
1137 mDNSlocal OSStatus
tlsReadSock(SSLConnectionRef connection
, void *data
, size_t *dataLength
)
1139 int ret
= recv(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1140 if (ret
> 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1141 if (ret
> 0) { *dataLength
= ret
; return(noErr
); }
1143 if (ret
== 0 || errno
== ENOENT
) return(errSSLClosedGraceful
);
1144 if ( errno
== EAGAIN
) return(errSSLWouldBlock
);
1145 if ( errno
== ECONNRESET
) return(errSSLClosedAbort
);
1146 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno
, strerror(errno
));
1147 return(errSSLClosedAbort
);
1150 mDNSlocal OSStatus
tlsSetupSock(TCPSocket
*sock
, SSLProtocolSide pside
, SSLConnectionType ctype
)
1152 char domname_cstr
[MAX_ESCAPED_DOMAIN_NAME
];
1154 sock
->tlsContext
= SSLCreateContext(kCFAllocatorDefault
, pside
, ctype
);
1155 if (!sock
->tlsContext
)
1157 LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
1158 return(mStatus_UnknownErr
);
1161 mStatus err
= SSLSetIOFuncs(sock
->tlsContext
, tlsReadSock
, tlsWriteSock
);
1164 LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err
);
1168 err
= SSLSetConnection(sock
->tlsContext
, (SSLConnectionRef
) sock
);
1171 LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err
);
1175 // Set the default ciphersuite configuration
1176 err
= SSLSetSessionConfig(sock
->tlsContext
, CFSTR("default"));
1179 LogMsg("ERROR: tlsSetupSock: SSLSetSessionConfig failed with error code: %d", err
);
1183 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
1184 // (error not in OSStatus space) is okay.
1185 if (!sock
->hostname
.c
[0])
1187 LogMsg("ERROR: tlsSetupSock: hostname NULL");
1192 ConvertDomainNameToCString(&sock
->hostname
, domname_cstr
);
1193 err
= SSLSetPeerDomainName(sock
->tlsContext
, domname_cstr
, strlen(domname_cstr
));
1196 LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr
, err
);
1203 if (sock
->tlsContext
)
1204 CFRelease(sock
->tlsContext
);
1208 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1209 mDNSlocal
void doSSLHandshake(TCPSocket
*sock
)
1211 mStatus err
= SSLHandshake(sock
->tlsContext
);
1213 //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
1214 //defined, KQueueLock is a noop. Hence we need to serialize here
1216 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
1217 //We need the rest of the logic also. Otherwise, we can enable the READ
1218 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
1219 //ConnFailed which means we are going to free the tcpInfo. While it
1220 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
1221 //and potentially call doTCPCallback with error which can close the fd and free the
1222 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
1225 dispatch_async(dispatch_get_main_queue(), ^{
1227 LogInfo("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
1229 if (sock
->handshake
== handshake_to_be_closed
)
1231 LogInfo("SSLHandshake completed after close");
1232 mDNSPlatformTCPCloseConnection(sock
);
1236 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1237 else LogMsg("doSSLHandshake: sock->fd is -1");
1239 if (err
== errSSLWouldBlock
)
1240 sock
->handshake
= handshake_required
;
1245 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
1246 CFRelease(sock
->tlsContext
);
1247 sock
->tlsContext
= NULL
;
1250 sock
->err
= err
? mStatus_ConnFailed
: 0;
1251 sock
->handshake
= handshake_completed
;
1253 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
1254 doTcpSocketCallback(sock
);
1258 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
1262 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1263 mDNSlocal
void *doSSLHandshake(TCPSocket
*sock
)
1265 // Warning: Touching sock without the kqueue lock!
1266 // We're protected because sock->handshake == handshake_in_progress
1267 mStatus err
= SSLHandshake(sock
->tlsContext
);
1270 debugf("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
1272 if (sock
->handshake
== handshake_to_be_closed
)
1274 LogInfo("SSLHandshake completed after close");
1275 mDNSPlatformTCPCloseConnection(sock
);
1279 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1280 else LogMsg("doSSLHandshake: sock->fd is -1");
1282 if (err
== errSSLWouldBlock
)
1283 sock
->handshake
= handshake_required
;
1288 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
1289 CFRelease(sock
->tlsContext
);
1290 sock
->tlsContext
= NULL
;
1293 sock
->err
= err
? mStatus_ConnFailed
: 0;
1294 sock
->handshake
= handshake_completed
;
1296 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
1297 doTcpSocketCallback(sock
);
1301 debugf("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
1302 KQueueUnlock("doSSLHandshake");
1305 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1307 mDNSlocal
void spawnSSLHandshake(TCPSocket
* sock
)
1309 debugf("spawnSSLHandshake %p: entry", sock
);
1311 if (sock
->handshake
!= handshake_required
) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock
->handshake
);
1312 sock
->handshake
= handshake_in_progress
;
1313 KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_READ
, sock
->kqEntry
);
1315 // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
1316 // to limit the number of threads used for SSLHandshake
1317 dispatch_async(SSLqueue
, ^{doSSLHandshake(sock
);});
1319 debugf("spawnSSLHandshake %p: done for %d", sock
, sock
->fd
);
1322 #endif /* NO_SECURITYFRAMEWORK */
1324 mDNSlocal
void tcpKQSocketCallback(__unused
int fd
, short filter
, void *context
, __unused mDNSBool encounteredEOF
)
1326 TCPSocket
*sock
= context
;
1327 sock
->err
= mStatus_NoError
;
1329 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1330 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1331 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1332 if (filter
== EVFILT_WRITE
)
1333 KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_WRITE
, sock
->kqEntry
);
1335 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1337 #ifndef NO_SECURITYFRAMEWORK
1340 sock
->setup
= mDNStrue
;
1341 sock
->err
= tlsSetupSock(sock
, kSSLClientSide
, kSSLStreamType
);
1344 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock
->err
);
1348 if (sock
->handshake
== handshake_required
)
1350 spawnSSLHandshake(sock
);
1353 else if (sock
->handshake
== handshake_in_progress
|| sock
->handshake
== handshake_to_be_closed
)
1357 else if (sock
->handshake
!= handshake_completed
)
1360 sock
->err
= mStatus_UnknownErr
;
1361 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock
->handshake
);
1363 #else /* NO_SECURITYFRAMEWORK */
1364 sock
->err
= mStatus_UnsupportedErr
;
1365 #endif /* NO_SECURITYFRAMEWORK */
1368 doTcpSocketCallback(sock
);
1371 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1372 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, KQueueEntry
*const entryRef
)
1374 dispatch_queue_t queue
= dispatch_get_main_queue();
1375 dispatch_source_t source
;
1376 if (flags
== EV_DELETE
)
1378 if (filter
== EVFILT_READ
)
1380 dispatch_source_cancel(entryRef
->readSource
);
1381 dispatch_release(entryRef
->readSource
);
1382 entryRef
->readSource
= mDNSNULL
;
1383 debugf("KQueueSet: source cancel for read %p, %p", entryRef
->readSource
, entryRef
->writeSource
);
1385 else if (filter
== EVFILT_WRITE
)
1387 dispatch_source_cancel(entryRef
->writeSource
);
1388 dispatch_release(entryRef
->writeSource
);
1389 entryRef
->writeSource
= mDNSNULL
;
1390 debugf("KQueueSet: source cancel for write %p, %p", entryRef
->readSource
, entryRef
->writeSource
);
1393 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter
);
1396 if (flags
!= EV_ADD
) LogMsg("KQueueSet: Invalid flags %d", flags
);
1398 if (filter
== EVFILT_READ
)
1400 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, fd
, 0, queue
);
1402 else if (filter
== EVFILT_WRITE
)
1404 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE
, fd
, 0, queue
);
1408 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter
);
1411 if (!source
) return -1;
1412 dispatch_source_set_event_handler(source
, ^{
1414 mDNSs32 stime
= mDNSPlatformRawTime();
1415 entryRef
->KQcallback(fd
, filter
, entryRef
->KQcontext
);
1416 mDNSs32 etime
= mDNSPlatformRawTime();
1417 if (etime
- stime
>= WatchDogReportingThreshold
)
1418 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime
- stime
);
1420 // Trigger the event delivery to the application. Even though we trigger the
1421 // event completion after handling every event source, these all will hopefully
1423 TriggerEventCompletion();
1426 dispatch_source_set_cancel_handler(source
, ^{
1427 if (entryRef
->fdClosed
)
1429 //LogMsg("CancelHandler: closing fd %d", fd);
1433 dispatch_resume(source
);
1434 if (filter
== EVFILT_READ
)
1435 entryRef
->readSource
= source
;
1437 entryRef
->writeSource
= source
;
1442 mDNSexport
void KQueueLock()
1445 mDNSexport
void KQueueUnlock(const char const *task
)
1447 (void)task
; //unused
1450 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, const KQueueEntry
*const entryRef
)
1452 struct kevent new_event
;
1453 EV_SET(&new_event
, fd
, filter
, flags
, 0, 0, (void*)entryRef
);
1454 return (kevent(KQueueFD
, &new_event
, 1, NULL
, 0, NULL
) < 0) ? errno
: 0;
1457 mDNSexport
void KQueueLock()
1459 mDNS
*const m
= &mDNSStorage
;
1460 pthread_mutex_lock(&m
->p
->BigMutex
);
1461 m
->p
->BigMutexStartTime
= mDNSPlatformRawTime();
1464 mDNSexport
void KQueueUnlock(const char* task
)
1466 mDNS
*const m
= &mDNSStorage
;
1467 mDNSs32 end
= mDNSPlatformRawTime();
1469 if (end
- m
->p
->BigMutexStartTime
>= WatchDogReportingThreshold
)
1470 LogInfo("WARNING: %s took %dms to complete", task
, end
- m
->p
->BigMutexStartTime
);
1472 pthread_mutex_unlock(&m
->p
->BigMutex
);
1475 if (send(m
->p
->WakeKQueueLoopFD
, &wake
, sizeof(wake
), 0) == -1)
1476 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno
, strerror(errno
));
1480 mDNSexport
void mDNSPlatformCloseFD(KQueueEntry
*kq
, int fd
)
1482 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1486 dispatch_source_cancel(kq
->readSource
);
1487 kq
->readSource
= mDNSNULL
;
1489 if (kq
->writeSource
)
1491 dispatch_source_cancel(kq
->writeSource
);
1492 kq
->writeSource
= mDNSNULL
;
1494 // Close happens in the cancellation handler
1495 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd
);
1496 kq
->fdClosed
= mDNStrue
;
1503 mDNSlocal mStatus
SetupTCPSocket(TCPSocket
*sock
, u_short sa_family
, mDNSIPPort
*port
, mDNSBool useBackgroundTrafficClass
)
1505 KQSocketSet
*cp
= &sock
->ss
;
1506 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1507 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1508 const int on
= 1; // "on" for setsockopt
1511 int skt
= socket(sa_family
, SOCK_STREAM
, IPPROTO_TCP
);
1512 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
));return(skt
); }
1514 // for TCP sockets, the traffic class is set once and not changed
1515 setTrafficClass(skt
, useBackgroundTrafficClass
);
1517 if (sa_family
== AF_INET
)
1520 struct sockaddr_in addr
;
1521 mDNSPlatformMemZero(&addr
, sizeof(addr
));
1522 addr
.sin_family
= AF_INET
;
1523 addr
.sin_port
= port
->NotAnInteger
;
1524 err
= bind(skt
, (struct sockaddr
*) &addr
, sizeof(addr
));
1525 if (err
< 0) { LogMsg("ERROR: bind %s", strerror(errno
)); close(skt
); return err
; }
1527 // Receive interface identifiers
1528 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1529 if (err
< 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
)); close(skt
); return err
; }
1531 mDNSPlatformMemZero(&addr
, sizeof(addr
));
1532 socklen_t len
= sizeof(addr
);
1533 err
= getsockname(skt
, (struct sockaddr
*) &addr
, &len
);
1534 if (err
< 0) { LogMsg("getsockname - %s", strerror(errno
)); close(skt
); return err
; }
1536 port
->NotAnInteger
= addr
.sin_port
;
1541 struct sockaddr_in6 addr6
;
1542 mDNSPlatformMemZero(&addr6
, sizeof(addr6
));
1543 addr6
.sin6_family
= AF_INET6
;
1544 addr6
.sin6_port
= port
->NotAnInteger
;
1545 err
= bind(skt
, (struct sockaddr
*) &addr6
, sizeof(addr6
));
1546 if (err
< 0) { LogMsg("ERROR: bind6 %s", strerror(errno
)); close(skt
); return err
; }
1548 // We want to receive destination addresses and receive interface identifiers
1549 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
1550 if (err
< 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno
)); close(skt
); return err
; }
1552 mDNSPlatformMemZero(&addr6
, sizeof(addr6
));
1553 socklen_t len
= sizeof(addr6
);
1554 err
= getsockname(skt
, (struct sockaddr
*) &addr6
, &len
);
1555 if (err
< 0) { LogMsg("getsockname6 - %s", strerror(errno
)); close(skt
); return err
; }
1557 port
->NotAnInteger
= addr6
.sin6_port
;
1561 k
->KQcallback
= tcpKQSocketCallback
;
1562 k
->KQcontext
= sock
;
1563 k
->KQtask
= "mDNSPlatformTCPSocket";
1564 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1565 k
->readSource
= mDNSNULL
;
1566 k
->writeSource
= mDNSNULL
;
1567 k
->fdClosed
= mDNSfalse
;
1569 return mStatus_NoError
;
1572 mDNSexport TCPSocket
*mDNSPlatformTCPSocket(TCPSocketFlags flags
, mDNSIPPort
*port
, mDNSBool useBackgroundTrafficClass
)
1576 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket
));
1577 if (!sock
) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL
); }
1579 mDNSPlatformMemZero(sock
, sizeof(TCPSocket
));
1581 sock
->ss
.m
= &mDNSStorage
;
1582 sock
->ss
.sktv4
= -1;
1583 sock
->ss
.sktv6
= -1;
1584 err
= SetupTCPSocket(sock
, AF_INET
, port
, useBackgroundTrafficClass
);
1588 err
= SetupTCPSocket(sock
, AF_INET6
, port
, useBackgroundTrafficClass
);
1589 if (err
) { mDNSPlatformCloseFD(&sock
->ss
.kqsv4
, sock
->ss
.sktv4
); sock
->ss
.sktv4
= -1; }
1593 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock
->fd
, errno
, strerror(errno
));
1594 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1597 // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
1598 sock
->fd
= sock
->ss
.sktv4
;
1599 sock
->callback
= mDNSNULL
;
1600 sock
->flags
= flags
;
1601 sock
->context
= mDNSNULL
;
1602 sock
->setup
= mDNSfalse
;
1603 sock
->connected
= mDNSfalse
;
1604 sock
->handshake
= handshake_required
;
1605 sock
->m
= &mDNSStorage
;
1606 sock
->err
= mStatus_NoError
;
1611 mDNSexport mStatus
mDNSPlatformTCPConnect(TCPSocket
*sock
, const mDNSAddr
*dst
, mDNSOpaque16 dstport
, domainname
*hostname
, mDNSInterfaceID InterfaceID
, TCPConnectionCallback callback
, void *context
)
1613 KQSocketSet
*cp
= &sock
->ss
;
1614 int *s
= (dst
->type
== mDNSAddrType_IPv4
) ? &cp
->sktv4
: &cp
->sktv6
;
1615 KQueueEntry
*k
= (dst
->type
== mDNSAddrType_IPv4
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1616 mStatus err
= mStatus_NoError
;
1617 struct sockaddr_storage ss
;
1619 sock
->callback
= callback
;
1620 sock
->context
= context
;
1621 sock
->setup
= mDNSfalse
;
1622 sock
->connected
= mDNSfalse
;
1623 sock
->handshake
= handshake_required
;
1624 sock
->err
= mStatus_NoError
;
1626 if (hostname
) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname
->c
); AssignDomainName(&sock
->hostname
, hostname
); }
1628 if (dst
->type
== mDNSAddrType_IPv4
)
1630 struct sockaddr_in
*saddr
= (struct sockaddr_in
*)&ss
;
1631 mDNSPlatformMemZero(saddr
, sizeof(*saddr
));
1632 saddr
->sin_family
= AF_INET
;
1633 saddr
->sin_port
= dstport
.NotAnInteger
;
1634 saddr
->sin_len
= sizeof(*saddr
);
1635 saddr
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1639 struct sockaddr_in6
*saddr6
= (struct sockaddr_in6
*)&ss
;
1640 mDNSPlatformMemZero(saddr6
, sizeof(*saddr6
));
1641 saddr6
->sin6_family
= AF_INET6
;
1642 saddr6
->sin6_port
= dstport
.NotAnInteger
;
1643 saddr6
->sin6_len
= sizeof(*saddr6
);
1644 saddr6
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1647 // Watch for connect complete (write is ready)
1648 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1649 if (KQueueSet(*s
, EV_ADD
/* | EV_ONESHOT */, EVFILT_WRITE
, k
))
1651 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1655 // Watch for incoming data
1656 if (KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
))
1658 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1662 if (fcntl(*s
, F_SETFL
, fcntl(*s
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
1664 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1665 return mStatus_UnknownErr
;
1668 // We bind to the interface and all subsequent packets including the SYN will be sent out
1669 // on this interface
1671 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
1672 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
1673 if (InterfaceID
&& InterfaceID
!= mDNSInterface_Unicast
)
1675 NetworkInterfaceInfoOSX
*info
= IfindexToInterfaceInfoOSX(InterfaceID
);
1676 if (dst
->type
== mDNSAddrType_IPv4
)
1679 if (info
) setsockopt(*s
, IPPROTO_IP
, IP_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1680 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID
); return mStatus_BadParamErr
; }
1682 (void)InterfaceID
; // Unused
1683 (void)info
; // Unused
1688 #ifdef IPV6_BOUND_IF
1689 if (info
) setsockopt(*s
, IPPROTO_IPV6
, IPV6_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1690 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID
); return mStatus_BadParamErr
; }
1692 (void)InterfaceID
; // Unused
1693 (void)info
; // Unused
1698 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
1699 // from which we can infer the destination address family. Hence we need to remember that here.
1700 // Instead of remembering the address family, we remember the right fd.
1703 // initiate connection wth peer
1704 if (connect(*s
, (struct sockaddr
*)&ss
, ss
.ss_len
) < 0)
1706 if (errno
== EINPROGRESS
) return mStatus_ConnPending
;
1707 if (errno
== EHOSTUNREACH
|| errno
== EADDRNOTAVAIL
|| errno
== ENETDOWN
)
1708 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock
->fd
, errno
, strerror(errno
));
1710 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock
->fd
, errno
, strerror(errno
), ss
.ss_len
);
1711 return mStatus_ConnFailed
;
1714 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1715 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1719 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1720 mDNSexport TCPSocket
*mDNSPlatformTCPAccept(TCPSocketFlags flags
, int fd
)
1722 mStatus err
= mStatus_NoError
;
1724 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket
));
1725 if (!sock
) return(mDNSNULL
);
1727 mDNSPlatformMemZero(sock
, sizeof(*sock
));
1729 sock
->flags
= flags
;
1731 if (flags
& kTCPSocketFlags_UseTLS
)
1733 #ifndef NO_SECURITYFRAMEWORK
1734 if (!ServerCerts
) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err
= mStatus_UnknownErr
; goto exit
; }
1736 err
= tlsSetupSock(sock
, kSSLServerSide
, kSSLStreamType
);
1737 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err
); goto exit
; }
1739 err
= SSLSetCertificate(sock
->tlsContext
, ServerCerts
);
1740 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err
); goto exit
; }
1742 err
= mStatus_UnsupportedErr
;
1743 #endif /* NO_SECURITYFRAMEWORK */
1745 #ifndef NO_SECURITYFRAMEWORK
1749 if (err
) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock
); return(mDNSNULL
); }
1753 mDNSexport mDNSu16
mDNSPlatformGetUDPPort(UDPSocket
*sock
)
1760 port
= sock
->ss
.port
.NotAnInteger
;
1765 mDNSlocal
void CloseSocketSet(KQSocketSet
*ss
)
1767 if (ss
->sktv4
!= -1)
1769 mDNSPlatformCloseFD(&ss
->kqsv4
, ss
->sktv4
);
1772 if (ss
->sktv6
!= -1)
1774 mDNSPlatformCloseFD(&ss
->kqsv6
, ss
->sktv6
);
1777 if (ss
->closeFlag
) *ss
->closeFlag
= 1;
1780 mDNSexport
void mDNSPlatformTCPCloseConnection(TCPSocket
*sock
)
1784 #ifndef NO_SECURITYFRAMEWORK
1785 if (sock
->tlsContext
)
1787 if (sock
->handshake
== handshake_in_progress
) // SSLHandshake thread using this sock (esp. tlsContext)
1789 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
1790 // When we come back from SSLHandshake, we will notice that a close was here and
1791 // call this function again which will do the cleanup then.
1792 sock
->handshake
= handshake_to_be_closed
;
1796 SSLClose(sock
->tlsContext
);
1797 CFRelease(sock
->tlsContext
);
1798 sock
->tlsContext
= NULL
;
1800 #endif /* NO_SECURITYFRAMEWORK */
1801 if (sock
->ss
.sktv4
!= -1)
1802 shutdown(sock
->ss
.sktv4
, 2);
1803 if (sock
->ss
.sktv6
!= -1)
1804 shutdown(sock
->ss
.sktv6
, 2);
1805 CloseSocketSet(&sock
->ss
);
1808 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock
);
1812 mDNSexport
long mDNSPlatformReadTCP(TCPSocket
*sock
, void *buf
, unsigned long buflen
, mDNSBool
*closed
)
1815 *closed
= mDNSfalse
;
1817 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1819 #ifndef NO_SECURITYFRAMEWORK
1820 if (sock
->handshake
== handshake_required
) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
1821 else if (sock
->handshake
== handshake_in_progress
) return 0;
1822 else if (sock
->handshake
!= handshake_completed
) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock
->handshake
);
1824 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
1825 mStatus err
= SSLRead(sock
->tlsContext
, buf
, buflen
, (size_t *)&nread
);
1826 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
1827 if (err
== errSSLClosedGraceful
) { nread
= 0; *closed
= mDNStrue
; }
1828 else if (err
&& err
!= errSSLWouldBlock
)
1829 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err
); nread
= -1; *closed
= mDNStrue
; }
1833 #endif /* NO_SECURITYFRAMEWORK */
1837 static int CLOSEDcount
= 0;
1838 static int EAGAINcount
= 0;
1839 nread
= recv(sock
->fd
, buf
, buflen
, 0);
1845 } // On success, clear our error counters
1846 else if (nread
== 0)
1849 if ((++CLOSEDcount
% 1000) == 0)
1851 LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock
->fd
, CLOSEDcount
);
1852 assert(CLOSEDcount
< 1000);
1853 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
1854 // crash mDNSResponder using assert() and restart fresh. See advantages below:
1855 // 1.Better User Experience
1856 // 2.CrashLogs frequency can be monitored
1857 // 3.StackTrace can be used for more info
1860 // else nread is negative -- see what kind of error we got
1861 else if (errno
== ECONNRESET
) { nread
= 0; *closed
= mDNStrue
; }
1862 else if (errno
!= EAGAIN
) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno
, strerror(errno
)); nread
= -1; }
1863 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
1866 if ((++EAGAINcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock
->fd
, EAGAINcount
); sleep(1); }
1873 mDNSexport
long mDNSPlatformWriteTCP(TCPSocket
*sock
, const char *msg
, unsigned long len
)
1877 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1879 #ifndef NO_SECURITYFRAMEWORK
1881 if (sock
->handshake
== handshake_required
) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
1882 if (sock
->handshake
== handshake_in_progress
) return 0;
1883 else if (sock
->handshake
!= handshake_completed
) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock
->handshake
);
1885 mStatus err
= SSLWrite(sock
->tlsContext
, msg
, len
, &processed
);
1887 if (!err
) nsent
= (int) processed
;
1888 else if (err
== errSSLWouldBlock
) nsent
= 0;
1889 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err
); nsent
= -1; }
1892 #endif /* NO_SECURITYFRAMEWORK */
1896 nsent
= send(sock
->fd
, msg
, len
, 0);
1899 if (errno
== EAGAIN
) nsent
= 0;
1900 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno
)); nsent
= -1; }
1907 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
1912 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1913 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1914 mDNSlocal mStatus
SetupSocket(KQSocketSet
*cp
, const mDNSIPPort port
, u_short sa_family
, mDNSIPPort
*const outport
)
1916 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1917 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1919 const int twofivefive
= 255;
1920 mStatus err
= mStatus_NoError
;
1921 char *errstr
= mDNSNULL
;
1925 cp
->closeFlag
= mDNSNULL
;
1927 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1928 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
));return(skt
); }
1930 // set default traffic class
1931 setTrafficClass(skt
, mDNSfalse
);
1933 #ifdef SO_RECV_ANYIF
1934 // Enable inbound packets on IFEF_AWDL interface.
1935 // Only done for multicast sockets, since we don't expect unicast socket operations
1936 // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
1937 if (mDNSSameIPPort(port
, MulticastDNSPort
))
1939 err
= setsockopt(skt
, SOL_SOCKET
, SO_RECV_ANYIF
, &on
, sizeof(on
));
1940 if (err
< 0) { errstr
= "setsockopt - SO_RECV_ANYIF"; goto fail
; }
1942 #endif // SO_RECV_ANYIF
1944 // ... with a shared UDP port, if it's for multicast receiving
1945 if (mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSSameIPPort(port
, NATPMPAnnouncementPort
))
1947 err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
1948 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
1951 // Don't want to wake from sleep for inbound packets on the mDNS sockets
1952 if (mDNSSameIPPort(port
, MulticastDNSPort
))
1955 if (setsockopt(skt
, SOL_SOCKET
, SO_NOWAKEFROMSLEEP
, &nowake
, sizeof(nowake
)) == -1)
1956 LogInfo("SetupSocket: SO_NOWAKEFROMSLEEP failed %s", strerror(errno
));
1959 if (sa_family
== AF_INET
)
1961 // We want to receive destination addresses
1962 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
1963 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
1965 // We want to receive interface identifiers
1966 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1967 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
1969 // We want to receive packet TTL value so we can check it
1970 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
1971 if (err
< 0) { errstr
= "setsockopt - IP_RECVTTL"; goto fail
; }
1973 // Send unicast packets with TTL 255
1974 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
1975 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
1977 // And multicast packets with TTL 255 too
1978 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
1979 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
1981 // And start listening for packets
1982 struct sockaddr_in listening_sockaddr
;
1983 listening_sockaddr
.sin_family
= AF_INET
;
1984 listening_sockaddr
.sin_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
1985 listening_sockaddr
.sin_addr
.s_addr
= mDNSSameIPPort(port
, NATPMPAnnouncementPort
) ? AllHosts_v4
.NotAnInteger
: 0;
1986 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
1987 if (err
) { errstr
= "bind"; goto fail
; }
1988 if (outport
) outport
->NotAnInteger
= listening_sockaddr
.sin_port
;
1990 else if (sa_family
== AF_INET6
)
1992 // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
1993 if (mDNSSameIPPort(port
, NATPMPAnnouncementPort
)) { if (outport
) *outport
= zeroIPPort
; close(skt
); return mStatus_NoError
; }
1995 // We want to receive destination addresses and receive interface identifiers
1996 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
1997 if (err
< 0) { errstr
= "setsockopt - IPV6_RECVPKTINFO"; goto fail
; }
1999 // We want to receive packet hop count value so we can check it
2000 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &on
, sizeof(on
));
2001 if (err
< 0) { errstr
= "setsockopt - IPV6_RECVHOPLIMIT"; goto fail
; }
2003 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
2004 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
2005 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
2006 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
2008 // Send unicast packets with TTL 255
2009 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
2010 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
2012 // And multicast packets with TTL 255 too
2013 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
2014 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
2016 // Want to receive our own packets
2017 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
2018 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
2020 // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
2021 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_USE_MIN_MTU
, &mtu
, sizeof(mtu
));
2022 if (err
< 0) // Since it is an optimization if we fail just log the err, no need to close the skt
2023 LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
2024 skt
, err
, errno
, strerror(errno
));
2026 // And start listening for packets
2027 struct sockaddr_in6 listening_sockaddr6
;
2028 mDNSPlatformMemZero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
2029 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
2030 listening_sockaddr6
.sin6_family
= AF_INET6
;
2031 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
2032 listening_sockaddr6
.sin6_flowinfo
= 0;
2033 listening_sockaddr6
.sin6_addr
= in6addr_any
; // Want to receive multicasts AND unicasts on this socket
2034 listening_sockaddr6
.sin6_scope_id
= 0;
2035 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
2036 if (err
) { errstr
= "bind"; goto fail
; }
2037 if (outport
) outport
->NotAnInteger
= listening_sockaddr6
.sin6_port
;
2040 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
2041 fcntl(skt
, F_SETFD
, 1); // set close-on-exec
2043 k
->KQcallback
= myKQSocketCallBack
;
2045 k
->KQtask
= "UDP packet reception";
2046 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2047 k
->readSource
= mDNSNULL
;
2048 k
->writeSource
= mDNSNULL
;
2049 k
->fdClosed
= mDNSfalse
;
2051 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
2053 return(mStatus_NoError
);
2056 saved_errno
= errno
;
2057 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
2058 if (strcmp(errstr
, "bind") || mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSIPPortIsZero(port
))
2059 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr
, skt
, mDNSVal16(port
), err
, saved_errno
, strerror(saved_errno
));
2061 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
2062 if (!strcmp(errstr
, "bind") && saved_errno
== EADDRINUSE
)
2065 if (mDNSSameIPPort(port
, MulticastDNSPort
))
2066 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
2067 "Congratulations, you've reproduced an elusive bug.\r"
2068 "Please contact the current assignee of <rdar://problem/3814904>.\r"
2069 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2070 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2073 mDNSPlatformCloseFD(k
, skt
);
2077 mDNSexport UDPSocket
*mDNSPlatformUDPSocket(const mDNSIPPort requestedport
)
2080 mDNSIPPort port
= requestedport
;
2081 mDNSBool randomizePort
= mDNSIPPortIsZero(requestedport
);
2082 int i
= 10000; // Try at most 10000 times to get a unique random port
2083 UDPSocket
*p
= mallocL("UDPSocket", sizeof(UDPSocket
));
2084 if (!p
) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL
); }
2085 mDNSPlatformMemZero(p
, sizeof(UDPSocket
));
2086 p
->ss
.port
= zeroIPPort
;
2087 p
->ss
.m
= &mDNSStorage
;
2090 p
->ss
.proxy
= mDNSfalse
;
2094 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
2095 if (randomizePort
) port
= mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
2096 err
= SetupSocket(&p
->ss
, port
, AF_INET
, &p
->ss
.port
);
2099 err
= SetupSocket(&p
->ss
, port
, AF_INET6
, &p
->ss
.port
);
2100 if (err
) { mDNSPlatformCloseFD(&p
->ss
.kqsv4
, p
->ss
.sktv4
); p
->ss
.sktv4
= -1; }
2103 } while (err
== EADDRINUSE
&& randomizePort
&& i
);
2107 // In customer builds we don't want to log failures with port 5351, because this is a known issue
2108 // of failing to bind to this port when Internet Sharing has already bound to it
2109 // We also don't want to log about port 5350, due to a known bug when some other
2110 // process is bound to it.
2111 if (mDNSSameIPPort(requestedport
, NATPMPPort
) || mDNSSameIPPort(requestedport
, NATPMPAnnouncementPort
))
2112 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
2113 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
2114 freeL("UDPSocket", p
);
2123 mDNSexport
void mDNSPlatformUDPClose(UDPSocket
*sock
)
2125 CloseSocketSet(&sock
->ss
);
2126 freeL("UDPSocket", sock
);
2130 mDNSexport mDNSBool
mDNSPlatformUDPSocketEncounteredEOF(const UDPSocket
*sock
)
2132 return (sock
->ss
.sktv4EOF
|| sock
->ss
.sktv6EOF
);
2135 #if COMPILER_LIKES_PRAGMA_MARK
2137 #pragma mark - BPF Raw packet sending/receiving
2140 #if APPLE_OSX_mDNSResponder
2142 mDNSexport
void mDNSPlatformSendRawPacket(const void *const msg
, const mDNSu8
*const end
, mDNSInterfaceID InterfaceID
)
2144 if (!InterfaceID
) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2145 NetworkInterfaceInfoOSX
*info
;
2147 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
2150 LogMsg("mDNSPlatformSendRawPacket: Invalid interface index %p", InterfaceID
);
2153 if (info
->BPF_fd
< 0)
2154 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info
->ifinfo
.ifname
, info
->BPF_fd
);
2157 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
2158 if (write(info
->BPF_fd
, msg
, end
- (mDNSu8
*)msg
) < 0)
2159 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info
->BPF_fd
, errno
, strerror(errno
));
2163 mDNSexport
void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr
*const tpa
, const mDNSEthAddr
*const tha
, mDNSInterfaceID InterfaceID
)
2165 if (!InterfaceID
) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
2166 NetworkInterfaceInfoOSX
*info
;
2167 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
2168 if (info
== NULL
) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID
); return; }
2169 // Manually inject an entry into our local ARP cache.
2170 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
2171 if (!mDNS_AddressIsLocalSubnet(&mDNSStorage
, InterfaceID
, tpa
))
2172 LogSPS("Don't need address cache entry for %s %#a %.6a", info
->ifinfo
.ifname
, tpa
, tha
);
2175 int result
= mDNSSetLocalAddressCacheEntry(info
->scope_id
, tpa
->type
, tpa
->ip
.v6
.b
, tha
->b
);
2176 if (result
) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info
->ifinfo
.ifname
, tpa
, tha
, result
);
2177 else LogSPS("Set local address cache entry for %s %#a %.6a", info
->ifinfo
.ifname
, tpa
, tha
);
2181 mDNSlocal
void CloseBPF(NetworkInterfaceInfoOSX
*const i
)
2183 LogSPS("%s closing BPF fd %d", i
->ifinfo
.ifname
, i
->BPF_fd
);
2184 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2185 // close will happen in the cancel handler
2186 dispatch_source_cancel(i
->BPF_source
);
2189 // Note: MUST NOT close() the underlying native BSD sockets.
2190 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
2191 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
2192 CFRunLoopRemoveSource(CFRunLoopGetMain(), i
->BPF_rls
, kCFRunLoopDefaultMode
);
2193 CFRelease(i
->BPF_rls
);
2194 CFSocketInvalidate(i
->BPF_cfs
);
2195 CFRelease(i
->BPF_cfs
);
2198 if (i
->BPF_mcfd
>= 0) { close(i
->BPF_mcfd
); i
->BPF_mcfd
= -1; }
2201 mDNSlocal
void bpf_callback_common(NetworkInterfaceInfoOSX
*info
)
2205 // Now we've got the lock, make sure the kqueue thread didn't close the fd out from under us (will not be a problem once the OS X
2206 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
2207 if (info
->BPF_fd
< 0) goto exit
;
2209 ssize_t n
= read(info
->BPF_fd
, &info
->m
->imsg
, info
->BPF_len
);
2210 const mDNSu8
*ptr
= (const mDNSu8
*)&info
->m
->imsg
;
2211 const mDNSu8
*end
= (const mDNSu8
*)&info
->m
->imsg
+ n
;
2212 debugf("%3d: bpf_callback got %d bytes on %s", info
->BPF_fd
, n
, info
->ifinfo
.ifname
);
2216 /* <rdar://problem/10287386>
2217 * sometimes there can be a race condition btw when the bpf socket
2218 * gets data and the callback get scheduled and when we call BIOCSETF (which
2219 * clears the socket). this can cause the read to hang for a really long time
2220 * and effectively prevent us from responding to requests for long periods of time.
2221 * to prevent this make the socket non blocking and just bail if we dont get anything
2223 if (errno
== EAGAIN
)
2225 LogMsg("bpf_callback got EAGAIN bailing");
2228 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info
->ifinfo
.ifname
, info
->BPF_fd
, errno
, strerror(errno
));
2235 const struct bpf_hdr
*const bh
= (const struct bpf_hdr
*)ptr
;
2236 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
2237 info
->BPF_fd
, ptr
, bh
->bh_hdrlen
, ptr
+ bh
->bh_hdrlen
, bh
->bh_caplen
, bh
->bh_datalen
,
2238 ptr
+ BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
), end
- (ptr
+ BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
)));
2239 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
2240 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
2241 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
2242 mDNSCoreReceiveRawPacket(info
->m
, ptr
+ bh
->bh_hdrlen
, ptr
+ bh
->bh_hdrlen
+ bh
->bh_caplen
, info
->ifinfo
.InterfaceID
);
2243 ptr
+= BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
);
2246 KQueueUnlock("bpf_callback");
2248 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2249 mDNSlocal
void bpf_callback_dispatch(NetworkInterfaceInfoOSX
*const info
)
2251 bpf_callback_common(info
);
2254 mDNSlocal
void bpf_callback(const CFSocketRef cfs
, const CFSocketCallBackType CallBackType
, const CFDataRef address
, const void *const data
, void *const context
)
2260 bpf_callback_common((NetworkInterfaceInfoOSX
*)context
);
2264 mDNSexport
void mDNSPlatformSendKeepalive(mDNSAddr
*sadd
, mDNSAddr
*dadd
, mDNSIPPort
*lport
, mDNSIPPort
*rport
, mDNSu32 seq
, mDNSu32 ack
, mDNSu16 win
)
2266 LogMsg("mDNSPlatformSendKeepalive called\n");
2267 mDNSSendKeepalive(sadd
->ip
.v6
.b
, dadd
->ip
.v6
.b
, lport
->NotAnInteger
, rport
->NotAnInteger
, seq
, ack
, win
);
2270 mDNSexport mStatus
mDNSPlatformClearSPSData(void)
2272 CFStringRef spsAddressKey
= NULL
;
2273 CFStringRef ownerOPTRecKey
= NULL
;
2274 SCDynamicStoreRef addrStore
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:SPSAddresses"), NULL
, NULL
);
2275 SCDynamicStoreRef optStore
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:SPSOPTRecord"), NULL
, NULL
);
2277 spsAddressKey
= SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, CFSTR("BonjourSleepProxyAddress"));
2278 if (spsAddressKey
!= NULL
)
2280 CFArrayRef keyList
= SCDynamicStoreCopyKeyList(addrStore
, spsAddressKey
);
2281 if (keyList
!= NULL
)
2283 if (SCDynamicStoreSetMultiple(addrStore
, NULL
, keyList
, NULL
) == false)
2284 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr( spsAddressKey
, kCFStringEncodingASCII
), SCErrorString(SCError()));
2286 if (keyList
) CFRelease(keyList
);
2288 ownerOPTRecKey
= SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, CFSTR("BonjourSleepProxyOPTRecord"));
2289 if(ownerOPTRecKey
!= NULL
)
2291 CFArrayRef keyList
= SCDynamicStoreCopyKeyList(addrStore
, ownerOPTRecKey
);
2292 if (keyList
!= NULL
)
2294 if (SCDynamicStoreSetMultiple(optStore
, NULL
, keyList
, NULL
) == false)
2295 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr(ownerOPTRecKey
, kCFStringEncodingASCII
), SCErrorString(SCError()));
2297 if (keyList
) CFRelease(keyList
);
2300 if (addrStore
) CFRelease(addrStore
);
2301 if (optStore
) CFRelease(optStore
);
2302 if (spsAddressKey
) CFRelease(spsAddressKey
);
2303 if (ownerOPTRecKey
) CFRelease(ownerOPTRecKey
);
2304 return KERN_SUCCESS
;
2307 mDNSlocal
int getMACAddress(int family
, v6addr_t raddr
, v6addr_t gaddr
, int *gfamily
, ethaddr_t eth
)
2311 struct rt_msghdr m_rtm
;
2315 struct rt_msghdr
*rtm
= &(m_rtmsg
.m_rtm
);
2316 char *cp
= m_rtmsg
.m_space
;
2317 int seq
= 6367, sock
, rlen
, i
;
2318 struct sockaddr_in
*sin
= NULL
;
2319 struct sockaddr_in6
*sin6
= NULL
;
2320 struct sockaddr_dl
*sdl
= NULL
;
2321 struct sockaddr_storage sins
;
2322 struct sockaddr_dl sdl_m
;
2324 #define NEXTADDR(w, s, len) \
2325 if (rtm->rtm_addrs & (w)) \
2327 bcopy((char *)s, cp, len); \
2331 bzero(&sins
, sizeof(struct sockaddr_storage
));
2332 bzero(&sdl_m
, sizeof(struct sockaddr_dl
));
2333 bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
2335 sock
= socket(PF_ROUTE
, SOCK_RAW
, 0);
2338 const int socket_errno
= errno
;
2339 LogMsg("getMACAddress: Can not open the socket - %s", strerror(socket_errno
));
2340 return socket_errno
;
2343 rtm
->rtm_addrs
|= RTA_DST
| RTA_GATEWAY
;
2344 rtm
->rtm_type
= RTM_GET
;
2346 rtm
->rtm_version
= RTM_VERSION
;
2347 rtm
->rtm_seq
= ++seq
;
2349 sdl_m
.sdl_len
= sizeof(sdl_m
);
2350 sdl_m
.sdl_family
= AF_LINK
;
2351 if (family
== AF_INET
)
2353 sin
= (struct sockaddr_in
*)&sins
;
2354 sin
->sin_family
= AF_INET
;
2355 sin
->sin_len
= sizeof(struct sockaddr_in
);
2356 memcpy(&sin
->sin_addr
, raddr
, sizeof(struct in_addr
));
2357 NEXTADDR(RTA_DST
, sin
, sin
->sin_len
);
2359 else if (family
== AF_INET6
)
2361 sin6
= (struct sockaddr_in6
*)&sins
;
2362 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
2363 sin6
->sin6_family
= AF_INET6
;
2364 memcpy(&sin6
->sin6_addr
, raddr
, sizeof(struct in6_addr
));
2365 NEXTADDR(RTA_DST
, sin6
, sin6
->sin6_len
);
2367 NEXTADDR(RTA_GATEWAY
, &sdl_m
, sdl_m
.sdl_len
);
2368 rtm
->rtm_msglen
= rlen
= cp
- (char *)&m_rtmsg
;
2370 if (write(sock
, (char *)&m_rtmsg
, rlen
) < 0)
2372 const int write_errno
= errno
;
2373 LogMsg("getMACAddress: writing to routing socket: %s", strerror(write_errno
));
2380 rlen
= read(sock
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
2382 while (rlen
> 0 && (rtm
->rtm_seq
!= seq
|| rtm
->rtm_pid
!= getpid()));
2385 LogMsg("getMACAddress: Read from routing socket failed");
2387 if (family
== AF_INET
)
2389 sin
= (struct sockaddr_in
*) (rtm
+ 1);
2390 sdl
= (struct sockaddr_dl
*) (sin
->sin_len
+ (char *) sin
);
2392 else if (family
== AF_INET6
)
2394 sin6
= (struct sockaddr_in6
*) (rtm
+1);
2395 sdl
= (struct sockaddr_dl
*) (sin6
->sin6_len
+ (char *) sin6
);
2400 LogMsg("getMACAddress: sdl is NULL for family %d", family
);
2405 // If the address is not on the local net, we get the IP address of the gateway.
2406 // We would have to repeat the process to get the MAC address of the gateway
2407 *gfamily
= sdl
->sdl_family
;
2408 if (sdl
->sdl_family
== AF_INET
)
2412 struct sockaddr_in
*new_sin
= (struct sockaddr_in
*)(sin
->sin_len
+(char*) sin
);
2413 memcpy(gaddr
, &new_sin
->sin_addr
, sizeof(struct in_addr
));
2417 LogMsg("getMACAddress: sin is NULL");
2422 else if (sdl
->sdl_family
== AF_INET6
)
2426 struct sockaddr_in6
*new_sin6
= (struct sockaddr_in6
*)(sin6
->sin6_len
+(char*) sin6
);
2427 memcpy(gaddr
, &new_sin6
->sin6_addr
, sizeof(struct in6_addr
));
2431 LogMsg("getMACAddress: sin6 is NULL");
2437 unsigned char *ptr
= (unsigned char *)LLADDR(sdl
);
2438 for (i
= 0; i
< ETHER_ADDR_LEN
; i
++)
2439 (eth
)[i
] = *(ptr
+i
);
2443 return KERN_SUCCESS
;
2446 mDNSlocal
int GetRemoteMacinternal(int family
, v6addr_t raddr
, ethaddr_t eth
)
2455 ret
= getMACAddress(family
, raddr
, gateway
, &gfamily
, eth
);
2458 memcpy(raddr
, gateway
, (gfamily
== AF_INET
) ? 4 : 16);
2463 while ((ret
== -1) && (count
< 5));
2467 mDNSlocal
int StoreSPSMACAddressinternal(int family
, v6addr_t spsaddr
, const char *ifname
)
2470 char spsip
[INET6_ADDRSTRLEN
];
2472 CFStringRef sckey
= NULL
;
2473 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL
, NULL
);
2474 SCDynamicStoreRef ipstore
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL
, NULL
);
2475 CFMutableDictionaryRef dict
= NULL
;
2476 CFStringRef entityname
= NULL
;
2477 CFDictionaryRef ipdict
= NULL
;
2478 CFArrayRef addrs
= NULL
;
2480 if ((store
== NULL
) || (ipstore
== NULL
))
2482 LogMsg("StoreSPSMACAddressinternal: Unable to accesss SC Dynamic Store");
2487 // Get the MAC address of the Sleep Proxy Server
2488 memset(eth
, 0, sizeof(eth
));
2489 ret
= GetRemoteMacinternal(family
, spsaddr
, eth
);
2492 LogMsg("StoreSPSMACAddressinternal: Failed to determine the MAC address");
2496 // Create/Update the dynamic store entry for the specified interface
2497 sckey
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname
, "/BonjourSleepProxyAddress");
2498 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2501 LogMsg("StoreSPSMACAddressinternal: SPSCreateDict() Could not create CFDictionary dict");
2506 CFStringRef macaddr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
2507 CFDictionarySetValue(dict
, CFSTR("MACAddress"), macaddr
);
2508 if (NULL
!= macaddr
)
2511 if( NULL
== inet_ntop(family
, (void *)spsaddr
, spsip
, sizeof(spsip
)))
2513 LogMsg("StoreSPSMACAddressinternal: inet_ntop failed: %s", strerror(errno
));
2518 CFStringRef ipaddr
= CFStringCreateWithCString(NULL
, spsip
, kCFStringEncodingUTF8
);
2519 CFDictionarySetValue(dict
, CFSTR("IPAddress"), ipaddr
);
2523 // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup
2524 if ((entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/IPv6"), ifname
)) != NULL
)
2526 if ((ipdict
= SCDynamicStoreCopyValue(ipstore
, entityname
)) != NULL
)
2528 if((addrs
= CFDictionaryGetValue(ipdict
, CFSTR("Addresses"))) != NULL
)
2530 addrs
= CFRetain(addrs
);
2531 CFDictionarySetValue(dict
, CFSTR("RegisteredAddresses"), addrs
);
2535 SCDynamicStoreSetValue(store
, sckey
, dict
);
2538 if (store
) CFRelease(store
);
2539 if (ipstore
) CFRelease(ipstore
);
2540 if (sckey
) CFRelease(sckey
);
2541 if (dict
) CFRelease(dict
);
2542 if (ipdict
) CFRelease(ipdict
);
2543 if (entityname
) CFRelease(entityname
);
2544 if (addrs
) CFRelease(addrs
);
2549 mDNSlocal
void mDNSStoreSPSMACAddress(int family
, v6addr_t spsaddr
, char *ifname
)
2557 mDNSPlatformMemCopy(addr
.saddr
, spsaddr
, sizeof(v6addr_t
));
2559 err
= StoreSPSMACAddressinternal(family
, (uint8_t *)addr
.saddr
, ifname
);
2561 LogMsg("mDNSStoreSPSMACAddress : failed");
2564 mDNSexport mStatus
mDNSPlatformStoreSPSMACAddr(mDNSAddr
*spsaddr
, char *ifname
)
2566 int family
= (spsaddr
->type
== mDNSAddrType_IPv4
) ? AF_INET
: AF_INET6
;
2568 LogInfo("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr
, ifname
);
2569 mDNSStoreSPSMACAddress(family
, spsaddr
->ip
.v6
.b
, ifname
);
2571 return KERN_SUCCESS
;
2575 mDNSexport mStatus
mDNSPlatformStoreOwnerOptRecord(char *ifname
, DNSMessage
* msg
, int length
)
2578 CFStringRef sckey
= NULL
;
2579 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:StoreOwnerOPTRecord"), NULL
, NULL
);
2580 CFMutableDictionaryRef dict
= NULL
;
2584 LogMsg("mDNSPlatformStoreOwnerOptRecord: Unable to accesss SC Dynamic Store");
2589 // Create/Update the dynamic store entry for the specified interface
2590 sckey
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname
, "/BonjourSleepProxyOPTRecord");
2591 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2594 LogMsg("mDNSPlatformStoreOwnerOptRecord: Could not create CFDictionary dictionary to store OPT Record");
2599 CFDataRef optRec
= NULL
;
2600 optRec
= CFDataCreate(NULL
, (const uint8_t *)msg
, (CFIndex
)length
);
2601 CFDictionarySetValue(dict
, CFSTR("OwnerOPTRecord"), optRec
);
2602 if (NULL
!= optRec
) CFRelease(optRec
);
2604 SCDynamicStoreSetValue(store
, sckey
, dict
);
2607 if (NULL
!= store
) CFRelease(store
);
2608 if (NULL
!= sckey
) CFRelease(sckey
);
2609 if (NULL
!= dict
) CFRelease(dict
);
2613 mDNSlocal
void mDNSGet_RemoteMAC(int family
, v6addr_t raddr
)
2616 IPAddressMACMapping
*addrMapping
;
2617 int kr
= KERN_FAILURE
;
2623 bzero(eth
, sizeof(ethaddr_t
));
2624 mDNSPlatformMemCopy(dst
.addr
, raddr
, sizeof(v6addr_t
));
2626 kr
= GetRemoteMacinternal(family
, (uint8_t *)dst
.addr
, eth
);
2628 // If the call to get the remote MAC address succeeds, allocate and copy
2629 // the values and schedule a task to update the MAC address in the TCP Keepalive record.
2632 addrMapping
= mDNSPlatformMemAllocate(sizeof(IPAddressMACMapping
));
2633 snprintf(addrMapping
->ethaddr
, sizeof(addrMapping
->ethaddr
), "%02x:%02x:%02x:%02x:%02x:%02x",
2634 eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
2635 if (family
== AF_INET
)
2637 addrMapping
->ipaddr
.type
= mDNSAddrType_IPv4
;
2638 mDNSPlatformMemCopy(addrMapping
->ipaddr
.ip
.v4
.b
, raddr
, sizeof(v6addr_t
));
2642 addrMapping
->ipaddr
.type
= mDNSAddrType_IPv6
;
2643 mDNSPlatformMemCopy(addrMapping
->ipaddr
.ip
.v6
.b
, raddr
, sizeof(v6addr_t
));
2645 UpdateRMAC(&mDNSStorage
, addrMapping
);
2649 mDNSexport mStatus
mDNSPlatformGetRemoteMacAddr(mDNSAddr
*raddr
)
2651 int family
= (raddr
->type
== mDNSAddrType_IPv4
) ? AF_INET
: AF_INET6
;
2653 LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC");
2654 mDNSGet_RemoteMAC(family
, raddr
->ip
.v6
.b
);
2656 return KERN_SUCCESS
;
2659 mDNSexport mStatus
mDNSPlatformRetrieveTCPInfo(mDNSAddr
*laddr
, mDNSIPPort
*lport
, mDNSAddr
*raddr
, mDNSIPPort
*rport
, mDNSTCPInfo
*mti
)
2663 int family
= (laddr
->type
== mDNSAddrType_IPv4
) ? AF_INET
: AF_INET6
;
2665 error
= mDNSRetrieveTCPInfo(family
, laddr
->ip
.v6
.b
, lport
->NotAnInteger
, raddr
->ip
.v6
.b
, rport
->NotAnInteger
, (uint32_t *)&(mti
->seq
), (uint32_t *)&(mti
->ack
), (uint16_t *)&(mti
->window
), (int32_t*)&intfid
);
2666 if (error
!= KERN_SUCCESS
)
2668 LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__
, error
);
2671 mti
->IntfId
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, intfid
);
2675 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2677 mDNSlocal
int CountProxyTargets(NetworkInterfaceInfoOSX
*x
, int *p4
, int *p6
)
2679 int numv4
= 0, numv6
= 0;
2682 for (rr
= mDNSStorage
.ResourceRecords
; rr
; rr
=rr
->next
)
2683 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2685 if (p4
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv4
, &rr
->AddressProxy
.ip
.v4
);
2689 for (rr
= mDNSStorage
.ResourceRecords
; rr
; rr
=rr
->next
)
2690 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
2692 if (p6
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv6
, &rr
->AddressProxy
.ip
.v6
);
2696 if (p4
) *p4
= numv4
;
2697 if (p6
) *p6
= numv6
;
2698 return(numv4
+ numv6
);
2701 mDNSexport
void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID
)
2703 mDNS
*const m
= &mDNSStorage
;
2704 NetworkInterfaceInfoOSX
*x
;
2706 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
2707 for (x
= m
->p
->InterfaceList
; x
; x
= x
->next
) if ((x
->ifinfo
.InterfaceID
== InterfaceID
) && (x
->BPF_fd
>= 0)) break;
2709 if (!x
) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID
); return; }
2711 #define MAX_BPF_ADDRS 250
2712 int numv4
= 0, numv6
= 0;
2714 if (CountProxyTargets(x
, &numv4
, &numv6
) > MAX_BPF_ADDRS
)
2716 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4
, numv6
);
2717 if (numv4
> MAX_BPF_ADDRS
) numv4
= MAX_BPF_ADDRS
;
2718 numv6
= MAX_BPF_ADDRS
- numv4
;
2721 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x
->BPF_fd
, x
->ifinfo
.ifname
, &x
->ifinfo
.MAC
, numv4
, numv6
);
2723 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
2724 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
2725 static struct bpf_insn filter
[17 + MAX_BPF_ADDRS
] =
2727 BPF_STMT(BPF_LD
+ BPF_H
+ BPF_ABS
, 12), // 0 Read Ethertype (bytes 12,13)
2729 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
2730 BPF_STMT(BPF_RET
+ BPF_K
, 42), // 2 Return 42-byte ARP
2732 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
2734 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
2735 BPF_STMT(BPF_LD
+ BPF_H
+ BPF_ABS
, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
2736 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
2737 BPF_STMT(BPF_RET
+ BPF_K
, 86), // 7 Return 86-byte ND
2739 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
2740 BPF_STMT(BPF_LD
+ BPF_W
+ BPF_ABS
, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
2743 // Special filter program to use when there are no address proxy records
2744 static struct bpf_insn nullfilter
[] =
2746 BPF_STMT(BPF_RET
| BPF_K
, 0) // 0 Match no packets and return size 0
2749 struct bpf_program prog
;
2750 if (!numv4
&& !numv6
)
2752 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
2753 if (m
->timenow
== 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
2755 // Cancel any previous ND group memberships we had
2756 if (x
->BPF_mcfd
>= 0)
2762 // Schedule check to see if we can close this BPF_fd now
2763 if (!m
->NetworkChanged
) m
->NetworkChanged
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2);
2764 if (x
->BPF_fd
< 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
2766 prog
.bf_insns
= nullfilter
;
2770 struct bpf_insn
*pc
= &filter
[9];
2771 struct bpf_insn
*chk6
= pc
+ numv4
+ 1; // numv4 address checks, plus a "return 0"
2772 struct bpf_insn
*fail
= chk6
+ 1 + numv6
; // Get v6 Dst LSW, plus numv6 address checks
2773 struct bpf_insn
*ret4
= fail
+ 1;
2774 struct bpf_insn
*ret6
= ret4
+ 4;
2776 static const struct bpf_insn rf
= BPF_STMT(BPF_RET
+ BPF_K
, 0); // No match: Return nothing
2778 static const struct bpf_insn g6
= BPF_STMT(BPF_LD
+ BPF_W
+ BPF_ABS
, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
2780 static const struct bpf_insn r4a
= BPF_STMT(BPF_LDX
+ BPF_B
+ BPF_MSH
, 14); // Get IP Header length (normally 20)
2781 static const struct bpf_insn r4b
= BPF_STMT(BPF_LD
+ BPF_IMM
, 54); // A = 54 (14-byte Ethernet plus 20-byte TCP + 20 bytes spare)
2782 static const struct bpf_insn r4c
= BPF_STMT(BPF_ALU
+ BPF_ADD
+ BPF_X
, 0); // A += IP Header length
2783 static const struct bpf_insn r4d
= BPF_STMT(BPF_RET
+ BPF_A
, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
2785 static const struct bpf_insn r6a
= BPF_STMT(BPF_RET
+ BPF_K
, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
2787 BPF_SetOffset(&filter
[4], jf
, fail
); // If Ethertype not ARP, IPv4, or IPv6, fail
2788 BPF_SetOffset(&filter
[6], jf
, chk6
); // If IPv6 but not ICMPv6, go to IPv6 address list check
2790 // BPF Byte-Order Note
2791 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
2792 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
2793 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
2794 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
2795 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
2796 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
2797 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
2798 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
2799 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
2800 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
2802 // IPSEC capture size notes:
2803 // 8 bytes UDP header
2804 // 4 bytes Non-ESP Marker
2805 // 28 bytes IKE Header
2807 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
2810 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2811 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2813 mDNSv4Addr a
= rr
->AddressProxy
.ip
.v4
;
2814 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
2815 BPF_SetOffset(pc
, jt
, ret4
);
2817 pc
->k
= (bpf_u_int32
)a
.b
[0] << 24 | (bpf_u_int32
)a
.b
[1] << 16 | (bpf_u_int32
)a
.b
[2] << 8 | (bpf_u_int32
)a
.b
[3];
2822 if (pc
!= chk6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc
, chk6
);
2823 *pc
++ = g6
; // chk6 points here
2825 // First cancel any previous ND group memberships we had, then create a fresh socket
2826 if (x
->BPF_mcfd
>= 0) close(x
->BPF_mcfd
);
2827 x
->BPF_mcfd
= socket(AF_INET6
, SOCK_DGRAM
, 0);
2829 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2830 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
2832 const mDNSv6Addr
*const a
= &rr
->AddressProxy
.ip
.v6
;
2833 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
2834 BPF_SetOffset(pc
, jt
, ret6
);
2836 pc
->k
= (bpf_u_int32
)a
->b
[0x0C] << 24 | (bpf_u_int32
)a
->b
[0x0D] << 16 | (bpf_u_int32
)a
->b
[0x0E] << 8 | (bpf_u_int32
)a
->b
[0x0F];
2839 struct ipv6_mreq i6mr
;
2840 i6mr
.ipv6mr_interface
= x
->scope_id
;
2841 i6mr
.ipv6mr_multiaddr
= *(const struct in6_addr
*)&NDP_prefix
;
2842 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xD] = a
->b
[0xD];
2843 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xE] = a
->b
[0xE];
2844 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xF] = a
->b
[0xF];
2846 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
2847 mStatus err
= setsockopt(x
->BPF_mcfd
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
2848 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
2849 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2851 err
= setsockopt(x
->BPF_mcfd
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
2852 if (err
< 0 && (errno
!= EADDRINUSE
)) // Joining same group twice can give "Address already in use" error -- no need to report that
2853 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2855 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr
.ipv6mr_multiaddr
, a
);
2858 if (pc
!= fail
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc
, fail
);
2859 *pc
++ = rf
; // fail points here
2861 if (pc
!= ret4
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc
, ret4
);
2862 *pc
++ = r4a
; // ret4 points here
2867 if (pc
!= ret6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc
, ret6
);
2868 *pc
++ = r6a
; // ret6 points here
2870 // For debugging BPF filter program
2872 for (q
=0; q
<prog
.bf_len
; q
++)
2873 LogSPS("mDNSPlatformUpdateProxyList: %2d { 0x%02x, %d, %d, 0x%08x },", q
, prog
.bf_insns
[q
].code
, prog
.bf_insns
[q
].jt
, prog
.bf_insns
[q
].jf
, prog
.bf_insns
[q
].k
);
2875 prog
.bf_len
= (u_int
)(pc
- filter
);
2876 prog
.bf_insns
= filter
;
2879 if (ioctl(x
->BPF_fd
, BIOCSETFNR
, &prog
) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog
.bf_len
, errno
, strerror(errno
));
2880 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog
.bf_len
);
2883 mDNSexport
void mDNSPlatformReceiveBPF_fd(int fd
)
2885 mDNS
*const m
= &mDNSStorage
;
2888 NetworkInterfaceInfoOSX
*i
;
2889 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
) if (i
->BPF_fd
== -2) break;
2890 if (!i
) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd
); close(fd
); }
2893 LogSPS("%s using BPF fd %d", i
->ifinfo
.ifname
, fd
);
2895 struct bpf_version v
;
2896 if (ioctl(fd
, BIOCVERSION
, &v
) < 0)
2897 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2898 else if (BPF_MAJOR_VERSION
!= v
.bv_major
|| BPF_MINOR_VERSION
!= v
.bv_minor
)
2899 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
2900 fd
, i
->ifinfo
.ifname
, BPF_MAJOR_VERSION
, BPF_MINOR_VERSION
, v
.bv_major
, v
.bv_minor
);
2902 if (ioctl(fd
, BIOCGBLEN
, &i
->BPF_len
) < 0)
2903 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2905 if (i
->BPF_len
> sizeof(m
->imsg
))
2907 i
->BPF_len
= sizeof(m
->imsg
);
2908 if (ioctl(fd
, BIOCSBLEN
, &i
->BPF_len
) < 0)
2909 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2911 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd
, i
->ifinfo
.ifname
, i
->BPF_len
);
2914 static const u_int opt_one
= 1;
2915 if (ioctl(fd
, BIOCIMMEDIATE
, &opt_one
) < 0)
2916 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2918 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
2919 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2921 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
2922 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2924 /* <rdar://problem/10287386>
2925 * make socket non blocking see comments in bpf_callback_common for more info
2927 if (fcntl(fd
, F_SETFL
, fcntl(fd
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
2929 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2933 mDNSPlatformMemZero(&ifr
, sizeof(ifr
));
2934 strlcpy(ifr
.ifr_name
, i
->ifinfo
.ifname
, sizeof(ifr
.ifr_name
));
2935 if (ioctl(fd
, BIOCSETIF
, &ifr
) < 0)
2936 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
)); i
->BPF_fd
= -3; }
2939 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2941 i
->BPF_source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, fd
, 0, dispatch_get_main_queue());
2942 if (!i
->BPF_source
) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
2943 dispatch_source_set_event_handler(i
->BPF_source
, ^{bpf_callback_dispatch(i
);});
2944 dispatch_source_set_cancel_handler(i
->BPF_source
, ^{close(fd
);});
2945 dispatch_resume(i
->BPF_source
);
2947 CFSocketContext myCFSocketContext
= { 0, i
, NULL
, NULL
, NULL
};
2949 i
->BPF_cfs
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
, bpf_callback
, &myCFSocketContext
);
2950 i
->BPF_rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, i
->BPF_cfs
, 0);
2951 CFRunLoopAddSource(CFRunLoopGetMain(), i
->BPF_rls
, kCFRunLoopDefaultMode
);
2953 mDNSPlatformUpdateProxyList(i
->ifinfo
.InterfaceID
);
2960 #endif // APPLE_OSX_mDNSResponder
2962 #if COMPILER_LIKES_PRAGMA_MARK
2964 #pragma mark - Key Management
2967 #ifndef NO_SECURITYFRAMEWORK
2968 mDNSlocal CFArrayRef
CopyCertChain(SecIdentityRef identity
)
2970 CFMutableArrayRef certChain
= NULL
;
2971 if (!identity
) { LogMsg("CopyCertChain: identity is NULL"); return(NULL
); }
2972 SecCertificateRef cert
;
2973 OSStatus err
= SecIdentityCopyCertificate(identity
, &cert
);
2974 if (err
|| !cert
) LogMsg("CopyCertChain: SecIdentityCopyCertificate() returned %d", (int) err
);
2977 #pragma clang diagnostic push
2978 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2979 SecPolicySearchRef searchRef
;
2980 err
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, &CSSMOID_APPLE_X509_BASIC
, NULL
, &searchRef
);
2981 if (err
|| !searchRef
) LogMsg("CopyCertChain: SecPolicySearchCreate() returned %d", (int) err
);
2984 SecPolicyRef policy
;
2985 err
= SecPolicySearchCopyNext(searchRef
, &policy
);
2986 if (err
|| !policy
) LogMsg("CopyCertChain: SecPolicySearchCopyNext() returned %d", (int) err
);
2989 CFArrayRef wrappedCert
= CFArrayCreate(NULL
, (const void**) &cert
, 1, &kCFTypeArrayCallBacks
);
2990 if (!wrappedCert
) LogMsg("CopyCertChain: wrappedCert is NULL");
2994 err
= SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
);
2995 if (err
|| !trust
) LogMsg("CopyCertChain: SecTrustCreateWithCertificates() returned %d", (int) err
);
2998 err
= SecTrustEvaluate(trust
, NULL
);
2999 if (err
) LogMsg("CopyCertChain: SecTrustEvaluate() returned %d", (int) err
);
3002 CFArrayRef rawCertChain
;
3003 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
3004 err
= SecTrustGetResult(trust
, NULL
, &rawCertChain
, &statusChain
);
3005 if (err
|| !rawCertChain
|| !statusChain
) LogMsg("CopyCertChain: SecTrustGetResult() returned %d", (int) err
);
3008 certChain
= CFArrayCreateMutableCopy(NULL
, 0, rawCertChain
);
3009 if (!certChain
) LogMsg("CopyCertChain: certChain is NULL");
3012 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
3013 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
3014 CFArraySetValueAtIndex(certChain
, 0, identity
);
3015 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
3016 if (CFArrayGetCount(certChain
) > 1) CFArrayRemoveValueAtIndex(certChain
, CFArrayGetCount(certChain
) - 1);
3018 CFRelease(rawCertChain
);
3019 // Do not free statusChain:
3020 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
3021 // certChain: Call the CFRelease function to release this object when you are finished with it.
3022 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
3027 CFRelease(wrappedCert
);
3031 CFRelease(searchRef
);
3033 #pragma clang diagnostic pop
3038 #endif /* NO_SECURITYFRAMEWORK */
3040 mDNSexport mStatus
mDNSPlatformTLSSetupCerts(void)
3042 #ifdef NO_SECURITYFRAMEWORK
3043 return mStatus_UnsupportedErr
;
3045 SecIdentityRef identity
= nil
;
3046 SecIdentitySearchRef srchRef
= nil
;
3049 #pragma clang diagnostic push
3050 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3051 // search for "any" identity matching specified key use
3052 // In this app, we expect there to be exactly one
3053 err
= SecIdentitySearchCreate(NULL
, CSSM_KEYUSE_DECRYPT
, &srchRef
);
3054 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err
); return err
; }
3056 err
= SecIdentitySearchCopyNext(srchRef
, &identity
);
3057 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err
); return err
; }
3058 #pragma clang diagnostic pop
3060 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
3061 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr
; }
3063 // Found one. Call CopyCertChain to create the correct certificate chain.
3064 ServerCerts
= CopyCertChain(identity
);
3065 if (ServerCerts
== nil
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: CopyCertChain error"); return mStatus_UnknownErr
; }
3067 return mStatus_NoError
;
3068 #endif /* NO_SECURITYFRAMEWORK */
3071 mDNSexport
void mDNSPlatformTLSTearDownCerts(void)
3073 #ifndef NO_SECURITYFRAMEWORK
3074 if (ServerCerts
) { CFRelease(ServerCerts
); ServerCerts
= NULL
; }
3075 #endif /* NO_SECURITYFRAMEWORK */
3078 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
3079 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
3081 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
3082 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
3085 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
3090 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
3091 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
3093 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
3096 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
3101 mDNSexport mDNSBool
DictionaryIsEnabled(CFDictionaryRef dict
)
3104 CFNumberRef state
= (CFNumberRef
)CFDictionaryGetValue(dict
, CFSTR("Enabled"));
3105 if (!state
) return mDNSfalse
;
3106 if (!CFNumberGetValue(state
, kCFNumberSInt32Type
, &val
))
3107 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse
; }
3108 return val
? mDNStrue
: mDNSfalse
;
3111 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
3113 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
3115 if (sa
->sa_family
== AF_INET
)
3117 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
3118 ip
->type
= mDNSAddrType_IPv4
;
3119 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
3120 return(mStatus_NoError
);
3123 if (sa
->sa_family
== AF_INET6
)
3125 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
3126 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
3127 // value into the second word of the IPv6 link-local address, so they can just
3128 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
3129 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
3130 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
3131 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
3132 ip
->type
= mDNSAddrType_IPv6
;
3133 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
3134 return(mStatus_NoError
);
3137 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
3138 return(mStatus_Invalid
);
3141 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
3143 mDNSEthAddr eth
= zeroEthAddr
;
3145 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
3148 CFDictionaryRef dict
= SCDynamicStoreCopyValue(NULL
, entityname
);
3151 CFRange range
= { 0, 6 }; // Offset, length
3152 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
3153 if (data
&& CFDataGetLength(data
) == 6)
3154 CFDataGetBytes(data
, range
, eth
.b
);
3157 CFRelease(entityname
);
3163 mDNSlocal
int GetMAC(mDNSEthAddr
*eth
, u_short ifindex
)
3165 struct ifaddrs
*ifa
;
3166 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
3167 if (ifa
->ifa_addr
&& ifa
->ifa_addr
->sa_family
== AF_LINK
)
3169 const struct sockaddr_dl
*const sdl
= (const struct sockaddr_dl
*)ifa
->ifa_addr
;
3170 if (sdl
->sdl_index
== ifindex
)
3171 { mDNSPlatformMemCopy(eth
->b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6); return 0; }
3177 #ifndef SIOCGIFWAKEFLAGS
3178 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
3181 #ifndef IF_WAKE_ON_MAGIC_PACKET
3182 #define IF_WAKE_ON_MAGIC_PACKET 0x01
3185 #ifndef ifr_wake_flags
3186 #define ifr_wake_flags ifr_ifru.ifru_intval
3191 RegistryEntrySearchCFPropertyAndIOObject( io_registry_entry_t entry
,
3192 const io_name_t plane
,
3194 CFTypeRef
* outProperty
,
3195 io_registry_entry_t
* outEntry
)
3199 IOObjectRetain(entry
);
3202 CFTypeRef ref
= IORegistryEntryCreateCFProperty(entry
, keystr
, kCFAllocatorDefault
, mDNSNULL
);
3205 if (outProperty
) *outProperty
= ref
;
3206 else CFRelease(ref
);
3209 io_registry_entry_t parent
;
3210 kr
= IORegistryEntryGetParentEntry(entry
, plane
, &parent
);
3211 if (kr
!= KERN_SUCCESS
) parent
= mDNSNULL
;
3212 IOObjectRelease(entry
);
3215 if (!entry
) kr
= kIOReturnNoDevice
;
3218 if (outEntry
) *outEntry
= entry
;
3219 else IOObjectRelease(entry
);
3225 mDNSlocal mDNSBool
CheckInterfaceSupport(NetworkInterfaceInfo
*const intf
, const char *key
)
3227 io_service_t service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOBSDNameMatching(kIOMasterPortDefault
, 0, intf
->ifname
));
3230 LogSPS("CheckInterfaceSupport: No service for interface %s", intf
->ifname
);
3234 mDNSBool ret
= mDNSfalse
;
3236 CFStringRef keystr
= CFStringCreateWithCString(NULL
, key
, kCFStringEncodingUTF8
);
3237 kern_return_t kr
= RegistryEntrySearchCFPropertyAndIOObject(service
, kIOServicePlane
, keystr
, mDNSNULL
, mDNSNULL
);
3239 if (kr
== KERN_SUCCESS
) ret
= mDNStrue
;
3243 IOObjectGetClass(service
, n1
);
3244 LogSPS("CheckInterfaceSupport: No %s for interface %s/%s kr %d", key
, intf
->ifname
, n1
, kr
);
3248 IOObjectRelease(service
);
3253 mDNSlocal mDNSBool
InterfaceSupportsKeepAlive(NetworkInterfaceInfo
*const intf
)
3255 return CheckInterfaceSupport(intf
, mDNS_IOREG_KA_KEY
);
3258 mDNSlocal mDNSBool
NetWakeInterface(NetworkInterfaceInfoOSX
*i
)
3260 // We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D.
3261 if (!MulticastInterface(i
) || (i
->ifa_flags
& IFF_LOOPBACK
) || i
->D2DInterface
)
3263 LogSPS("NetWakeInterface: returning false for %s", i
->ifinfo
.ifname
);
3267 // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
3268 // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
3269 // when the power source is not AC Power.
3270 if (InterfaceSupportsKeepAlive(&i
->ifinfo
))
3272 LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i
->ifinfo
.ifname
);
3276 int s
= socket(AF_INET
, SOCK_DGRAM
, 0);
3277 if (s
< 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i
->ifinfo
.ifname
, s
, errno
, strerror(errno
)); return(mDNSfalse
); }
3280 strlcpy(ifr
.ifr_name
, i
->ifinfo
.ifname
, sizeof(ifr
.ifr_name
));
3281 if (ioctl(s
, SIOCGIFWAKEFLAGS
, &ifr
) < 0)
3283 const int ioctl_errno
= errno
;
3284 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
3285 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
3286 // error code is being returned from the kernel, we need to use the kernel version.
3287 #define KERNEL_EOPNOTSUPP 102
3288 if (ioctl_errno
!= KERNEL_EOPNOTSUPP
) // "Operation not supported on socket", the expected result on Leopard and earlier
3289 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i
->ifinfo
.ifname
, ioctl_errno
, strerror(ioctl_errno
));
3290 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
3291 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
3292 ifr
.ifr_wake_flags
= (ioctl_errno
== KERNEL_EOPNOTSUPP
&& !(i
)->BSSID
.l
[0] && i
->m
->SystemWakeOnLANEnabled
) ? IF_WAKE_ON_MAGIC_PACKET
: 0;
3297 // ifr.ifr_wake_flags = IF_WAKE_ON_MAGIC_PACKET; // For testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
3299 LogSPS("NetWakeInterface: %-6s %#-14a %s WOMP", i
->ifinfo
.ifname
, &i
->ifinfo
.ip
, (ifr
.ifr_wake_flags
& IF_WAKE_ON_MAGIC_PACKET
) ? "supports" : "no");
3301 return((ifr
.ifr_wake_flags
& IF_WAKE_ON_MAGIC_PACKET
) != 0);
3304 mDNSlocal u_int64_t
getExtendedFlags(char * ifa_name
)
3309 sockFD
= socket(AF_INET
, SOCK_DGRAM
, 0);
3312 LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno
, strerror(errno
));
3316 ifr
.ifr_addr
.sa_family
= AF_INET
;
3317 strlcpy(ifr
.ifr_name
, ifa_name
, sizeof(ifr
.ifr_name
));
3319 if (ioctl(sockFD
, SIOCGIFEFLAGS
, (caddr_t
)&ifr
) == -1)
3321 LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno
, strerror(errno
));
3326 return ifr
.ifr_eflags
;
3330 // IFRTYPE_FUNCTIONAL_INTCOPROC type interfaces on macOS do not support Bonjour discovery.
3331 mDNSlocal mDNSBool
isCoprocessorInterface(int sockFD
, char * ifa_name
)
3337 LogMsg("isCoprocessorInterface: invalid socket FD passed: %d", sockFD
);
3341 memset(&ifr
, 0, sizeof(struct ifreq
));
3342 strlcpy(ifr
.ifr_name
, ifa_name
, sizeof(ifr
.ifr_name
));
3344 if (ioctl(sockFD
, SIOCGIFFUNCTIONALTYPE
, (caddr_t
)&ifr
) == -1)
3346 LogMsg("isCoprocessorInterface: SIOCGIFFUNCTIONALTYPE failed, errno = %d (%s)", errno
, strerror(errno
));
3350 if (ifr
.ifr_functional_type
== IFRTYPE_FUNCTIONAL_INTCOPROC
)
3352 LogMsg("isCoprocessorInterface: %s marked as coprocessor interface", ifa_name
);
3359 #else // TARGET_OS_OSX
3360 #define isCoprocessorInterface(A, B) mDNSfalse
3361 #endif // TARGET_OS_OSX
3363 #if TARGET_OS_IPHONE
3365 // Function pointers for the routines we use in the MobileWiFi framework.
3366 static WiFiManagerClientRef (*WiFiManagerClientCreate_p
)(CFAllocatorRef allocator
, WiFiClientType type
) = mDNSNULL
;
3367 static CFArrayRef (*WiFiManagerClientCopyDevices_p
)(WiFiManagerClientRef manager
) = mDNSNULL
;
3368 static WiFiNetworkRef (*WiFiDeviceClientCopyCurrentNetwork_p
)(WiFiDeviceClientRef device
) = mDNSNULL
;
3369 static bool (*WiFiNetworkIsCarPlay_p
)(WiFiNetworkRef network
) = mDNSNULL
;
3371 mDNSlocal mDNSBool
MobileWiFiLibLoad(void)
3373 static mDNSBool isInitialized
= mDNSfalse
;
3374 static void *MobileWiFiLib_p
= mDNSNULL
;
3375 static const char path
[] = "/System/Library/PrivateFrameworks/MobileWiFi.framework/MobileWiFi";
3379 if (!MobileWiFiLib_p
)
3381 MobileWiFiLib_p
= dlopen(path
, RTLD_LAZY
| RTLD_LOCAL
);
3382 if (!MobileWiFiLib_p
)
3384 LogInfo("MobileWiFiLibLoad: dlopen() failed.");
3389 if (!WiFiManagerClientCreate_p
)
3391 WiFiManagerClientCreate_p
= dlsym(MobileWiFiLib_p
, "WiFiManagerClientCreate");
3392 if (!WiFiManagerClientCreate_p
)
3394 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCreate symbol failed.");
3399 if (!WiFiManagerClientCopyDevices_p
)
3401 WiFiManagerClientCopyDevices_p
= dlsym(MobileWiFiLib_p
, "WiFiManagerClientCopyDevices");
3402 if (!WiFiManagerClientCopyDevices_p
)
3404 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCopyDevices symbol failed.");
3409 if (!WiFiDeviceClientCopyCurrentNetwork_p
)
3411 WiFiDeviceClientCopyCurrentNetwork_p
= dlsym(MobileWiFiLib_p
, "WiFiDeviceClientCopyCurrentNetwork");
3412 if (!WiFiDeviceClientCopyCurrentNetwork_p
)
3414 LogInfo("MobileWiFiLibLoad: load of WiFiDeviceClientCopyCurrentNetwork symbol failed.");
3419 if (!WiFiNetworkIsCarPlay_p
)
3421 WiFiNetworkIsCarPlay_p
= dlsym(MobileWiFiLib_p
, "WiFiNetworkIsCarPlay");
3422 if (!WiFiNetworkIsCarPlay_p
)
3424 LogInfo("MobileWiFiLibLoad: load of WiFiNetworkIsCarPlay symbol failed.");
3429 isInitialized
= mDNStrue
;
3433 return isInitialized
;
3436 #define CARPLAY_DEBUG 0
3438 // Return true if the interface is associate to a CarPlay hosted SSID.
3439 // If we have associated with a CarPlay hosted SSID, then use the same
3440 // optimizations that are used when an interface has the IFEF_DIRECTLINK flag set.
3441 mDNSlocal mDNSBool
IsCarPlaySSID(char *ifa_name
)
3443 static WiFiManagerClientRef manager
= NULL
;
3445 WiFiDeviceClientRef device
;
3446 WiFiNetworkRef network
;
3447 mDNSBool rvalue
= mDNSfalse
;
3449 if (!MobileWiFiLibLoad())
3451 LogInfo("IsCarPlaySSID: MobileWiFiLibLoad() failed!");
3455 // Cache the WiFiManagerClientRef.
3456 if (manager
== NULL
)
3457 manager
= WiFiManagerClientCreate_p(NULL
, kWiFiClientTypeNormal
);
3459 if (manager
== NULL
)
3461 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3465 devices
= WiFiManagerClientCopyDevices_p(manager
);
3467 // If the first call fails, update the cached WiFiManagerClientRef pointer and try again.
3468 if (devices
== NULL
)
3470 LogInfo("IsCarPlaySSID: First call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name
);
3472 // Release the previously cached WiFiManagerClientRef which is apparently now stale.
3474 manager
= WiFiManagerClientCreate_p(NULL
, kWiFiClientTypeNormal
);
3475 if (manager
== NULL
)
3477 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3480 devices
= WiFiManagerClientCopyDevices_p(manager
);
3481 if (devices
== NULL
)
3483 LogInfo("IsCarPlaySSID: Second call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name
);
3488 device
= (WiFiDeviceClientRef
)CFArrayGetValueAtIndex(devices
, 0);
3489 network
= WiFiDeviceClientCopyCurrentNetwork_p(device
);
3490 if (network
!= NULL
)
3492 if (WiFiNetworkIsCarPlay_p(network
))
3494 LogInfo("IsCarPlaySSID: %s is CarPlay hosted", ifa_name
);
3499 LogInfo("IsCarPlaySSID: %s is NOT CarPlay hosted", ifa_name
);
3500 #endif // CARPLAY_DEBUG
3505 LogInfo("IsCarPlaySSID: WiFiDeviceClientCopyCurrentNetwork() returned NULL for %s", ifa_name
);
3512 #else // TARGET_OS_IPHONE
3514 mDNSlocal mDNSBool
IsCarPlaySSID(char *ifa_name
)
3516 (void)ifa_name
; // unused
3518 // OSX WifiManager currently does not implement WiFiNetworkIsCarPlay()
3522 #endif // TARGET_OS_IPHONE
3524 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
3525 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
3526 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
3527 // (e.g. sa_family not AF_INET or AF_INET6)
3528 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(struct ifaddrs
*ifa
, mDNSs32 utc
)
3530 mDNS
*const m
= &mDNSStorage
;
3531 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
3532 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
3533 u_int64_t eflags
= getExtendedFlags(ifa
->ifa_name
);
3536 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
3537 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
3539 NetworkInterfaceInfoOSX
**p
;
3540 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
3541 if (scope_id
== (*p
)->scope_id
&&
3542 mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) &&
3543 mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
3545 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p, ifname before %s, after %s", scope_id
, &bssid
, &ip
, *p
, (*p
)->ifinfo
.ifname
, ifa
->ifa_name
);
3546 // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
3547 // When interfaces are created with same MAC address, kernel resurrects the old interface.
3548 // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
3549 // we get the corresponding name for the interface index on which the packet was received and check against
3550 // the InterfaceList for a matching name. So, keep the name in sync
3551 strlcpy((*p
)->ifinfo
.ifname
, ifa
->ifa_name
, sizeof((*p
)->ifinfo
.ifname
));
3553 // Determine if multicast state has changed.
3554 const mDNSBool txrx
= MulticastInterface(*p
);
3555 if ((*p
)->ifinfo
.McastTxRx
!= txrx
)
3557 (*p
)->ifinfo
.McastTxRx
= txrx
;
3558 (*p
)->Exists
= MulticastStateChanged
; // State change; need to deregister and reregister this interface
3561 (*p
)->Exists
= mDNStrue
;
3563 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
3564 if ((*p
)->LastSeen
!= utc
) (*p
)->AppearanceTime
= utc
;
3566 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
3567 // we may need to start or stop or sleep proxy browse operation
3568 const mDNSBool NetWake
= NetWakeInterface(*p
);
3569 if ((*p
)->ifinfo
.NetWake
!= NetWake
)
3571 (*p
)->ifinfo
.NetWake
= NetWake
;
3572 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
3573 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
3574 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
3575 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
3576 if ((*p
)->Registered
)
3579 if (NetWake
) mDNS_ActivateNetWake_internal (m
, &(*p
)->ifinfo
);
3580 else mDNS_DeactivateNetWake_internal(m
, &(*p
)->ifinfo
);
3584 // Reset the flag if it has changed this time.
3585 (*p
)->ifinfo
.IgnoreIPv4LL
= ((eflags
& IFEF_ARPLL
) != 0) ? mDNSfalse
: mDNStrue
;
3590 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
3591 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
3592 if (!i
) return(mDNSNULL
);
3593 mDNSPlatformMemZero(i
, sizeof(NetworkInterfaceInfoOSX
));
3594 i
->ifinfo
.InterfaceID
= (mDNSInterfaceID
)(uintptr_t)scope_id
;
3596 i
->ifinfo
.mask
= mask
;
3597 strlcpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
3598 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
3599 // We can be configured to disable multicast advertisement, but we want to to support
3600 // local-only services, which need a loopback address record.
3601 i
->ifinfo
.Advertise
= m
->DivertMulticastAdvertisements
? ((ifa
->ifa_flags
& IFF_LOOPBACK
) ? mDNStrue
: mDNSfalse
) : m
->AdvertiseLocalAddresses
;
3602 i
->ifinfo
.Loopback
= ((ifa
->ifa_flags
& IFF_LOOPBACK
) != 0) ? mDNStrue
: mDNSfalse
;
3603 i
->ifinfo
.IgnoreIPv4LL
= ((eflags
& IFEF_ARPLL
) != 0) ? mDNSfalse
: mDNStrue
;
3605 // Setting DirectLink indicates we can do the optimization of skipping the probe phase
3606 // for the interface address records since they should be unique.
3607 // Unfortunately, the legacy p2p* interfaces do not set the IFEF_LOCALNET_PRIVATE
3608 // or IFEF_DIRECTLINK flags, so we have to match against the name.
3609 if ((eflags
& (IFEF_DIRECTLINK
| IFEF_AWDL
)) || (strncmp(i
->ifinfo
.ifname
, "p2p", 3) == 0))
3610 i
->ifinfo
.DirectLink
= mDNStrue
;
3612 i
->ifinfo
.DirectLink
= IsCarPlaySSID(ifa
->ifa_name
);
3614 if (i
->ifinfo
.DirectLink
)
3615 LogInfo("AddInterfaceToList: DirectLink set for %s", ifa
->ifa_name
);
3619 i
->Exists
= mDNStrue
;
3620 i
->Flashing
= mDNSfalse
;
3621 i
->Occulting
= mDNSfalse
;
3623 i
->D2DInterface
= ((eflags
& IFEF_LOCALNET_PRIVATE
) || (strncmp(i
->ifinfo
.ifname
, "p2p", 3) == 0)) ? mDNStrue
: mDNSfalse
;
3624 if (i
->D2DInterface
)
3625 LogInfo("AddInterfaceToList: D2DInterface set for %s", ifa
->ifa_name
);
3627 i
->isExpensive
= (eflags
& IFEF_EXPENSIVE
) ? mDNStrue
: mDNSfalse
;
3628 i
->isAWDL
= (eflags
& IFEF_AWDL
) ? mDNStrue
: mDNSfalse
;
3629 i
->isCLAT46
= (eflags
& IFEF_CLAT46
) ? mDNStrue
: mDNSfalse
;
3630 if (eflags
& IFEF_AWDL
)
3632 // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
3633 // limited AWDL resources so we don't set the kDNSQClass_UnicastResponse bit in
3634 // Bonjour requests over the AWDL interface.
3635 i
->ifinfo
.SupportsUnicastMDNSResponse
= mDNSfalse
;
3636 AWDLInterfaceID
= i
->ifinfo
.InterfaceID
;
3637 LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID
);
3641 i
->ifinfo
.SupportsUnicastMDNSResponse
= mDNStrue
;
3643 i
->AppearanceTime
= utc
; // Brand new interface; AppearanceTime is now
3645 i
->ifa_flags
= ifa
->ifa_flags
;
3646 i
->scope_id
= scope_id
;
3648 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
3652 i
->Registered
= mDNSNULL
;
3654 // MulticastInterface() depends on the "m" and "ifa_flags" values being initialized above.
3655 i
->ifinfo
.McastTxRx
= MulticastInterface(i
);
3656 // Do this AFTER i->BSSID has been set up
3657 i
->ifinfo
.NetWake
= (eflags
& IFEF_EXPENSIVE
)? mDNSfalse
: NetWakeInterface(i
);
3658 GetMAC(&i
->ifinfo
.MAC
, scope_id
);
3659 if (i
->ifinfo
.NetWake
&& !i
->ifinfo
.MAC
.l
[0])
3660 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i
->ifinfo
.MAC
, scope_id
, i
->ifinfo
.ifname
, &ip
);
3666 #if APPLE_OSX_mDNSResponder
3668 #if COMPILER_LIKES_PRAGMA_MARK
3670 #pragma mark - AutoTunnel
3673 #define kRacoonPort 4500
3675 static DomainAuthInfo
* AnonymousRacoonConfig
= mDNSNULL
;
3677 #ifndef NO_SECURITYFRAMEWORK
3679 static CFMutableDictionaryRef domainStatusDict
= NULL
;
3681 mDNSlocal mStatus
CheckQuestionForStatus(const DNSQuestion
*const q
)
3685 if (q
->servAddr
.type
== mDNSAddrType_IPv4
&& mDNSIPv4AddressIsOnes(q
->servAddr
.ip
.v4
))
3686 return mStatus_NoSuchRecord
;
3687 else if (q
->state
== LLQ_Poll
)
3688 return mStatus_PollingMode
;
3689 else if (q
->state
!= LLQ_Established
&& !q
->DuplicateOf
)
3690 return mStatus_TransientErr
;
3693 return mStatus_NoError
;
3696 mDNSlocal mStatus
UpdateLLQStatus(char *buffer
, int bufsz
, const DomainAuthInfo
*const info
)
3698 mStatus status
= mStatus_NoError
;
3699 DNSQuestion
* q
, *worst_q
= mDNSNULL
;
3700 for (q
= mDNSStorage
.Questions
; q
; q
=q
->next
)
3701 if (q
->AuthInfo
== info
)
3703 mStatus newStatus
= CheckQuestionForStatus(q
);
3704 if (newStatus
== mStatus_NoSuchRecord
) { status
= newStatus
; worst_q
= q
; break; }
3705 else if (newStatus
== mStatus_PollingMode
) { status
= newStatus
; worst_q
= q
; }
3706 else if (newStatus
== mStatus_TransientErr
&& status
== mStatus_NoError
) { status
= newStatus
; worst_q
= q
; }
3709 if (status
== mStatus_NoError
) mDNS_snprintf(buffer
, bufsz
, "Success");
3710 else if (status
== mStatus_NoSuchRecord
) mDNS_snprintf(buffer
, bufsz
, "GetZoneData %s: %##s", worst_q
->nta
? "not yet complete" : "failed", worst_q
->qname
.c
);
3711 else if (status
== mStatus_PollingMode
) mDNS_snprintf(buffer
, bufsz
, "Query polling %##s", worst_q
->qname
.c
);
3712 else if (status
== mStatus_TransientErr
) mDNS_snprintf(buffer
, bufsz
, "Query not yet established %##s", worst_q
->qname
.c
);
3716 mDNSlocal mStatus
UpdateRRStatus(char *buffer
, int bufsz
, const DomainAuthInfo
*const info
)
3720 if (info
->deltime
) return mStatus_NoError
;
3721 for (r
= mDNSStorage
.ResourceRecords
; r
; r
= r
->next
)
3723 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
3724 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
3725 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
3726 // has already checked
3727 const domainname
*n
= r
->resrec
.name
;
3730 DomainAuthInfo
*ptr
;
3731 for (ptr
= mDNSStorage
.AuthInfoList
; ptr
; ptr
= ptr
->next
)
3732 if (SameDomainName(&ptr
->domain
, n
))
3734 if (ptr
== info
&& (r
->updateError
== mStatus_BadSig
|| r
->updateError
== mStatus_BadKey
|| r
->updateError
== mStatus_BadTime
))
3736 mDNS_snprintf(buffer
, bufsz
, "Resource record update failed for %##s", r
->resrec
.name
);
3737 return r
->updateError
;
3740 n
= (const domainname
*)(n
->c
+ 1 + n
->c
[0]);
3743 return mStatus_NoError
;
3746 #endif // ndef NO_SECURITYFRAMEWORK
3748 // MUST be called with lock held
3749 mDNSlocal
void UpdateAutoTunnelDomainStatus(const DomainAuthInfo
*const info
)
3751 #ifdef NO_SECURITYFRAMEWORK
3754 // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
3755 // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
3756 mDNS
*const m
= &mDNSStorage
;
3757 const NATTraversalInfo
*const llq
= m
->LLQNAT
.clientCallback
? &m
->LLQNAT
: mDNSNULL
;
3758 const NATTraversalInfo
*const tun
= m
->AutoTunnelNAT
.clientContext
? &m
->AutoTunnelNAT
: mDNSNULL
;
3760 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3761 CFStringRef domain
= NULL
;
3762 CFStringRef tmp
= NULL
;
3763 CFNumberRef num
= NULL
;
3764 mStatus status
= mStatus_NoError
;
3765 mStatus llqStatus
= mStatus_NoError
;
3766 char llqBuffer
[1024];
3770 if (!domainStatusDict
)
3772 domainStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3773 if (!domainStatusDict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
3776 if (!dict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
3778 mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", info
->domain
.c
);
3779 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3780 if (!domain
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3784 if (CFDictionaryContainsKey(domainStatusDict
, domain
))
3786 CFDictionaryRemoveValue(domainStatusDict
, domain
);
3787 if (!m
->ShutdownTime
) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, mDNSNULL
, domainStatusDict
);
3795 mDNS_snprintf(buffer
, sizeof(buffer
), "%#a", &m
->Router
);
3796 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3798 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
3801 CFDictionarySetValue(dict
, CFSTR("RouterAddress"), tmp
);
3807 mDNSu32 port
= mDNSVal16(llq
->ExternalPort
);
3809 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
3811 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
3814 CFDictionarySetValue(dict
, CFSTR("LLQExternalPort"), num
);
3820 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &llq
->Result
);
3822 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
3825 CFDictionarySetValue(dict
, CFSTR("LLQNPMStatus"), num
);
3833 mDNSu32 port
= mDNSVal16(tun
->ExternalPort
);
3835 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
3837 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
3840 CFDictionarySetValue(dict
, CFSTR("AutoTunnelExternalPort"), num
);
3844 mDNS_snprintf(buffer
, sizeof(buffer
), "%.4a", &tun
->ExternalAddress
);
3845 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3847 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
3850 CFDictionarySetValue(dict
, CFSTR("ExternalAddress"), tmp
);
3856 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tun
->Result
);
3858 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
3861 CFDictionarySetValue(dict
, CFSTR("AutoTunnelNPMStatus"), num
);
3868 mDNSu32 code
= m
->LastNATMapResultCode
;
3870 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &code
);
3872 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
3875 CFDictionarySetValue(dict
, CFSTR("LastNATMapResultCode"), num
);
3880 mDNS_snprintf(buffer
, sizeof(buffer
), "Success");
3881 llqStatus
= UpdateLLQStatus(llqBuffer
, sizeof(llqBuffer
), info
);
3882 status
= UpdateRRStatus(buffer
, sizeof(buffer
), info
);
3884 // If we have a bad signature error updating a RR, it overrides any error as it needs to be
3885 // reported so that it can be fixed automatically (or the user needs to be notified)
3886 if (status
!= mStatus_NoError
)
3888 LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status
, buffer
);
3890 else if (m
->Router
.type
== mDNSAddrType_None
)
3892 status
= mStatus_NoRouter
;
3893 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - none");
3895 else if (m
->Router
.type
== mDNSAddrType_IPv4
&& mDNSIPv4AddressIsZero(m
->Router
.ip
.v4
))
3897 status
= mStatus_NoRouter
;
3898 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - v4 zero");
3900 else if (mDNSIPv6AddressIsZero(info
->AutoTunnelInnerAddress
))
3902 status
= mStatus_ServiceNotRunning
;
3903 mDNS_snprintf(buffer
, sizeof(buffer
), "No inner address");
3905 else if (!llq
&& !tun
)
3907 status
= mStatus_NotInitializedErr
;
3908 mDNS_snprintf(buffer
, sizeof(buffer
), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
3910 else if (llqStatus
== mStatus_NoSuchRecord
)
3913 mDNS_snprintf(buffer
, sizeof(buffer
), "%s", llqBuffer
);
3915 else if ((llq
&& llq
->Result
== mStatus_DoubleNAT
) || (tun
&& tun
->Result
== mStatus_DoubleNAT
))
3917 status
= mStatus_DoubleNAT
;
3918 mDNS_snprintf(buffer
, sizeof(buffer
), "Double NAT: Router is reporting a private address");
3920 else if ((llq
&& llq
->Result
== mStatus_NATPortMappingDisabled
) ||
3921 (tun
&& tun
->Result
== mStatus_NATPortMappingDisabled
) ||
3922 (m
->LastNATMapResultCode
== NATErr_Refused
&& ((llq
&& !llq
->Result
&& mDNSIPPortIsZero(llq
->ExternalPort
)) || (tun
&& !tun
->Result
&& mDNSIPPortIsZero(tun
->ExternalPort
)))))
3924 status
= mStatus_NATPortMappingDisabled
;
3925 mDNS_snprintf(buffer
, sizeof(buffer
), "PCP/NAT-PMP is disabled on the router");
3927 else if ((llq
&& llq
->Result
) || (tun
&& tun
->Result
))
3929 status
= mStatus_NATTraversal
;
3930 mDNS_snprintf(buffer
, sizeof(buffer
), "Error obtaining NAT port mapping from router");
3932 else if ((llq
&& mDNSIPPortIsZero(llq
->ExternalPort
)) || (tun
&& mDNSIPPortIsZero(tun
->ExternalPort
)))
3934 status
= mStatus_NATTraversal
;
3935 mDNS_snprintf(buffer
, sizeof(buffer
), "Unable to obtain NAT port mapping from router");
3940 mDNS_snprintf(buffer
, sizeof(buffer
), "%s", llqBuffer
);
3941 LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status
, buffer
);
3944 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
);
3946 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
3949 CFDictionarySetValue(dict
, CFSTR("StatusCode"), num
);
3953 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3955 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
3958 CFDictionarySetValue(dict
, CFSTR("StatusMessage"), tmp
);
3962 if (!CFDictionaryContainsKey(domainStatusDict
, domain
) ||
3963 !CFEqual(dict
, (CFMutableDictionaryRef
)CFDictionaryGetValue(domainStatusDict
, domain
)))
3965 CFDictionarySetValue(domainStatusDict
, domain
, dict
);
3966 if (!m
->ShutdownTime
)
3968 LogInfo("UpdateAutoTunnelDomainStatus: %s status %d", status
? "failure" : "success", status
);
3969 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, mDNSNULL
, domainStatusDict
);
3976 debugf("UpdateAutoTunnelDomainStatus: %s", buffer
);
3977 #endif // def NO_SECURITYFRAMEWORK
3980 // MUST be called with lock held
3981 mDNSexport
void UpdateAutoTunnelDomainStatuses(const mDNS
*const m
)
3983 #ifdef NO_SECURITYFRAMEWORK
3987 DomainAuthInfo
* info
;
3988 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
3989 if (info
->AutoTunnel
&& !info
->deltime
)
3990 UpdateAutoTunnelDomainStatus(info
);
3991 #endif // def NO_SECURITYFRAMEWORK
3994 mDNSlocal
void UpdateAnonymousRacoonConfig(mDNS
*m
) // Determine whether we need racoon to accept incoming connections
3996 DomainAuthInfo
*info
;
3998 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
3999 if (info
->AutoTunnel
&& !info
->deltime
&& (!mDNSIPPortIsZero(m
->AutoTunnelNAT
.ExternalPort
) || !mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
)))
4002 if (info
!= AnonymousRacoonConfig
)
4004 AnonymousRacoonConfig
= info
;
4005 LogInfo("UpdateAnonymousRacoonConfig need not be done in mDNSResponder");
4009 mDNSlocal
void AutoTunnelRecordCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
4011 // Caller must hold the lock
4012 mDNSlocal mDNSBool
DeregisterAutoTunnelRecord(mDNS
*m
, DomainAuthInfo
*info
, AuthRecord
* record
)
4016 LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info
->domain
.c
, record
->namestorage
.c
);
4018 if (record
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
4020 mStatus err
= mDNS_Deregister_internal(m
, record
, mDNS_Dereg_normal
);
4023 record
->resrec
.RecordType
= kDNSRecordTypeUnregistered
;
4024 LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err
, info
->domain
.c
, record
->namestorage
.c
);
4027 else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
4029 else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record
->resrec
.RecordType
);
4034 // Caller must hold the lock
4035 mDNSlocal
void DeregisterAutoTunnelHostRecord(mDNS
*m
, DomainAuthInfo
*info
)
4037 if (!DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnelHostRecord
))
4039 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
4040 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4044 // Caller must hold the lock
4045 mDNSlocal
void UpdateAutoTunnelHostRecord(mDNS
*m
, DomainAuthInfo
*info
)
4048 mDNSBool NATProblem
= mDNSIPPortIsZero(m
->AutoTunnelNAT
.ExternalPort
) || m
->AutoTunnelNAT
.Result
;
4052 if (!info
->AutoTunnelServiceStarted
|| info
->deltime
|| m
->ShutdownTime
|| mDNSIPv6AddressIsZero(info
->AutoTunnelInnerAddress
) || (m
->SleepState
!= SleepState_Awake
&& NATProblem
))
4054 LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
4055 info
->domain
.c
, info
->AutoTunnelServiceStarted
, info
->deltime
, &info
->AutoTunnelInnerAddress
, m
->SleepState
);
4056 DeregisterAutoTunnelHostRecord(m
, info
);
4058 else if (info
->AutoTunnelHostRecord
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4060 mDNS_SetupResourceRecord(&info
->AutoTunnelHostRecord
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
,
4061 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
4062 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
4063 AppendDomainLabel(&info
->AutoTunnelHostRecord
.namestorage
, &m
->hostlabel
);
4064 AppendDomainName (&info
->AutoTunnelHostRecord
.namestorage
, &info
->domain
);
4065 info
->AutoTunnelHostRecord
.resrec
.rdata
->u
.ipv6
= info
->AutoTunnelInnerAddress
;
4066 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4068 err
= mDNS_Register_internal(m
, &info
->AutoTunnelHostRecord
);
4069 if (err
) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
4072 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
4073 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4074 LogInfo("UpdateAutoTunnelHostRecord registering %##s", info
->AutoTunnelHostRecord
.namestorage
.c
);
4077 else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info
->AutoTunnelHostRecord
.resrec
.RecordType
);
4080 // Caller must hold the lock
4081 mDNSlocal
void DeregisterAutoTunnelServiceRecords(mDNS
*m
, DomainAuthInfo
*info
)
4083 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info
->domain
.c
);
4085 DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnelTarget
);
4086 DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnelService
);
4087 UpdateAutoTunnelHostRecord(m
, info
);
4090 // Caller must hold the lock
4091 mDNSlocal
void UpdateAutoTunnelServiceRecords(mDNS
*m
, DomainAuthInfo
*info
)
4095 if (!info
->AutoTunnelServiceStarted
|| info
->deltime
|| m
->ShutdownTime
|| mDNSIPPortIsZero(m
->AutoTunnelNAT
.ExternalPort
) || m
->AutoTunnelNAT
.Result
)
4097 LogInfo("UpdateAutoTunnelServiceRecords: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) ExtPort(%d) NATResult(%d)", info
->domain
.c
, info
->AutoTunnelServiceStarted
, info
->deltime
, mDNSVal16(m
->AutoTunnelNAT
.ExternalPort
), m
->AutoTunnelNAT
.Result
);
4098 DeregisterAutoTunnelServiceRecords(m
, info
);
4102 if (info
->AutoTunnelTarget
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4104 // 1. Set up our address record for the external tunnel address
4105 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
4106 mDNS_SetupResourceRecord(&info
->AutoTunnelTarget
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, kHostNameTTL
,
4107 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
4108 AssignDomainName (&info
->AutoTunnelTarget
.namestorage
, (const domainname
*) "\x0B" "_autotunnel");
4109 AppendDomainLabel(&info
->AutoTunnelTarget
.namestorage
, &m
->hostlabel
);
4110 AppendDomainName (&info
->AutoTunnelTarget
.namestorage
, &info
->domain
);
4111 info
->AutoTunnelTarget
.resrec
.rdata
->u
.ipv4
= m
->AutoTunnelNAT
.ExternalAddress
;
4112 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4114 mStatus err
= mDNS_Register_internal(m
, &info
->AutoTunnelTarget
);
4115 if (err
) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err
, info
->AutoTunnelTarget
.namestorage
.c
);
4116 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info
->AutoTunnelTarget
.namestorage
.c
);
4118 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info
->AutoTunnelTarget
.resrec
.RecordType
);
4120 if (info
->AutoTunnelService
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4122 // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
4123 mDNS_SetupResourceRecord(&info
->AutoTunnelService
, mDNSNULL
, mDNSInterface_Any
, kDNSType_SRV
, kHostNameTTL
,
4124 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
4125 AssignDomainName (&info
->AutoTunnelService
.namestorage
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
4126 AppendDomainLabel(&info
->AutoTunnelService
.namestorage
, &m
->hostlabel
);
4127 AppendDomainName (&info
->AutoTunnelService
.namestorage
, &info
->domain
);
4128 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.priority
= 0;
4129 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.weight
= 0;
4130 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.port
= m
->AutoTunnelNAT
.ExternalPort
;
4131 AssignDomainName(&info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.target
, &info
->AutoTunnelTarget
.namestorage
);
4132 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4134 mStatus err
= mDNS_Register_internal(m
, &info
->AutoTunnelService
);
4135 if (err
) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
4136 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info
->AutoTunnelService
.namestorage
.c
);
4138 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info
->AutoTunnelService
.resrec
.RecordType
);
4140 UpdateAutoTunnelHostRecord(m
, info
);
4142 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
4143 info
->AutoTunnelTarget
.namestorage
.c
, &m
->AdvertisedV4
.ip
.v4
, mDNSVal16(m
->AutoTunnelNAT
.IntPort
),
4144 info
->AutoTunnelHostRecord
.namestorage
.c
, &info
->AutoTunnelInnerAddress
);
4149 // Caller must hold the lock
4150 mDNSlocal
void DeregisterAutoTunnelDeviceInfoRecord(mDNS
*m
, DomainAuthInfo
*info
)
4152 DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnelDeviceInfo
);
4155 // Caller must hold the lock
4156 mDNSlocal
void UpdateAutoTunnelDeviceInfoRecord(mDNS
*m
, DomainAuthInfo
*info
)
4160 if (!info
->AutoTunnelServiceStarted
|| info
->deltime
|| m
->ShutdownTime
)
4161 DeregisterAutoTunnelDeviceInfoRecord(m
, info
);
4162 else if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4164 mDNS_SetupResourceRecord(&info
->AutoTunnelDeviceInfo
, mDNSNULL
, mDNSInterface_Any
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
4165 ConstructServiceName(&info
->AutoTunnelDeviceInfo
.namestorage
, &m
->nicelabel
, &DeviceInfoName
, &info
->domain
);
4167 info
->AutoTunnelDeviceInfo
.resrec
.rdlength
= initializeDeviceInfoTXT(m
, info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
);
4168 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4170 mStatus err
= mDNS_Register_internal(m
, &info
->AutoTunnelDeviceInfo
);
4171 if (err
) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
4172 else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info
->AutoTunnelDeviceInfo
.namestorage
.c
);
4175 LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info
->AutoTunnelDeviceInfo
.resrec
.RecordType
);
4178 // Caller must hold the lock
4179 mDNSlocal
void DeregisterAutoTunnel6Record(mDNS
*m
, DomainAuthInfo
*info
)
4181 LogInfo("DeregisterAutoTunnel6Record %##s", info
->domain
.c
);
4183 DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnel6Record
);
4184 UpdateAutoTunnelHostRecord(m
, info
);
4185 UpdateAutoTunnelDomainStatus(info
);
4188 // Caller must hold the lock
4189 mDNSlocal
void UpdateAutoTunnel6Record(mDNS
*m
, DomainAuthInfo
*info
)
4193 if (!info
->AutoTunnelServiceStarted
|| info
->deltime
|| m
->ShutdownTime
|| mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
) || m
->SleepState
!= SleepState_Awake
)
4194 DeregisterAutoTunnel6Record(m
, info
);
4195 else if (info
->AutoTunnel6Record
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4197 mDNS_SetupResourceRecord(&info
->AutoTunnel6Record
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
,
4198 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
4199 AssignDomainName (&info
->AutoTunnel6Record
.namestorage
, (const domainname
*) "\x0C" "_autotunnel6");
4200 AppendDomainLabel(&info
->AutoTunnel6Record
.namestorage
, &m
->hostlabel
);
4201 AppendDomainName (&info
->AutoTunnel6Record
.namestorage
, &info
->domain
);
4202 info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
= m
->AutoTunnelRelayAddr
;
4203 info
->AutoTunnel6Record
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4205 mStatus err
= mDNS_Register_internal(m
, &info
->AutoTunnel6Record
);
4206 if (err
) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err
, info
->AutoTunnel6Record
.namestorage
.c
);
4207 else LogInfo("UpdateAutoTunnel6Record registering %##s", info
->AutoTunnel6Record
.namestorage
.c
);
4209 UpdateAutoTunnelHostRecord(m
, info
);
4211 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
4212 info
->AutoTunnel6Record
.namestorage
.c
, &m
->AutoTunnelRelayAddr
,
4213 info
->AutoTunnelHostRecord
.namestorage
.c
, &info
->AutoTunnelInnerAddress
);
4216 else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info
->AutoTunnel6Record
.resrec
.RecordType
);
4219 mDNSlocal
void AutoTunnelRecordCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
4221 DomainAuthInfo
*info
= (DomainAuthInfo
*)rr
->RecordContext
;
4222 if (result
== mStatus_MemFree
)
4224 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m
, rr
));
4228 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
4229 if (rr
== &info
->AutoTunnelHostRecord
)
4231 rr
->namestorage
.c
[0] = 0;
4232 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4233 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m
->NextSRVUpdate
- m
->timenow
, m
->timenow
);
4235 if (m
->ShutdownTime
)
4237 LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
4241 if (rr
== &info
->AutoTunnelHostRecord
)
4243 LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
4244 UpdateAutoTunnelHostRecord(m
,info
);
4246 else if (rr
== &info
->AutoTunnelDeviceInfo
)
4248 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
4249 UpdateAutoTunnelDeviceInfoRecord(m
,info
);
4251 else if (rr
== &info
->AutoTunnelService
|| rr
== &info
->AutoTunnelTarget
)
4253 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
4254 UpdateAutoTunnelServiceRecords(m
,info
);
4256 else if (rr
== &info
->AutoTunnel6Record
)
4258 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
4259 UpdateAutoTunnel6Record(m
,info
);
4266 mDNSlocal
void AutoTunnelNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
4268 DomainAuthInfo
*info
;
4270 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
4271 n
->Result
, &n
->ExternalAddress
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->ExternalPort
));
4275 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4276 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m
->NextSRVUpdate
- m
->timenow
, m
->timenow
);
4278 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
4279 if (info
->AutoTunnel
)
4280 UpdateAutoTunnelServiceRecords(m
, info
);
4282 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
4284 UpdateAutoTunnelDomainStatuses(m
);
4289 mDNSlocal
void AutoTunnelHostNameChanged(mDNS
*m
, DomainAuthInfo
*info
)
4291 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m
->hostlabel
.c
, info
->domain
.c
);
4294 // We forcibly deregister the records that are based on the hostname.
4295 // When deregistration of each completes, the MemFree callback will make the
4296 // appropriate Update* call to use the new name to reregister.
4297 DeregisterAutoTunnelHostRecord(m
, info
);
4298 DeregisterAutoTunnelDeviceInfoRecord(m
, info
);
4299 DeregisterAutoTunnelServiceRecords(m
, info
);
4300 DeregisterAutoTunnel6Record(m
, info
);
4301 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4305 // Must be called with the lock held
4306 mDNSexport
void StartServerTunnel(DomainAuthInfo
*const info
)
4308 mDNS
*const m
= &mDNSStorage
;
4309 if (info
->deltime
) return;
4311 if (info
->AutoTunnelServiceStarted
)
4313 // On wake from sleep, this function will be called when determining SRV targets,
4314 // and needs to re-register the host record for the target to be set correctly
4315 UpdateAutoTunnelHostRecord(m
, info
);
4319 info
->AutoTunnelServiceStarted
= mDNStrue
;
4321 // Now that we have a service in this domain, we need to try to register the
4322 // AutoTunnel records, because the relay connection & NAT-T may have already been
4323 // started for another domain. If the relay connection is not up or the NAT-T has not
4324 // yet succeeded, the Update* functions are smart enough to not register the records.
4325 // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
4326 // decide whether to register the AutoTunnel records in the calls below.
4327 UpdateAutoTunnelServiceRecords(m
, info
);
4328 UpdateAutoTunnel6Record(m
, info
);
4329 UpdateAutoTunnelDeviceInfoRecord(m
, info
);
4330 UpdateAutoTunnelHostRecord(m
, info
);
4332 // If the global AutoTunnel NAT-T is not yet started, start it.
4333 if (!m
->AutoTunnelNAT
.clientContext
)
4335 m
->AutoTunnelNAT
.clientCallback
= AutoTunnelNATCallback
;
4336 m
->AutoTunnelNAT
.clientContext
= (void*)1; // Means AutoTunnelNAT Traversal is active;
4337 m
->AutoTunnelNAT
.Protocol
= NATOp_MapUDP
;
4338 m
->AutoTunnelNAT
.IntPort
= IPSECPort
;
4339 m
->AutoTunnelNAT
.RequestedPort
= IPSECPort
;
4340 m
->AutoTunnelNAT
.NATLease
= 0;
4341 mStatus err
= mDNS_StartNATOperation_internal(m
, &m
->AutoTunnelNAT
);
4342 if (err
) LogMsg("StartServerTunnel: error %d starting NAT mapping", err
);
4346 mDNSlocal mStatus
AutoTunnelSetKeys(ClientTunnel
*tun
, mDNSBool AddNew
)
4348 mDNSv6Addr loc_outer6
;
4349 mDNSv6Addr rmt_outer6
;
4351 // When we are tunneling over IPv6 Relay address, the port number is zero
4352 if (mDNSIPPortIsZero(tun
->rmt_outer_port
))
4354 loc_outer6
= tun
->loc_outer6
;
4355 rmt_outer6
= tun
->rmt_outer6
;
4359 loc_outer6
= zerov6Addr
;
4360 loc_outer6
.b
[0] = tun
->loc_outer
.b
[0];
4361 loc_outer6
.b
[1] = tun
->loc_outer
.b
[1];
4362 loc_outer6
.b
[2] = tun
->loc_outer
.b
[2];
4363 loc_outer6
.b
[3] = tun
->loc_outer
.b
[3];
4365 rmt_outer6
= zerov6Addr
;
4366 rmt_outer6
.b
[0] = tun
->rmt_outer
.b
[0];
4367 rmt_outer6
.b
[1] = tun
->rmt_outer
.b
[1];
4368 rmt_outer6
.b
[2] = tun
->rmt_outer
.b
[2];
4369 rmt_outer6
.b
[3] = tun
->rmt_outer
.b
[3];
4372 return(mDNSAutoTunnelSetKeys(AddNew
? kmDNSAutoTunnelSetKeysReplace
: kmDNSAutoTunnelSetKeysDelete
, tun
->loc_inner
.b
, loc_outer6
.b
, kRacoonPort
, tun
->rmt_inner
.b
, rmt_outer6
.b
, mDNSVal16(tun
->rmt_outer_port
), btmmprefix
, SkipLeadingLabels(&tun
->dstname
, 1)));
4375 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
4376 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
4378 mDNSlocal
void ReissueBlockedQuestionWithType(domainname
*d
, mDNSBool success
, mDNSu16 qtype
)
4380 mDNS
*const m
= &mDNSStorage
;
4381 DNSQuestion
*q
= m
->Questions
;
4384 if (q
->NoAnswer
== NoAnswer_Suspended
&& q
->qtype
== qtype
&& q
->AuthInfo
&& q
->AuthInfo
->AutoTunnel
&& SameDomainName(&q
->qname
, d
))
4386 LogInfo("Restart %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4387 mDNSQuestionCallback
*tmp
= q
->QuestionCallback
;
4388 q
->QuestionCallback
= AutoTunnelCallback
; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
4389 mDNS_StopQuery(m
, q
);
4390 mDNS_StartQuery(m
, q
);
4391 q
->QuestionCallback
= tmp
; // Restore QuestionCallback back to the real value
4392 if (!success
) q
->NoAnswer
= NoAnswer_Fail
;
4393 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
4394 // In general we have to assume that the question list might have changed in arbitrary ways.
4395 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
4396 // already in use. The safest solution is just to go back to the start of the list and start again.
4397 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
4398 // just one suspended question, so it's really a 2n algorithm.
4406 mDNSlocal
void ReissueBlockedQuestions(domainname
*d
, mDNSBool success
)
4408 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
4409 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
4410 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
4411 // even if the name does have a valid AAAA record, we don't want clients trying to connect to it without a properly encrypted tunnel.
4412 // 3. For A queries we never fabricate failures -- if a BTTM service is really using raw IPv4, then it doesn't need the IPv6 tunnel.
4413 ReissueBlockedQuestionWithType(d
, success
, kDNSType_AAAA
);
4414 ReissueBlockedQuestionWithType(d
, mDNStrue
, kDNSType_A
);
4417 mDNSlocal
void UnlinkAndReissueBlockedQuestions(ClientTunnel
*tun
, mDNSBool success
)
4419 mDNS
*const m
= &mDNSStorage
;
4420 ClientTunnel
**p
= &m
->TunnelClients
;
4421 while (*p
!= tun
&& *p
) p
= &(*p
)->next
;
4422 if (*p
) *p
= tun
->next
;
4423 ReissueBlockedQuestions(&tun
->dstname
, success
);
4424 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun
);
4425 freeL("ClientTunnel", tun
);
4428 mDNSlocal mDNSBool
TunnelClientDeleteMatching(ClientTunnel
*tun
, mDNSBool v6Tunnel
)
4430 mDNS
*const m
= &mDNSStorage
;
4432 mDNSBool needSetKeys
= mDNStrue
;
4437 // Is this a tunnel to the same host that we are trying to setup now?
4438 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
4441 ClientTunnel
*old
= *p
;
4444 if (!mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue; }
4445 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4446 if (old
->q
.ThisQInterval
>= 0)
4448 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4449 mDNS_StopQuery(m
, &old
->q
);
4451 else if (!mDNSSameIPv6Address((*p
)->rmt_inner
, tun
->rmt_inner
) ||
4452 !mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
4453 !mDNSSameIPv6Address(old
->loc_outer6
, tun
->loc_outer6
) ||
4454 !mDNSSameIPv6Address(old
->rmt_outer6
, tun
->rmt_outer6
))
4456 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4457 // the other parameters of the tunnel are different
4458 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4459 AutoTunnelSetKeys(old
, mDNSfalse
);
4463 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4464 // as "tun" and "old" are identical
4465 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
,
4467 needSetKeys
= mDNSfalse
;
4472 if (mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue; }
4473 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4474 if (old
->q
.ThisQInterval
>= 0)
4476 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4477 mDNS_StopQuery(m
, &old
->q
);
4479 else if (!mDNSSameIPv6Address((*p
)->rmt_inner
, tun
->rmt_inner
) ||
4480 !mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
4481 !mDNSSameIPv4Address(old
->loc_outer
, tun
->loc_outer
) ||
4482 !mDNSSameIPv4Address(old
->rmt_outer
, tun
->rmt_outer
) ||
4483 !mDNSSameIPPort(old
->rmt_outer_port
, tun
->rmt_outer_port
))
4485 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4486 // the other parameters of the tunnel are different
4487 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4488 AutoTunnelSetKeys(old
, mDNSfalse
);
4492 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4493 // as "tun" and "old" are identical
4494 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
,
4496 needSetKeys
= mDNSfalse
;
4501 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old
);
4502 freeL("ClientTunnel", old
);
4508 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
4509 // tunnel will be deleted
4510 mDNSlocal
void TunnelClientDeleteAny(ClientTunnel
*tun
, mDNSBool v6Tunnel
)
4517 // If there is more than one client tunnel to the same host, delete all of them.
4518 // We do this by just checking against the EUI64 rather than the full address
4519 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
4522 ClientTunnel
*old
= *p
;
4525 if (!mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue;}
4526 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4530 if (mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue;}
4531 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4533 if (old
->q
.ThisQInterval
>= 0)
4535 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4536 mDNS_StopQuery(&mDNSStorage
, &old
->q
);
4540 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4541 AutoTunnelSetKeys(old
, mDNSfalse
);
4544 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old
);
4545 freeL("ClientTunnel", old
);
4550 mDNSlocal
void TunnelClientFinish(DNSQuestion
*question
, const ResourceRecord
*const answer
)
4552 mDNS
*const m
= &mDNSStorage
;
4553 mDNSBool needSetKeys
= mDNStrue
;
4554 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
4555 mDNSBool v6Tunnel
= mDNSfalse
;
4556 DomainAuthInfo
*info
;
4558 // If the port is zero, then we have a relay address of the peer
4559 if (mDNSIPPortIsZero(tun
->rmt_outer_port
))
4560 v6Tunnel
= mDNStrue
;
4564 LogInfo("TunnelClientFinish: Relay address %.16a", &answer
->rdata
->u
.ipv6
);
4565 tun
->rmt_outer6
= answer
->rdata
->u
.ipv6
;
4566 tun
->loc_outer6
= m
->AutoTunnelRelayAddr
;
4570 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer
->rdata
->u
.ipv4
);
4571 tun
->rmt_outer
= answer
->rdata
->u
.ipv4
;
4572 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
4573 tmpDst
.ip
.v4
= tun
->rmt_outer
;
4574 mDNSAddr tmpSrc
= zeroAddr
;
4575 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
4576 if (tmpSrc
.type
== mDNSAddrType_IPv4
) tun
->loc_outer
= tmpSrc
.ip
.v4
;
4577 else tun
->loc_outer
= m
->AdvertisedV4
.ip
.v4
;
4580 question
->ThisQInterval
= -1; // So we know this tunnel setup has completed
4582 info
= GetAuthInfoForName(m
, &tun
->dstname
);
4585 LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun
->dstname
.c
);
4586 ReissueBlockedQuestions(&tun
->dstname
, mDNSfalse
);
4590 tun
->loc_inner
= info
->AutoTunnelInnerAddress
;
4592 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
4593 // look for existing tunnels to see whether they have the same information for our peer.
4594 // If not, delete them and need to create a new tunnel. If they are same, just use the
4595 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
4596 TunnelClientDeleteAny(tun
, !v6Tunnel
);
4597 needSetKeys
= TunnelClientDeleteMatching(tun
, v6Tunnel
);
4599 if (needSetKeys
) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel
? "IPv6" : "IPv4"), tun
->dstname
.c
, &tun
->rmt_inner
);
4600 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel
? "IPv6" : "IPv4"), tun
->dstname
.c
, &tun
->rmt_inner
);
4602 mStatus result
= needSetKeys
? AutoTunnelSetKeys(tun
, mDNStrue
) : mStatus_NoError
;
4603 LogInfo("TunnelClientFinish: Tunnel setup result %d", result
);
4604 // Kick off any questions that were held pending this tunnel setup
4605 ReissueBlockedQuestions(&tun
->dstname
, (result
== mStatus_NoError
) ? mDNStrue
: mDNSfalse
);
4608 mDNSexport
void AutoTunnelCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
4610 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
4611 DomainAuthInfo
*info
;
4613 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun
, AddRecord
, answer
->rdlength
, question
->qtype
);
4615 if (!AddRecord
) return;
4616 mDNS_StopQuery(m
, question
);
4618 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
4619 // The code below will look for _autotunnel._udp SRV record followed by A record
4620 if (tun
->tc_state
!= TC_STATE_AAAA_PEER_RELAY
&& !answer
->rdlength
)
4622 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
4623 UnlinkAndReissueBlockedQuestions(tun
, mDNSfalse
);
4627 switch (tun
->tc_state
)
4629 case TC_STATE_AAAA_PEER
:
4630 if (question
->qtype
!= kDNSType_AAAA
)
4632 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question
->qtype
);
4634 info
= GetAuthInfoForName(m
, &tun
->dstname
);
4637 LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun
->dstname
.c
);
4638 UnlinkAndReissueBlockedQuestions(tun
, mDNStrue
);
4641 if (mDNSSameIPv6Address(answer
->rdata
->u
.ipv6
, info
->AutoTunnelInnerAddress
))
4643 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer
->rdata
->u
.ipv6
);
4644 UnlinkAndReissueBlockedQuestions(tun
, mDNStrue
);
4647 if (info
&& mDNSSameIPv6NetworkPart(answer
->rdata
->u
.ipv6
, info
->AutoTunnelInnerAddress
))
4649 LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer
->rdata
->u
.ipv6
);
4650 UnlinkAndReissueBlockedQuestions(tun
, mDNStrue
);
4653 tun
->rmt_inner
= answer
->rdata
->u
.ipv6
;
4654 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun
->rmt_inner
);
4655 if (!mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
))
4657 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
4658 tun
->tc_state
= TC_STATE_AAAA_PEER_RELAY
;
4659 question
->qtype
= kDNSType_AAAA
;
4660 AssignDomainName(&question
->qname
, (const domainname
*) "\x0C" "_autotunnel6");
4664 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
4665 tun
->tc_state
= TC_STATE_SRV_PEER
;
4666 question
->qtype
= kDNSType_SRV
;
4667 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
4669 AppendDomainName(&question
->qname
, &tun
->dstname
);
4670 mDNS_StartQuery(m
, &tun
->q
);
4672 case TC_STATE_AAAA_PEER_RELAY
:
4673 if (question
->qtype
!= kDNSType_AAAA
)
4675 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question
->qtype
);
4677 // If it failed, look for the SRV record.
4678 if (!answer
->rdlength
)
4680 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
4681 tun
->tc_state
= TC_STATE_SRV_PEER
;
4682 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
4683 AppendDomainName(&question
->qname
, &tun
->dstname
);
4684 question
->qtype
= kDNSType_SRV
;
4685 mDNS_StartQuery(m
, &tun
->q
);
4688 TunnelClientFinish(question
, answer
);
4690 case TC_STATE_SRV_PEER
:
4691 if (question
->qtype
!= kDNSType_SRV
)
4693 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question
->qtype
);
4695 LogInfo("AutoTunnelCallback: SRV target name %##s", answer
->rdata
->u
.srv
.target
.c
);
4696 tun
->tc_state
= TC_STATE_ADDR_PEER
;
4697 AssignDomainName(&tun
->q
.qname
, &answer
->rdata
->u
.srv
.target
);
4698 tun
->rmt_outer_port
= answer
->rdata
->u
.srv
.port
;
4699 question
->qtype
= kDNSType_A
;
4700 mDNS_StartQuery(m
, &tun
->q
);
4702 case TC_STATE_ADDR_PEER
:
4703 if (question
->qtype
!= kDNSType_A
)
4705 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question
->qtype
);
4707 TunnelClientFinish(question
, answer
);
4710 LogMsg("AutoTunnelCallback: Unknown question %p", question
);
4714 // Must be called with the lock held
4715 mDNSexport
void AddNewClientTunnel(DNSQuestion
*const q
)
4717 mDNS
*const m
= &mDNSStorage
;
4718 ClientTunnel
*p
= mallocL("ClientTunnel", sizeof(ClientTunnel
));
4720 AssignDomainName(&p
->dstname
, &q
->qname
);
4721 p
->MarkedForDeletion
= mDNSfalse
;
4722 p
->loc_inner
= zerov6Addr
;
4723 p
->loc_outer
= zerov4Addr
;
4724 p
->loc_outer6
= zerov6Addr
;
4725 p
->rmt_inner
= zerov6Addr
;
4726 p
->rmt_outer
= zerov4Addr
;
4727 p
->rmt_outer6
= zerov6Addr
;
4728 p
->rmt_outer_port
= zeroIPPort
;
4729 p
->tc_state
= TC_STATE_AAAA_PEER
;
4730 p
->next
= m
->TunnelClients
;
4731 m
->TunnelClients
= p
; // We intentionally build list in reverse order
4733 p
->q
.InterfaceID
= mDNSInterface_Any
;
4735 p
->q
.Target
= zeroAddr
;
4736 AssignDomainName(&p
->q
.qname
, &q
->qname
);
4737 p
->q
.qtype
= kDNSType_AAAA
;
4738 p
->q
.qclass
= kDNSClass_IN
;
4739 p
->q
.LongLived
= mDNSfalse
;
4740 p
->q
.ExpectUnique
= mDNStrue
;
4741 p
->q
.ForceMCast
= mDNSfalse
;
4742 p
->q
.ReturnIntermed
= mDNStrue
;
4743 p
->q
.SuppressUnusable
= mDNSfalse
;
4744 p
->q
.SearchListIndex
= 0;
4745 p
->q
.AppendSearchDomains
= 0;
4746 p
->q
.RetryWithSearchDomains
= mDNSfalse
;
4747 p
->q
.TimeoutQuestion
= 0;
4748 p
->q
.WakeOnResolve
= 0;
4749 p
->q
.UseBackgroundTrafficClass
= mDNSfalse
;
4750 p
->q
.ValidationRequired
= 0;
4751 p
->q
.ValidatingResponse
= 0;
4752 p
->q
.ProxyQuestion
= 0;
4753 p
->q
.qnameOrig
= mDNSNULL
;
4754 p
->q
.AnonInfo
= mDNSNULL
;
4755 p
->q
.pid
= mDNSPlatformGetPID();
4757 p
->q
.QuestionCallback
= AutoTunnelCallback
;
4758 p
->q
.QuestionContext
= p
;
4760 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p
, &q
->qname
.c
, DNSTypeName(q
->qtype
), q
->LongLived
? " LongLived" : "");
4761 mDNS_StartQuery_internal(m
, &p
->q
);
4764 #endif // APPLE_OSX_mDNSResponder
4766 #if COMPILER_LIKES_PRAGMA_MARK
4768 #pragma mark - Power State & Configuration Change Management
4771 mDNSlocal mStatus
ReorderInterfaceList()
4773 // Disable Reorder lists till <rdar://problem/30071012> is fixed to prevent spurious name conflicts
4774 return (mStatus_NoError
);
4776 mDNS
*const m
= &mDNSStorage
;
4777 nwi_state_t state
= nwi_state_copy();
4779 if (state
== mDNSNULL
)
4781 LogMsg("NWI State is NULL!");
4782 return (mStatus_Invalid
);
4785 // Get the count of interfaces
4786 mDNSu32 count
= nwi_state_get_interface_names(state
, mDNSNULL
, 0);
4789 LogMsg("Unable to get the ordered list of interface names");
4790 nwi_state_release(state
);
4791 return (mStatus_Invalid
);
4794 // Get the ordered interface list
4796 const char *names
[count
];
4797 count
= nwi_state_get_interface_names(state
, names
, count
);
4799 NetworkInterfaceInfo
*newList
= mDNSNULL
;
4800 for (i
= count
-1; i
>= 0; i
--)
4801 { // Build a new ordered interface list
4802 NetworkInterfaceInfo
**ptr
= &m
->HostInterfaces
;
4803 while (*ptr
!= mDNSNULL
)
4805 if (strcmp((*ptr
)->ifname
, names
[i
]) == 0)
4807 NetworkInterfaceInfo
*node
= *ptr
;
4808 *ptr
= (*ptr
)->next
;
4809 node
->next
= newList
;
4813 ptr
= &((*ptr
)->next
);
4817 // Get to the end of the list
4818 NetworkInterfaceInfo
*newListEnd
= newList
;
4819 while (newListEnd
!= mDNSNULL
&& newListEnd
->next
!= mDNSNULL
)
4820 newListEnd
= newListEnd
->next
;
4822 // Add any remaing interfaces to the end of the sorted list
4823 if (newListEnd
!= mDNSNULL
)
4824 newListEnd
->next
= m
->HostInterfaces
;
4826 // If we have a valid new list, point to that now
4827 if (newList
!= mDNSNULL
)
4828 m
->HostInterfaces
= newList
;
4830 nwi_state_release(state
);
4831 return (mStatus_NoError
);
4834 mDNSlocal mStatus
UpdateInterfaceList(mDNSs32 utc
)
4836 mDNS
*const m
= &mDNSStorage
;
4837 mDNSBool foundav4
= mDNSfalse
;
4838 mDNSBool foundav6
= mDNSfalse
;
4839 struct ifaddrs
*ifa
= myGetIfAddrs(0);
4840 struct ifaddrs
*v4Loopback
= NULL
;
4841 struct ifaddrs
*v6Loopback
= NULL
;
4842 char defaultname
[64];
4843 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
4844 if (InfoSocket
< 3 && errno
!= EAFNOSUPPORT
)
4845 LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
4847 if (m
->SleepState
== SleepState_Sleeping
) ifa
= NULL
;
4851 #if LIST_ALL_INTERFACES
4854 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
4855 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
4856 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4857 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
4858 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
4859 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4860 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
4861 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
4862 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4865 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X ifa_addr is NOT set",
4866 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
);
4868 if (!(ifa
->ifa_flags
& IFF_UP
))
4869 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
4870 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
,
4871 ifa
->ifa_addr
? ifa
->ifa_addr
->sa_family
: 0);
4872 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
4873 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
4874 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
,
4875 ifa
->ifa_addr
? ifa
->ifa_addr
->sa_family
: 0);
4876 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
4877 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
4878 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
,
4879 ifa
->ifa_addr
? ifa
->ifa_addr
->sa_family
: 0);
4880 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
4881 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
4882 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
,
4883 ifa
->ifa_addr
? ifa
->ifa_addr
->sa_family
: 0);
4886 if (ifa
->ifa_addr
&& ifa
->ifa_addr
->sa_family
== AF_LINK
)
4888 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
4889 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(m
->PrimaryMAC
) && mDNSSameEthAddress(&m
->PrimaryMAC
, &zeroEthAddr
))
4890 mDNSPlatformMemCopy(m
->PrimaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6);
4893 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
&& !isCoprocessorInterface(InfoSocket
, ifa
->ifa_name
))
4894 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
4896 if (!ifa
->ifa_netmask
)
4899 SetupAddr(&ip
, ifa
->ifa_addr
);
4900 LogMsg("UpdateInterfaceList: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
4901 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
4903 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
4904 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4905 else if (ifa
->ifa_netmask
->sa_family
!= ifa
->ifa_addr
->sa_family
&& ifa
->ifa_netmask
->sa_family
!= 0)
4908 SetupAddr(&ip
, ifa
->ifa_addr
);
4909 LogMsg("UpdateInterfaceList: ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
4910 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
4912 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
4913 else if ((int)if_nametoindex(ifa
->ifa_name
) <= 0)
4915 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
));
4919 // Make sure ifa_netmask->sa_family is set correctly
4920 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4921 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
;
4922 int ifru_flags6
= 0;
4924 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
4925 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
4927 struct in6_ifreq ifr6
;
4928 mDNSPlatformMemZero((char *)&ifr6
, sizeof(ifr6
));
4929 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
4930 ifr6
.ifr_addr
= *sin6
;
4931 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
4932 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
4933 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
4936 if (!(ifru_flags6
& (IN6_IFF_TENTATIVE
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
4938 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
4940 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
4942 else if (sin6
->sin6_addr
.s6_addr
[0] != 0xFD)
4947 NetworkInterfaceInfoOSX
*i
= AddInterfaceToList(ifa
, utc
);
4948 if (i
&& MulticastInterface(i
) && i
->ifinfo
.Advertise
)
4950 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
4951 foundav4
= mDNStrue
;
4953 foundav6
= mDNStrue
;
4959 ifa
= ifa
->ifa_next
;
4962 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
4963 if (!foundav4
&& v4Loopback
) AddInterfaceToList(v4Loopback
, utc
);
4964 if (!foundav6
&& v6Loopback
) AddInterfaceToList(v6Loopback
, utc
);
4966 if (InfoSocket
>= 0)
4969 mDNS_snprintf(defaultname
, sizeof(defaultname
), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen
, HINFO_HWstring
,
4970 m
->PrimaryMAC
.b
[0], m
->PrimaryMAC
.b
[1], m
->PrimaryMAC
.b
[2], m
->PrimaryMAC
.b
[3], m
->PrimaryMAC
.b
[4], m
->PrimaryMAC
.b
[5]);
4972 // Set up the nice label
4973 domainlabel nicelabel
;
4975 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
4976 if (nicelabel
.c
[0] == 0)
4978 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname
);
4979 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
4982 // Set up the RFC 1034-compliant label
4983 domainlabel hostlabel
;
4985 GetUserSpecifiedLocalHostName(&hostlabel
);
4986 if (hostlabel
.c
[0] == 0)
4988 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname
);
4989 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
4992 mDNSBool namechange
= mDNSfalse
;
4994 // We use a case-sensitive comparison here because even though changing the capitalization
4995 // of the name alone is not significant to DNS, it's still a change from the user's point of view
4996 if (SameDomainLabelCS(m
->p
->usernicelabel
.c
, nicelabel
.c
))
4997 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
5000 if (m
->p
->usernicelabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
5001 LogMsg("User updated Computer Name from “%#s” to “%#s”", m
->p
->usernicelabel
.c
, nicelabel
.c
);
5002 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
5003 namechange
= mDNStrue
;
5006 if (SameDomainLabelCS(m
->p
->userhostlabel
.c
, hostlabel
.c
))
5007 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
5010 if (m
->p
->userhostlabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
5011 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m
->p
->userhostlabel
.c
, hostlabel
.c
);
5012 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
5014 namechange
= mDNStrue
;
5017 if (namechange
) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
5019 #if APPLE_OSX_mDNSResponder
5020 DomainAuthInfo
*info
;
5021 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
5022 if (info
->AutoTunnel
) AutoTunnelHostNameChanged(m
, info
);
5023 #endif // APPLE_OSX_mDNSResponder
5026 return(mStatus_NoError
);
5029 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
5030 // Returns -1 if all the one-bits are not contiguous
5031 mDNSlocal
int CountMaskBits(mDNSAddr
*mask
)
5033 int i
= 0, bits
= 0;
5034 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
5037 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
5038 while (b
& 0x80) { bits
++; b
<<= 1; }
5041 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
5045 // Returns count of non-link local V4 addresses registered (why? -- SC)
5046 mDNSlocal
int SetupActiveInterfaces(mDNSs32 utc
)
5048 mDNS
*const m
= &mDNSStorage
;
5049 NetworkInterfaceInfoOSX
*i
;
5052 // Recalculate SuppressProbes time based on the current set of active interfaces.
5053 m
->SuppressProbes
= 0;
5054 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
5057 NetworkInterfaceInfo
*const n
= &i
->ifinfo
;
5058 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_UNSPEC
);
5059 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifinfo
.ifname
);
5061 if (i
->Registered
&& i
->Registered
!= primary
) // Sanity check
5063 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i
->Registered
, primary
);
5064 i
->Registered
= mDNSNULL
;
5069 InterfaceActivationSpeed activationSpeed
;
5071 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5072 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5073 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it.
5074 i
->Registered
= primary
;
5076 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
5077 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
5078 // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario.
5079 i
->Occulting
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->LastSeen
> 0 && utc
- i
->LastSeen
< 60);
5081 // The "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
5082 // every time a new interface is created. We think it is a duplicate and hence consider it
5083 // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
5084 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
5085 // logs a warning message to system.log noting frequent interface transitions.
5086 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
5087 if ((strncmp(i
->ifinfo
.ifname
, "p2p", 3) == 0) || i
->ifinfo
.DirectLink
)
5089 activationSpeed
= FastActivation
;
5090 LogInfo("SetupActiveInterfaces: %s DirectLink interface registering", i
->ifinfo
.ifname
);
5092 else if (i
->Flashing
&& i
->Occulting
)
5094 activationSpeed
= SlowActivation
;
5098 activationSpeed
= NormalActivation
;
5101 mDNS_RegisterInterface(m
, n
, activationSpeed
);
5103 if (!mDNSAddressIsLinkLocal(&n
->ip
)) count
++;
5104 LogInfo("SetupActiveInterfaces: Registered %7s(%u) BSSID %.6a Struct addr %p, primary %p, %#a/%d%s%s%s",
5105 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
, primary
, &n
->ip
, CountMaskBits(&n
->mask
),
5106 i
->Flashing
? " (Flashing)" : "",
5107 i
->Occulting
? " (Occulting)" : "",
5108 n
->InterfaceActive
? " (Primary)" : "");
5112 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, &n
->ip
);
5113 #if TARGET_OS_EMBEDDED
5114 // We join the Bonjour multicast group on Apple embedded platforms ONLY when a client request is active,
5115 // so we leave the multicast group here to clear any residual group membership.
5116 if (i
->sa_family
== AF_INET
)
5119 primary
->ifa_v4addr
.s_addr
= n
->ip
.ip
.v4
.NotAnInteger
;
5120 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
5121 imr
.imr_interface
= primary
->ifa_v4addr
;
5123 if (SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_INET
) == i
)
5125 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IP_DROP_MEMBERSHIP for %.4a on %.4a", i
->ifinfo
.ifname
, i
->scope_id
, &imr
.imr_multiaddr
, &imr
.imr_interface
);
5126 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, &imr
, sizeof(imr
));
5127 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
5128 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err
, errno
, strerror(errno
));
5131 if (i
->sa_family
== AF_INET6
)
5133 struct ipv6_mreq i6mr
;
5134 i6mr
.ipv6mr_interface
= primary
->scope_id
;
5135 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroup_v6
.ip
.v6
;
5137 if (SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_INET6
) == i
)
5139 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IPV6_LEAVE_GROUP for %.16a on %u", i
->ifinfo
.ifname
, i
->scope_id
, &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5140 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
5141 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
5142 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5145 #endif // TARGET_OS_EMBEDDED
5149 if (i
->sa_family
== AF_INET
)
5152 primary
->ifa_v4addr
.s_addr
= n
->ip
.ip
.v4
.NotAnInteger
;
5153 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
5154 imr
.imr_interface
= primary
->ifa_v4addr
;
5156 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
5157 // before trying to join the group, to clear out stale kernel state which may be lingering.
5158 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
5159 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
5160 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
5161 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
5162 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
5163 // because by the time we get the configuration change notification, the interface is already gone,
5164 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
5165 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
5166 if (SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_INET
) == i
)
5168 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i
->ifinfo
.ifname
, i
->scope_id
, &imr
.imr_multiaddr
, &imr
.imr_interface
);
5169 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, &imr
, sizeof(imr
));
5170 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
5171 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err
, errno
, strerror(errno
));
5174 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i
->ifinfo
.ifname
, i
->scope_id
, &imr
.imr_multiaddr
, &imr
.imr_interface
);
5175 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
5176 // Joining same group twice can give "Address already in use" error -- no need to report that
5177 if (err
< 0 && (errno
!= EADDRINUSE
))
5178 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err
, errno
, strerror(errno
), &imr
.imr_multiaddr
, &imr
.imr_interface
);
5180 if (i
->sa_family
== AF_INET6
)
5182 struct ipv6_mreq i6mr
;
5183 i6mr
.ipv6mr_interface
= primary
->scope_id
;
5184 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroup_v6
.ip
.v6
;
5186 if (SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_INET6
) == i
)
5188 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i
->ifinfo
.ifname
, i
->scope_id
, &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5189 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
5190 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
5191 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5194 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i
->ifinfo
.ifname
, i
->scope_id
, &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5195 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
5196 // Joining same group twice can give "Address already in use" error -- no need to report that
5197 if (err
< 0 && (errno
!= EADDRINUSE
))
5198 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5207 mDNSlocal
void MarkAllInterfacesInactive(mDNSs32 utc
)
5209 NetworkInterfaceInfoOSX
*i
;
5210 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
5212 if (i
->Exists
) i
->LastSeen
= utc
;
5213 i
->Exists
= mDNSfalse
;
5217 // Returns count of non-link local V4 addresses deregistered (why? -- SC)
5218 mDNSlocal
int ClearInactiveInterfaces(mDNSs32 utc
)
5220 mDNS
*const m
= &mDNSStorage
;
5222 // If an interface is going away, then deregister this from the mDNSCore.
5223 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
5224 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
5225 // it refers to has gone away we'll crash.
5226 NetworkInterfaceInfoOSX
*i
;
5228 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
5230 // If this interface is no longer active, or its InterfaceID is changing, deregister it
5231 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_UNSPEC
);
5233 if (i
->Exists
== 0 || i
->Exists
== MulticastStateChanged
|| i
->Registered
!= primary
)
5235 InterfaceActivationSpeed activationSpeed
;
5237 i
->Flashing
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->AppearanceTime
< 60);
5238 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5239 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
, primary
,
5240 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
),
5241 i
->Flashing
? " (Flashing)" : "",
5242 i
->Occulting
? " (Occulting)" : "",
5243 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
5245 // "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
5246 // every time it creates a new interface. We think it is a duplicate and hence consider it
5247 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
5248 // stale data returned to the application even after the interface is removed. The application
5249 // then starts to send data but the new interface is not yet created.
5250 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
5251 if ((strncmp(i
->ifinfo
.ifname
, "p2p", 3) == 0) || i
->ifinfo
.DirectLink
)
5253 activationSpeed
= FastActivation
;
5254 LogInfo("ClearInactiveInterfaces: %s DirectLink interface deregistering", i
->ifinfo
.ifname
);
5256 else if (i
->Flashing
&& i
->Occulting
)
5258 activationSpeed
= SlowActivation
;
5262 activationSpeed
= NormalActivation
;
5264 mDNS_DeregisterInterface(m
, &i
->ifinfo
, activationSpeed
);
5266 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
5267 i
->Registered
= mDNSNULL
;
5268 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5269 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5270 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
5272 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
5273 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
5278 // Now that everything that's going to deregister has done so, we can clean up and free the memory
5279 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
5283 // If no longer active, delete interface from list and free memory
5286 if (i
->LastSeen
== utc
) i
->LastSeen
= utc
- 1;
5287 const mDNSBool
delete = (i
->isAWDL
|| (NumCacheRecordsForInterfaceID(m
, i
->ifinfo
.InterfaceID
) == 0)) && (utc
- i
->LastSeen
>= 60);
5288 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
5289 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
,
5290 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), utc
- i
->LastSeen
,
5291 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
5292 #if APPLE_OSX_mDNSResponder
5293 if (i
->BPF_fd
>= 0) CloseBPF(i
);
5294 #endif // APPLE_OSX_mDNSResponder
5298 freeL("NetworkInterfaceInfoOSX", i
);
5299 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
5307 mDNSlocal
void AppendDNameListElem(DNameListElem
***List
, mDNSu32 uid
, domainname
*name
)
5309 DNameListElem
*dnle
= (DNameListElem
*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem
));
5310 if (!dnle
) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
5313 dnle
->next
= mDNSNULL
;
5315 AssignDomainName(&dnle
->name
, name
);
5317 *List
= &dnle
->next
;
5321 mDNSlocal
int compare_dns_configs(const void *aa
, const void *bb
)
5323 dns_resolver_t
*a
= *(dns_resolver_t
**)aa
;
5324 dns_resolver_t
*b
= *(dns_resolver_t
**)bb
;
5326 return (a
->search_order
< b
->search_order
) ? -1 : (a
->search_order
== b
->search_order
) ? 0 : 1;
5329 mDNSlocal
void UpdateSearchDomainHash(MD5_CTX
*sdc
, char *domain
, mDNSInterfaceID InterfaceID
)
5331 mDNS
*const m
= &mDNSStorage
;
5333 mDNSu32 scopeid
= 0;
5339 // Hash the search domain name followed by the InterfaceID.
5340 // As we have scoped search domains, we also included InterfaceID. If either of them change,
5341 // we will detect it. Even if the order of them change, we will detect it.
5343 // Note: We have to handle a few of these tricky cases.
5345 // 1) Current: com, apple.com Changing to: comapple.com
5346 // 2) Current: a.com,b.com Changing to a.comb.com
5347 // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
5348 // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
5350 // There are more variants of the above. The key thing is if we include the null in each case
5351 // at the end of name and the InterfaceID, it will prevent a new name (which can't include
5352 // NULL as part of the name) to be mistakenly thought of as a old name.
5354 scopeid
= mDNSPlatformInterfaceIndexfromInterfaceID(m
, InterfaceID
, mDNStrue
);
5355 // mDNS_snprintf always null terminates
5356 if (mDNS_snprintf(ifid_buf
, sizeof(ifid_buf
), "%u", scopeid
) >= sizeof(ifid_buf
))
5357 LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid
);
5359 LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf
, ifid_buf
);
5360 MD5_Update(sdc
, buf
, strlen(buf
) + 1);
5361 MD5_Update(sdc
, ifid_buf
, strlen(ifid_buf
) + 1);
5364 mDNSlocal
void FinalizeSearchDomainHash(MD5_CTX
*sdc
)
5366 mDNS
*const m
= &mDNSStorage
;
5367 mDNSu8 md5_hash
[MD5_LEN
];
5369 MD5_Final(md5_hash
, sdc
);
5371 if (memcmp(md5_hash
, m
->SearchDomainsHash
, MD5_LEN
))
5373 // If the hash is different, either the search domains have changed or
5374 // the ordering between them has changed. Restart the questions that
5375 // would be affected by this.
5376 LogInfo("FinalizeSearchDomains: The hash is different");
5377 memcpy(m
->SearchDomainsHash
, md5_hash
, MD5_LEN
);
5378 RetrySearchDomainQuestions(m
);
5380 else { LogInfo("FinalizeSearchDomains: The hash is same"); }
5383 mDNSexport
const char *DNSScopeToString(mDNSu32 scope
)
5389 case kScopeInterfaceID
:
5390 return "InterfaceScoped";
5391 case kScopeServiceID
:
5392 return "ServiceScoped";
5398 mDNSlocal
void ConfigSearchDomains(dns_resolver_t
*resolver
, mDNSInterfaceID interfaceId
, mDNSu32 scope
, MD5_CTX
*sdc
, uint64_t generation
)
5400 const char *scopeString
= DNSScopeToString(scope
);
5404 if (scope
== kScopeNone
)
5405 interfaceId
= mDNSInterface_Any
;
5407 if (scope
== kScopeNone
|| scope
== kScopeInterfaceID
)
5409 for (j
= 0; j
< resolver
->n_search
; j
++)
5411 if (MakeDomainNameFromDNSNameString(&d
, resolver
->search
[j
]) != NULL
)
5413 static char interface_buf
[32];
5414 mDNS_snprintf(interface_buf
, sizeof(interface_buf
), "for interface %s", InterfaceNameForID(&mDNSStorage
, interfaceId
));
5415 LogInfo("ConfigSearchDomains: (%s) configuring search domain %s %s (generation= %llu)", scopeString
,
5416 resolver
->search
[j
], (interfaceId
== mDNSInterface_Any
) ? "" : interface_buf
, generation
);
5417 UpdateSearchDomainHash(sdc
, resolver
->search
[j
], interfaceId
);
5418 mDNS_AddSearchDomain_CString(resolver
->search
[j
], interfaceId
);
5422 LogInfo("ConfigSearchDomains: An invalid search domain was detected for %s domain %s n_nameserver %d, (generation= %llu)",
5423 DNSScopeToString(scope
), resolver
->domain
, resolver
->n_nameserver
, generation
);
5429 LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString
, InterfaceNameForID(&mDNSStorage
, interfaceId
));
5433 mDNSlocal mDNSInterfaceID
ConfigParseInterfaceID(mDNSu32 ifindex
)
5435 NetworkInterfaceInfoOSX
*ni
;
5436 mDNSInterfaceID interface
;
5438 for (ni
= mDNSStorage
.p
->InterfaceList
; ni
; ni
= ni
->next
)
5440 if (ni
->ifinfo
.InterfaceID
&& ni
->scope_id
== ifindex
)
5445 interface
= ni
->ifinfo
.InterfaceID
;
5449 // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
5450 // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
5451 // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
5452 // As the caller is going to ack the configuration always, we have to add all the DNS servers
5453 // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
5455 LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex
);
5457 // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
5458 interface
= (mDNSInterfaceID
)(unsigned long)ifindex
;
5463 mDNSlocal
void ConfigNonUnicastResolver(dns_resolver_t
*r
)
5465 char *opt
= r
->options
;
5468 if (opt
&& !strncmp(opt
, "mdns", strlen(opt
)))
5470 if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
))
5472 LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r
->domain
);
5475 mDNS_AddMcastResolver(&mDNSStorage
, &d
, mDNSInterface_Any
, r
->timeout
);
5479 mDNSlocal
void ConfigDNSServers(dns_resolver_t
*r
, mDNSInterfaceID interface
, mDNSu32 scope
, mDNSu16 resGroupID
)
5484 mDNSBool cellIntf
= mDNSfalse
;
5485 mDNSBool reqA
, reqAAAA
;
5486 NetworkInterfaceInfoOSX
*info
;
5487 mDNSBool isExpensive
;
5490 if (!r
->domain
|| !*r
->domain
)
5494 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
))
5496 LogMsg("ConfigDNSServers: bad domain %s", r
->domain
);
5499 // Parse the resolver specific attributes that affects all the DNS servers.
5500 if (scope
== kScopeServiceID
)
5502 serviceID
= r
->service_identifier
;
5505 #if TARGET_OS_IPHONE
5506 cellIntf
= (r
->reach_flags
& kSCNetworkReachabilityFlagsIsWWAN
) ? mDNStrue
: mDNSfalse
;
5508 reqA
= (r
->flags
& DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
? mDNStrue
: mDNSfalse
);
5509 reqAAAA
= (r
->flags
& DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
? mDNStrue
: mDNSfalse
);
5510 info
= IfindexToInterfaceInfoOSX(interface
);
5511 isExpensive
= (info
&& info
->isExpensive
) ? mDNStrue
: mDNSfalse
;
5512 isCLAT46
= (info
&& info
->isCLAT46
) ? mDNStrue
: mDNSfalse
;
5514 for (n
= 0; n
< r
->n_nameserver
; n
++)
5519 if (r
->nameserver
[n
]->sa_family
!= AF_INET
&& r
->nameserver
[n
]->sa_family
!= AF_INET6
)
5522 if (SetupAddr(&saddr
, r
->nameserver
[n
]))
5524 LogMsg("ConfigDNSServers: Bad address");
5528 // The timeout value is for all the DNS servers in a given resolver, hence we pass
5529 // the timeout value only for the first DNSServer. If we don't have a value in the
5530 // resolver, then use the core's default value
5532 // Note: this assumes that when the core picks a list of DNSServers for a question,
5533 // it takes the sum of all the timeout values for all DNS servers. By doing this, it
5534 // tries all the DNS servers in a specified timeout
5535 s
= mDNS_AddDNSServer(&mDNSStorage
, &d
, interface
, serviceID
, &saddr
, r
->port
? mDNSOpaque16fromIntVal(r
->port
) : UnicastDNSPort
, scope
,
5536 (n
== 0 ? (r
->timeout
? r
->timeout
: DEFAULT_UDNS_TIMEOUT
) : 0), cellIntf
, isExpensive
, isCLAT46
,
5537 resGroupID
, reqA
, reqAAAA
, mDNStrue
);
5540 LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope
), &s
->addr
, mDNSVal16(s
->port
), d
.c
);
5545 // ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
5546 // Service scope resolvers. This is indicated by the scope argument.
5548 // "resolver" has entries that should only be used for unscoped questions.
5550 // "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
5551 // interface index (q->InterfaceID)
5553 // "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
5554 // a service identifier (q->ServiceID)
5556 mDNSlocal
void ConfigResolvers(dns_config_t
*config
, mDNSu32 scope
, mDNSBool setsearch
, mDNSBool setservers
, MD5_CTX
*sdc
, mDNSu16 resGroupID
)
5559 dns_resolver_t
**resolver
;
5561 const char *scopeString
= DNSScopeToString(scope
);
5562 mDNSInterfaceID interface
;
5567 resolver
= config
->resolver
;
5568 nresolvers
= config
->n_resolver
;
5570 case kScopeInterfaceID
:
5571 resolver
= config
->scoped_resolver
;
5572 nresolvers
= config
->n_scoped_resolver
;
5574 case kScopeServiceID
:
5575 resolver
= config
->service_specific_resolver
;
5576 nresolvers
= config
->n_service_specific_resolver
;
5581 qsort(resolver
, nresolvers
, sizeof(dns_resolver_t
*), compare_dns_configs
);
5583 for (i
= 0; i
< nresolvers
; i
++)
5585 dns_resolver_t
*r
= resolver
[i
];
5587 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString
, i
, r
->domain
, r
->n_nameserver
);
5589 interface
= mDNSInterface_Any
;
5591 // Parse the interface index
5592 if (r
->if_index
!= 0)
5594 interface
= ConfigParseInterfaceID(r
->if_index
);
5599 ConfigSearchDomains(resolver
[i
], interface
, scope
, sdc
, config
->generation
);
5601 // Parse other scoped resolvers for search lists
5606 if (r
->port
== 5353 || r
->n_nameserver
== 0)
5608 ConfigNonUnicastResolver(r
);
5612 // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the
5613 // scoped resolver are not used by other non-scoped or scoped resolvers.
5614 if (scope
!= kScopeNone
)
5617 ConfigDNSServers(r
, interface
, scope
, resGroupID
);
5622 #if APPLE_OSX_mDNSResponder
5623 mDNSlocal mDNSBool
QuestionValidForDNSTrigger(DNSQuestion
*q
)
5625 if (QuerySuppressed(q
))
5627 debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
5630 if (mDNSOpaque16IsZero(q
->TargetQID
))
5632 debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
5635 // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
5637 if (q
->LOAddressAnswers
)
5639 debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
5646 // This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
5647 // We set our state appropriately so that if we start receiving answers, trigger the
5648 // upper layer to retry DNS questions.
5649 #if APPLE_OSX_mDNSResponder
5650 mDNSexport
void mDNSPlatformUpdateDNSStatus(DNSQuestion
*q
)
5652 mDNS
*const m
= &mDNSStorage
;
5653 if (!QuestionValidForDNSTrigger(q
))
5656 // Ignore applications that start and stop queries for no reason before we ever talk
5657 // to any DNS server.
5658 if (!q
->triedAllServersOnce
)
5660 LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q
->qname
.c
, DNSTypeName(q
->qtype
));
5663 if (q
->qtype
== kDNSType_A
)
5664 m
->p
->v4answers
= 0;
5665 if (q
->qtype
== kDNSType_AAAA
)
5666 m
->p
->v6answers
= 0;
5667 if (!m
->p
->v4answers
|| !m
->p
->v6answers
)
5669 LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, question %##s (%s)", m
->p
->v4answers
, m
->p
->v6answers
, q
->qname
.c
,
5670 DNSTypeName(q
->qtype
));
5675 mDNSlocal
void AckConfigd(dns_config_t
*config
)
5677 mDNS_CheckLock(&mDNSStorage
);
5679 // Acking the configuration triggers configd to reissue the reachability queries
5680 mDNSStorage
.p
->DNSTrigger
= NonZeroTime(mDNSStorage
.timenow
);
5681 _dns_configuration_ack(config
, "com.apple.mDNSResponder");
5684 // If v4q is non-NULL, it means we have received some answers for "A" type questions
5685 // If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
5686 #if APPLE_OSX_mDNSResponder
5687 mDNSexport
void mDNSPlatformTriggerDNSRetry(DNSQuestion
*v4q
, DNSQuestion
*v6q
)
5689 mDNS
*const m
= &mDNSStorage
;
5690 mDNSBool trigger
= mDNSfalse
;
5693 // Don't send triggers too often.
5694 // If we have started delivering answers to questions, we should send a trigger
5695 // if the time permits. If we are delivering answers, we should set the state
5696 // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know
5697 // whether the answers that are being delivered currently is for configd or some
5698 // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
5699 // then we won't deliver the trigger later when it is okay to send one as the
5700 // "answers" are already set to 1. Hence, don't affect the state of v4answers and
5701 // v6answers if we are not delivering triggers.
5703 timenow
= m
->timenow
;
5704 if (m
->p
->DNSTrigger
&& (timenow
- m
->p
->DNSTrigger
) < DNS_TRIGGER_INTERVAL
)
5706 if (!m
->p
->v4answers
|| !m
->p
->v6answers
)
5708 debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
5709 (timenow
- m
->p
->DNSTrigger
), m
->p
->v4answers
, m
->p
->v6answers
);
5715 if (v4q
!= NULL
&& QuestionValidForDNSTrigger(v4q
))
5717 int old
= m
->p
->v4answers
;
5719 m
->p
->v4answers
= 1;
5721 // If there are IPv4 answers now and previously we did not have
5722 // any answers, trigger a DNS change so that reachability
5723 // can retry the queries again.
5726 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow
- m
->p
->DNSTrigger
),
5727 v4q
->qname
.c
, DNSTypeName(v4q
->qtype
));
5731 if (v6q
!= NULL
&& QuestionValidForDNSTrigger(v6q
))
5733 int old
= m
->p
->v6answers
;
5735 m
->p
->v6answers
= 1;
5736 // If there are IPv6 answers now and previously we did not have
5737 // any answers, trigger a DNS change so that reachability
5738 // can retry the queries again.
5741 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow
- m
->p
->DNSTrigger
),
5742 v6q
->qname
.c
, DNSTypeName(v6q
->qtype
));
5748 dns_config_t
*config
= dns_configuration_copy();
5754 dns_configuration_free(config
);
5758 LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
5763 mDNSlocal
void SetupActiveDirectoryDomain(dns_config_t
*config
)
5765 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
5766 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
5767 if (config
->n_resolver
&& config
->resolver
[0]->domain
&& config
->resolver
[0]->n_nameserver
&&
5768 config
->resolver
[0]->nameserver
[0])
5770 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain
, config
->resolver
[0]->domain
);
5774 ActiveDirectoryPrimaryDomain
.c
[0] = 0;
5777 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
5778 ActiveDirectoryPrimaryDomainLabelCount
= CountLabels(&ActiveDirectoryPrimaryDomain
);
5779 if (config
->n_resolver
&& config
->resolver
[0]->n_nameserver
&&
5780 SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain
, ActiveDirectoryPrimaryDomainLabelCount
- 1), &localdomain
))
5782 SetupAddr(&ActiveDirectoryPrimaryDomainServer
, config
->resolver
[0]->nameserver
[0]);
5786 AssignDomainName(&ActiveDirectoryPrimaryDomain
, (const domainname
*)"");
5787 ActiveDirectoryPrimaryDomainLabelCount
= 0;
5788 ActiveDirectoryPrimaryDomainServer
= zeroAddr
;
5793 mDNSlocal
void SetupDDNSDomains(domainname
*const fqdn
, DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
)
5796 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NULL
5799 CFDictionaryRef ddnsdict
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_DynamicDNS
);
5804 CFArrayRef fqdnArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("HostNames"));
5805 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
5807 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
5808 CFDictionaryRef fqdnDict
= CFArrayGetValueAtIndex(fqdnArray
, 0);
5809 if (fqdnDict
&& DictionaryIsEnabled(fqdnDict
))
5811 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
5814 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5815 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
5816 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
5818 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
5825 CFArrayRef regArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("RegistrationDomains"));
5826 if (regArray
&& CFArrayGetCount(regArray
) > 0)
5828 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
5829 if (regDict
&& DictionaryIsEnabled(regDict
))
5831 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
5834 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5835 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
5836 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
5839 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf
);
5840 AppendDNameListElem(&RegDomains
, 0, &d
);
5848 CFArrayRef browseArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("BrowseDomains"));
5851 for (i
= 0; i
< CFArrayGetCount(browseArray
); i
++)
5853 CFDictionaryRef browseDict
= CFArrayGetValueAtIndex(browseArray
, i
);
5854 if (browseDict
&& DictionaryIsEnabled(browseDict
))
5856 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
5859 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5860 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
5861 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf
[0] ? buf
: "(unknown)");
5864 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf
);
5865 AppendDNameListElem(&BrowseDomains
, 0, &d
);
5872 CFRelease(ddnsdict
);
5874 #if MDNSRESPONDER_BTMM_SUPPORT
5877 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_BackToMyMac
);
5880 CFIndex size
= CFDictionaryGetCount(btmm
);
5881 const void *key
[size
];
5882 const void *val
[size
];
5883 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
5884 for (i
= 0; i
< size
; i
++)
5886 LogInfo("BackToMyMac %d", i
);
5887 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5888 LogMsg("Can't read BackToMyMac %d key %s", i
, buf
);
5891 mDNSu32 uid
= atoi(buf
);
5892 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5893 LogMsg("Can't read BackToMyMac %d val %s", i
, buf
);
5894 else if (MakeDomainNameFromDNSNameString(&d
, buf
) && d
.c
[0])
5896 LogInfo("BackToMyMac %d %d %##s", i
, uid
, d
.c
);
5897 AppendDNameListElem(&RegDomains
, uid
, &d
);
5907 // Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
5908 mDNSexport mDNSBool
mDNSPlatformSetDNSConfig(mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
,
5909 DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
, mDNSBool ackConfig
)
5911 mDNS
*const m
= &mDNSStorage
;
5912 MD5_CTX sdc
; // search domain context
5913 static mDNSu16 resolverGroupID
= 0;
5915 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
5916 if (fqdn
) fqdn
->c
[0] = 0;
5917 if (RegDomains
) *RegDomains
= NULL
;
5918 if (BrowseDomains
) *BrowseDomains
= NULL
;
5920 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
5921 setservers
? " setservers" : "",
5922 setsearch
? " setsearch" : "",
5923 fqdn
? " fqdn" : "",
5924 RegDomains
? " RegDomains" : "",
5925 BrowseDomains
? " BrowseDomains" : "");
5927 if (setsearch
) MD5_Init(&sdc
);
5929 // Add the inferred address-based configuration discovery domains
5930 // (should really be in core code I think, not platform-specific)
5933 struct ifaddrs
*ifa
= mDNSNULL
;
5934 struct sockaddr_in saddr
;
5935 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
5936 saddr
.sin_len
= sizeof(saddr
);
5937 saddr
.sin_family
= AF_INET
;
5939 saddr
.sin_addr
.s_addr
= *(in_addr_t
*)&m
->Router
.ip
.v4
;
5941 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
5942 if (!AddrRequiresPPPConnection((struct sockaddr
*)&saddr
)) ifa
= myGetIfAddrs(1);
5949 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
5951 !(ifa
->ifa_flags
& IFF_LOOPBACK
) &&
5952 !SetupAddr(&a
, ifa
->ifa_addr
) &&
5953 !mDNSv4AddressIsLinkLocal(&a
.ip
.v4
) )
5955 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be incorrect, so we explicitly fix it here before calling SetupAddr
5956 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5957 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
; // Make sure ifa_netmask->sa_family is set correctly
5958 SetupAddr(&n
, ifa
->ifa_netmask
);
5959 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
5960 mDNS_snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d.in-addr.arpa.", a
.ip
.v4
.b
[3] & n
.ip
.v4
.b
[3],
5961 a
.ip
.v4
.b
[2] & n
.ip
.v4
.b
[2],
5962 a
.ip
.v4
.b
[1] & n
.ip
.v4
.b
[1],
5963 a
.ip
.v4
.b
[0] & n
.ip
.v4
.b
[0]);
5964 UpdateSearchDomainHash(&sdc
, buf
, NULL
);
5965 mDNS_AddSearchDomain_CString(buf
, mDNSNULL
);
5967 ifa
= ifa
->ifa_next
;
5971 #ifndef MDNS_NO_DNSINFO
5972 if (setservers
|| setsearch
)
5974 dns_config_t
*config
= dns_configuration_copy();
5977 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
5978 // Apparently this is expected behaviour -- "not a bug".
5979 // Accordingly, we suppress syslog messages for the first three minutes after boot.
5980 // If we are still getting failures after three minutes, then we log them.
5981 if ((mDNSu32
)mDNSPlatformRawTime() > (mDNSu32
)(mDNSPlatformOneSecond
* 180))
5982 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
5986 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config
->n_resolver
, config
->generation
, m
->p
->LastConfigGeneration
);
5988 // For every network change, mDNSPlatformSetDNSConfig is called twice. First,
5989 // to update the search domain list (in which case, the setsearch bool is set);
5990 // and second, to update the DNS server list (in which case, the setservers bool
5991 // is set). The code assumes only one of these flags, setsearch or setserver,
5992 // will be set when mDNSPlatformSetDNSConfig is called to handle a network change.
5993 // The mDNSPlatformSetDNSConfig function also assumes that ackCfg will be set
5994 // when setservers is set.
5996 // The search domains update occurs on every network change to avoid sync issues
5997 // that may occur if a network change happens during the processing
5998 // of a network change. The dns servers update occurs when the DNS config
5999 // changes. The dns servers stay in sync by saving the config's generation number
6000 // on every update; and only updating when the generation number changes.
6002 // If this is a DNS server update and the configuration hasn't changed, then skip update
6003 if (setservers
&& m
->p
->LastConfigGeneration
== config
->generation
)
6005 LogInfo("mDNSPlatformSetDNSConfig(setservers): generation number %llu same, not processing", config
->generation
);
6006 dns_configuration_free(config
);
6007 SetupDDNSDomains(fqdn
, RegDomains
, BrowseDomains
);
6010 #if APPLE_OSX_mDNSResponder
6011 SetupActiveDirectoryDomain(config
);
6014 // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry
6015 // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need
6016 // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between
6017 // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the
6018 // same resolverGroupID.
6020 // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally.
6021 ConfigResolvers(config
, kScopeNone
, setsearch
, setservers
, &sdc
, ++resolverGroupID
);
6022 resolverGroupID
+= config
->n_resolver
;
6024 ConfigResolvers(config
, kScopeInterfaceID
, setsearch
, setservers
, &sdc
, resolverGroupID
);
6025 resolverGroupID
+= config
->n_scoped_resolver
;
6027 ConfigResolvers(config
, kScopeServiceID
, setsearch
, setservers
, &sdc
, resolverGroupID
);
6029 // Acking provides a hint to other processes that the current DNS configuration has completed
6030 // its update. When configd receives the ack, it publishes a notification.
6031 // Applications monitoring the notification then know when to re-issue their DNS queries
6032 // after a network change occurs.
6035 // Note: We have to set the generation number here when we are acking.
6036 // For every DNS configuration change, we do the following:
6038 // 1) Copy dns configuration, handle search domains change
6039 // 2) Copy dns configuration, handle dns server change
6041 // If we update the generation number at step (1), we won't process the
6042 // DNS servers the second time because generation number would be the same.
6043 // As we ack only when we process dns servers, we set the generation number
6045 m
->p
->LastConfigGeneration
= config
->generation
;
6046 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers
, setsearch
);
6049 dns_configuration_free(config
);
6050 if (setsearch
) FinalizeSearchDomainHash(&sdc
);
6053 #endif // MDNS_NO_DNSINFO
6054 SetupDDNSDomains(fqdn
, RegDomains
, BrowseDomains
);
6059 mDNSexport mStatus
mDNSPlatformGetPrimaryInterface(mDNSAddr
*v4
, mDNSAddr
*v6
, mDNSAddr
*r
)
6063 CFDictionaryRef dict
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_IPv4
);
6066 r
->type
= mDNSAddrType_IPv4
;
6067 r
->ip
.v4
= zerov4Addr
;
6068 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
6071 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
6072 LogMsg("Could not convert router to CString");
6075 struct sockaddr_in saddr
;
6076 saddr
.sin_len
= sizeof(saddr
);
6077 saddr
.sin_family
= AF_INET
;
6079 inet_aton(buf
, &saddr
.sin_addr
);
6080 *(in_addr_t
*)&r
->ip
.v4
= saddr
.sin_addr
.s_addr
;
6083 string
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
6086 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
6087 struct ifaddrs
*ifa
= myGetIfAddrs(1);
6088 *v4
= *v6
= zeroAddr
;
6090 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
6092 LogMsg("Could not convert router to CString");
6095 // find primary interface in list
6096 while (ifa
&& (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
) || !HavePrimaryGlobalv6
))
6100 LogMsg("Skip interface, %s, since ifa_addr is not set.", (ifa
->ifa_name
) ? ifa
->ifa_name
: "name not found");
6101 ifa
= ifa
->ifa_next
;
6104 mDNSAddr tmp6
= zeroAddr
;
6105 if (!strcmp(buf
, ifa
->ifa_name
))
6107 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
6109 if (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
))
6110 SetupAddr(v4
, ifa
->ifa_addr
);
6112 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
6114 SetupAddr(&tmp6
, ifa
->ifa_addr
);
6115 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
6117 HavePrimaryGlobalv6
= mDNStrue
;
6124 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
6125 if (!HavePrimaryGlobalv6
&& ifa
->ifa_addr
->sa_family
== AF_INET6
&& !v6
->ip
.v6
.b
[0])
6127 SetupAddr(&tmp6
, ifa
->ifa_addr
);
6128 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1)
6132 ifa
= ifa
->ifa_next
;
6134 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
6135 // V4 to communicate w/ our DNS server
6141 return mStatus_NoError
;
6144 mDNSexport
void mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
6146 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status
, dname
->c
);
6147 char uname
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
6148 ConvertDomainNameToCString(dname
, uname
);
6154 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
6158 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
6159 // That single entity is a CFDictionary with name "HostNames".
6160 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
6161 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
6162 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
6163 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
6164 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
6166 const CFStringRef StateKeys
[1] = { CFSTR("HostNames") };
6167 const CFStringRef HostKeys
[1] = { CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
) };
6168 const CFStringRef StatusKeys
[1] = { CFSTR("Status") };
6169 if (!HostKeys
[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname
);
6172 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
6173 if (!StatusVals
[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status
);
6176 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
6179 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
6182 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
6185 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig
, mDNSNULL
, StateDict
);
6186 CFRelease(StateDict
);
6188 CFRelease(StateVals
[0]);
6190 CFRelease(HostVals
[0]);
6192 CFRelease(StatusVals
[0]);
6194 CFRelease(HostKeys
[0]);
6198 #if MDNSRESPONDER_BTMM_SUPPORT
6201 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
6202 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
6204 mDNSlocal mDNSBool
IsBTMMDomain(domainname
*d
)
6206 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:IsBTMMDomain"), NULL
, NULL
);
6209 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6212 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BackToMyMac
);
6215 CFIndex size
= CFDictionaryGetCount(btmm
);
6216 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
6217 const void *key
[size
];
6218 const void *val
[size
];
6221 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
6222 for (i
= 0; i
< size
; i
++)
6224 LogInfo("BackToMyMac %d", i
);
6225 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
6226 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i
, buf
);
6229 mDNSu32 uid
= atoi(buf
);
6230 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
6231 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i
, buf
);
6232 else if (MakeDomainNameFromDNSNameString(&dom
, buf
) && dom
.c
[0])
6234 if (SameDomainName(&dom
, d
))
6236 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d
->c
, uid
);
6247 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d
->c
);
6251 // Appends data to the buffer
6252 mDNSlocal
int AddOneItem(char *buf
, int bufsz
, char *data
, int *currlen
)
6256 len
= strlcpy(buf
+ *currlen
, data
, bufsz
- *currlen
);
6257 if (len
>= (bufsz
- *currlen
))
6259 // if we have exceeded the space in buf, it has already been NULL terminated
6260 // and we have nothing more to do. Set currlen to the last byte so that the caller
6261 // knows to do the right thing
6262 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen
, len
);
6263 *currlen
= bufsz
- 1;
6266 else { (*currlen
) += len
; }
6268 buf
[*currlen
] = ',';
6269 if (*currlen
>= bufsz
)
6271 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen
);
6272 *currlen
= bufsz
- 1;
6276 // if we have filled up the buffer exactly, then there is no more work to do
6277 if (*currlen
== bufsz
- 1) { buf
[*currlen
] = 0; return -1; }
6282 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
6283 // BTMM domains, then bring down the connection to the relay.
6284 mDNSlocal
void UpdateBTMMRelayConnection(mDNS
*const m
)
6286 DomainAuthInfo
*BTMMDomain
= mDNSNULL
;
6287 DomainAuthInfo
*FoundInList
;
6288 static mDNSBool AWACSDConnected
= mDNSfalse
;
6289 char AllUsers
[1024]; // maximum size of mach message
6290 char AllPass
[1024]; // maximum size of mach message
6291 char username
[MAX_DOMAIN_LABEL
+ 1];
6295 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
6296 // we may not be able to send the dns queries over the relay connection which may be needed
6297 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
6298 // need to make sure that we send the disconnect before attempting the next connect as the
6299 // awacs connections are redirected based on usernames.
6301 // For now we send a disconnect immediately. When we start sending dns queries over the relay
6302 // connection, we will need to fix this.
6304 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
6305 if (!FoundInList
->deltime
&& FoundInList
->AutoTunnel
&& IsBTMMDomain(&FoundInList
->domain
))
6307 // We need the passwd from the first domain.
6308 BTMMDomain
= FoundInList
;
6309 ConvertDomainLabelToCString_unescaped((domainlabel
*)BTMMDomain
->domain
.c
, username
);
6310 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username
, BTMMDomain
->domain
.c
);
6311 if (AddOneItem(AllUsers
, sizeof(AllUsers
), username
, &currulen
) == -1) break;
6312 if (AddOneItem(AllPass
, sizeof(AllPass
), BTMMDomain
->b64keydata
, &currplen
) == -1) break;
6317 // In the normal case (where we neither exceed the buffer size nor write bytes that
6318 // fit exactly into the buffer), currulen/currplen should be a different size than
6319 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
6321 if (currulen
!= (int)(sizeof(AllUsers
) - 1)) AllUsers
[currulen
- 1] = 0;
6322 if (currplen
!= (int)(sizeof(AllPass
) - 1)) AllPass
[currplen
- 1] = 0;
6324 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers
);
6325 AWACS_Connect(AllUsers
, AllPass
, "hello.connectivity.me.com");
6326 AWACSDConnected
= mDNStrue
;
6330 // Disconnect only if we connected previously
6331 if (AWACSDConnected
)
6333 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
6335 AWACSDConnected
= mDNSfalse
;
6337 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
6341 mDNSlocal
void UpdateBTMMRelayConnection(mDNS
*const m
)
6344 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
6346 #endif // ! NO_AWACS
6348 mDNSlocal
void ProcessConndConfigChanges(void);
6350 #endif // MDNSRESPONDER_BTMM_SUPPORT
6352 // MUST be called holding the lock
6353 mDNSlocal
void SetDomainSecrets_internal(mDNS
*m
)
6355 #ifdef NO_SECURITYFRAMEWORK
6357 LogMsg("Note: SetDomainSecrets: no keychain support");
6359 mDNSBool haveAutoTunnels
= mDNSfalse
;
6361 LogInfo("SetDomainSecrets");
6363 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
6364 // In the case where the user simultaneously removes their DDNS host name and the key
6365 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
6366 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
6367 // address records behind that we no longer have permission to delete.
6368 DomainAuthInfo
*ptr
;
6369 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
6370 ptr
->deltime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
*10);
6372 #if APPLE_OSX_mDNSResponder
6374 // Mark all TunnelClients for deletion
6375 ClientTunnel
*client
;
6376 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
6378 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client
->dstname
.c
);
6379 client
->MarkedForDeletion
= mDNStrue
;
6382 #endif // APPLE_OSX_mDNSResponder
6384 // String Array used to write list of private domains to Dynamic Store
6385 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6386 if (!sa
) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
6388 CFDataRef data
= NULL
;
6389 const int itemsPerEntry
= 4; // domain name, key name, key value, Name value
6390 CFArrayRef secrets
= NULL
;
6391 int err
= mDNSKeychainGetSecrets(&secrets
);
6392 if (err
|| !secrets
)
6393 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err
, secrets
);
6396 CFIndex ArrayCount
= CFArrayGetCount(secrets
);
6397 // Iterate through the secrets
6398 for (i
= 0; i
< ArrayCount
; ++i
)
6400 mDNSBool AutoTunnel
;
6402 CFArrayRef entry
= CFArrayGetValueAtIndex(secrets
, i
);
6403 if (CFArrayGetTypeID() != CFGetTypeID(entry
) || itemsPerEntry
!= CFArrayGetCount(entry
))
6404 { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i
, itemsPerEntry
); continue; }
6405 for (j
= 0; j
< CFArrayGetCount(entry
); ++j
)
6406 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry
, j
)))
6407 { LogMsg("SetDomainSecrets: malformed entry item %d", j
); continue; }
6409 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
6411 // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
6412 // Get DNS domain this key is for (kmDNSKcWhere)
6413 char stringbuf
[MAX_ESCAPED_DOMAIN_NAME
+ sizeof(btmmprefix
)];
6414 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcWhere
);
6415 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
6416 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data
)); continue; }
6417 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
6418 stringbuf
[CFDataGetLength(data
)] = '\0';
6420 AutoTunnel
= mDNSfalse
;
6422 if (!strncmp(stringbuf
, dnsprefix
, strlen(dnsprefix
)))
6423 offset
= strlen(dnsprefix
);
6424 #if MDNSRESPONDER_BTMM_SUPPORT
6425 else if (!strncmp(stringbuf
, btmmprefix
, strlen(btmmprefix
)))
6427 AutoTunnel
= mDNStrue
;
6428 offset
= strlen(btmmprefix
);
6432 if (!MakeDomainNameFromDNSNameString(&domain
, stringbuf
+ offset
)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf
); continue; }
6434 // Get key name (kmDNSKcAccount)
6435 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcAccount
);
6436 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
6437 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data
)); continue; }
6438 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)stringbuf
);
6439 stringbuf
[CFDataGetLength(data
)] = '\0';
6442 if (!MakeDomainNameFromDNSNameString(&keyname
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf
); continue; }
6444 // Get key data (kmDNSKcKey)
6445 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcKey
);
6446 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
6448 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data
));
6451 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
6452 stringbuf
[CFDataGetLength(data
)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
6454 // Get the Name of the keychain entry (kmDNSKcName) host or host:port
6455 // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
6456 char hostbuf
[MAX_ESCAPED_DOMAIN_NAME
+ 6]; // Max legal domainname as C-string, including terminating NUL
6457 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcName
);
6458 if (CFDataGetLength(data
) >= (int)sizeof(hostbuf
))
6460 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data
));
6463 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)hostbuf
);
6464 hostbuf
[CFDataGetLength(data
)] = '\0';
6466 domainname hostname
;
6469 hptr
= strchr(hostbuf
, ':');
6471 port
.NotAnInteger
= 0;
6478 while(hptr
&& *hptr
!= 0)
6480 if (*hptr
< '0' || *hptr
> '9')
6481 { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr
, val
); val
= 0; break;}
6482 val
= val
* 10 + *hptr
- '0';
6487 port
.NotAnInteger
= p
[0] << 8 | p
[1];
6489 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
6490 hptr
= strchr(hostbuf
, '@');
6495 if (!MakeDomainNameFromDNSNameString(&hostname
, hptr
)) { LogMsg("SetDomainSecrets: bad host name %s", hptr
); continue; }
6497 DomainAuthInfo
*FoundInList
;
6498 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
6499 if (SameDomainName(&FoundInList
->domain
, &domain
)) break;
6501 #if APPLE_OSX_mDNSResponder
6504 // If any client tunnel destination is in this domain, set deletion flag to false
6505 ClientTunnel
*client
;
6506 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
6507 if (FoundInList
== GetAuthInfoForName_internal(m
, &client
->dstname
))
6509 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client
->dstname
.c
);
6510 client
->MarkedForDeletion
= mDNSfalse
;
6514 #endif // APPLE_OSX_mDNSResponder
6516 // Uncomment the line below to view the keys as they're read out of the system keychain
6517 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
6518 //LogInfo("SetDomainSecrets: domain %##s keyname %##s key %s hostname %##s port %d", &domain.c, &keyname.c, stringbuf, hostname.c, (port.b[0] << 8 | port.b[1]));
6519 LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain
.c
, &keyname
.c
, hostname
.c
, (port
.b
[0] << 8 | port
.b
[1]));
6521 // If didn't find desired domain in the list, make a new entry
6523 if (FoundInList
&& FoundInList
->AutoTunnel
&& haveAutoTunnels
== mDNSfalse
) haveAutoTunnels
= mDNStrue
;
6526 ptr
= (DomainAuthInfo
*)mallocL("DomainAuthInfo", sizeof(*ptr
));
6527 if (!ptr
) { LogMsg("SetDomainSecrets: No memory"); continue; }
6530 //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
6532 // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
6533 if (mDNS_SetSecretForDomain(m
, ptr
, &domain
, &keyname
, stringbuf
, &hostname
, &port
, AutoTunnel
) == mStatus_BadParamErr
)
6535 if (!FoundInList
) mDNSPlatformMemFree(ptr
); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
6539 ConvertDomainNameToCString(&domain
, stringbuf
);
6540 CFStringRef cfs
= CFStringCreateWithCString(NULL
, stringbuf
, kCFStringEncodingUTF8
);
6541 if (cfs
) { CFArrayAppendValue(sa
, cfs
); CFRelease(cfs
); }
6546 if (!privateDnsArray
|| !CFEqual(privateDnsArray
, sa
))
6548 if (privateDnsArray
)
6549 CFRelease(privateDnsArray
);
6551 privateDnsArray
= sa
;
6552 CFRetain(privateDnsArray
);
6553 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, mDNSNULL
, privateDnsArray
);
6557 #if APPLE_OSX_mDNSResponder
6559 // clean up ClientTunnels
6560 ClientTunnel
**pp
= &m
->TunnelClients
;
6563 if ((*pp
)->MarkedForDeletion
)
6565 ClientTunnel
*cur
= *pp
;
6566 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur
, cur
->dstname
.c
);
6567 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
6568 AutoTunnelSetKeys(cur
, mDNSfalse
);
6570 freeL("ClientTunnel", cur
);
6576 mDNSBool needAutoTunnelNAT
= mDNSfalse
;
6577 DomainAuthInfo
*info
;
6578 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
6580 if (info
->AutoTunnel
)
6582 UpdateAutoTunnelDeviceInfoRecord(m
, info
);
6583 UpdateAutoTunnelHostRecord(m
, info
);
6584 UpdateAutoTunnelServiceRecords(m
, info
);
6585 UpdateAutoTunnel6Record(m
, info
);
6588 if (info
->AutoTunnelServiceStarted
) info
->AutoTunnelServiceStarted
= mDNSfalse
;
6590 else if (info
->AutoTunnelServiceStarted
)
6591 needAutoTunnelNAT
= true;
6593 UpdateAutoTunnelDomainStatus(info
);
6597 // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
6598 if (!needAutoTunnelNAT
&& m
->AutoTunnelNAT
.clientContext
)
6600 // stop the NAT operation, reset port, cleanup state
6601 mDNS_StopNATOperation_internal(m
, &m
->AutoTunnelNAT
);
6602 m
->AutoTunnelNAT
.ExternalAddress
= zerov4Addr
;
6603 m
->AutoTunnelNAT
.NewAddress
= zerov4Addr
;
6604 m
->AutoTunnelNAT
.ExternalPort
= zeroIPPort
;
6605 m
->AutoTunnelNAT
.RequestedPort
= zeroIPPort
;
6606 m
->AutoTunnelNAT
.Lifetime
= 0;
6607 m
->AutoTunnelNAT
.Result
= mStatus_NoError
;
6608 m
->AutoTunnelNAT
.clientContext
= mDNSNULL
;
6611 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
6612 #if MDNSRESPONDER_BTMM_SUPPORT
6613 ProcessConndConfigChanges(); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
6616 #endif // APPLE_OSX_mDNSResponder
6618 CheckSuppressUnusableQuestions(m
);
6620 #endif /* NO_SECURITYFRAMEWORK */
6623 mDNSexport
void SetDomainSecrets(mDNS
*m
)
6626 // Don't get secrets for BTMM if running in debug mode
6627 if (!IsDebugSocketInUse())
6629 SetDomainSecrets_internal(m
);
6632 mDNSlocal
void SetLocalDomains(void)
6634 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6635 if (!sa
) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
6637 CFArrayAppendValue(sa
, CFSTR("local"));
6638 CFArrayAppendValue(sa
, CFSTR("254.169.in-addr.arpa"));
6639 CFArrayAppendValue(sa
, CFSTR("8.e.f.ip6.arpa"));
6640 CFArrayAppendValue(sa
, CFSTR("9.e.f.ip6.arpa"));
6641 CFArrayAppendValue(sa
, CFSTR("a.e.f.ip6.arpa"));
6642 CFArrayAppendValue(sa
, CFSTR("b.e.f.ip6.arpa"));
6644 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig
, mDNSNULL
, sa
);
6648 mDNSlocal
void GetCurrentPMSetting(const CFStringRef name
, mDNSs32
*val
)
6651 CFDictionaryRef dict
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_PowerSettings
);
6654 LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
6658 CFNumberRef number
= CFDictionaryGetValue(dict
, name
);
6659 if (!number
|| CFGetTypeID(number
) != CFNumberGetTypeID() || !CFNumberGetValue(number
, kCFNumberSInt32Type
, val
))
6666 #if APPLE_OSX_mDNSResponder
6668 static CFMutableDictionaryRef spsStatusDict
= NULL
;
6669 static const CFStringRef kMetricRef
= CFSTR("Metric");
6671 mDNSlocal
void SPSStatusPutNumber(CFMutableDictionaryRef dict
, const mDNSu8
* const ptr
, CFStringRef key
)
6673 mDNSu8 tmp
= (ptr
[0] - '0') * 10 + ptr
[1] - '0';
6674 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt8Type
, &tmp
);
6676 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
6679 CFDictionarySetValue(dict
, key
, num
);
6684 mDNSlocal CFMutableDictionaryRef
SPSCreateDict(const mDNSu8
* const ptr
)
6686 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
6687 if (!dict
) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict
; }
6690 buffer
[mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", ptr
) - 1] = 0;
6691 CFStringRef spsname
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
6692 if (!spsname
) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict
); return NULL
; }
6693 CFDictionarySetValue(dict
, CFSTR("FullName"), spsname
);
6696 if (ptr
[0] >= 2) SPSStatusPutNumber(dict
, ptr
+ 1, CFSTR("Type"));
6697 if (ptr
[0] >= 5) SPSStatusPutNumber(dict
, ptr
+ 4, CFSTR("Portability"));
6698 if (ptr
[0] >= 8) SPSStatusPutNumber(dict
, ptr
+ 7, CFSTR("MarginalPower"));
6699 if (ptr
[0] >= 11) SPSStatusPutNumber(dict
, ptr
+10, CFSTR("TotalPower"));
6701 mDNSu32 tmp
= SPSMetric(ptr
);
6702 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tmp
);
6704 LogMsg("SPSCreateDict: Could not create CFNumber");
6707 CFDictionarySetValue(dict
, kMetricRef
, num
);
6713 memcpy(buffer
, ptr
+ 13, ptr
[0] - 12);
6714 buffer
[ptr
[0] - 12] = 0;
6715 spsname
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
6716 if (!spsname
) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict
); return NULL
; }
6719 CFDictionarySetValue(dict
, CFSTR("PrettyName"), spsname
);
6727 mDNSlocal CFComparisonResult
CompareSPSEntries(const void *val1
, const void *val2
, void *context
)
6730 return CFNumberCompare((CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val1
, kMetricRef
),
6731 (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val2
, kMetricRef
),
6735 mDNSlocal
void UpdateSPSStatus(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
6737 NetworkInterfaceInfo
* info
= (NetworkInterfaceInfo
*)question
->QuestionContext
;
6738 debugf("UpdateSPSStatus: %s %##s %s %s", info
->ifname
, question
->qname
.c
, AddRecord
? "Add" : "Rmv", answer
? RRDisplayString(m
, answer
) : "<null>");
6741 mDNS_UpdateAllowSleep(m
);
6744 if (answer
&& SPSMetric(answer
->rdata
->u
.name
.c
) > 999999) return; // Ignore instances with invalid names
6748 spsStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
6749 if (!spsStatusDict
) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
6752 CFStringRef ifname
= CFStringCreateWithCString(NULL
, info
->ifname
, kCFStringEncodingUTF8
);
6753 if (!ifname
) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
6755 CFMutableArrayRef array
= NULL
;
6757 if (!CFDictionaryGetValueIfPresent(spsStatusDict
, ifname
, (const void**) &array
))
6759 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6760 if (!array
) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname
); return; }
6761 CFDictionarySetValue(spsStatusDict
, ifname
, array
);
6762 CFRelease(array
); // let go of our reference, now that the dict has one
6765 if (!array
) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info
->ifname
); CFRelease(ifname
); return; }
6767 if (!answer
) // special call that means the question has been stopped (because the interface is going away)
6768 CFArrayRemoveAllValues(array
);
6771 CFMutableDictionaryRef dict
= SPSCreateDict(answer
->rdata
->u
.name
.c
);
6772 if (!dict
) { CFRelease(ifname
); return; }
6776 if (!CFArrayContainsValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), dict
))
6779 for (i
=0; i
<CFArrayGetCount(array
); i
++)
6780 if (CompareSPSEntries(CFArrayGetValueAtIndex(array
, i
), dict
, NULL
) != kCFCompareLessThan
)
6782 CFArrayInsertValueAtIndex(array
, i
, dict
);
6784 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info
->ifname
, answer
->rdata
->u
.name
.c
);
6788 CFIndex i
= CFArrayGetFirstIndexOfValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), dict
);
6789 if (i
!= -1) CFArrayRemoveValueAtIndex(array
, i
);
6790 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info
->ifname
, answer
->rdata
->u
.name
.c
);
6796 if (!m
->ShutdownTime
) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState
, info
->ifname
, array
);
6801 mDNSlocal mDNSs32
GetSystemSleepTimerSetting(void)
6804 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL
, NULL
);
6806 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6809 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_PowerSettings
);
6812 CFNumberRef number
= CFDictionaryGetValue(dict
, CFSTR("System Sleep Timer"));
6813 if (number
) CFNumberGetValue(number
, kCFNumberSInt32Type
, &val
);
6821 mDNSlocal
void SetSPS(mDNS
*const m
)
6824 // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
6825 mDNSu8 sps
= (OfferSleepProxyService
&& GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware
: 0;
6827 // For devices that are not running NAT, but are set to never sleep, we may choose to act
6828 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
6829 //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
6831 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
6833 // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
6834 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
6835 // We rate such a device as metric 70 ("Incidentally Available Hardware")
6836 if (SPMetricMarginalPower
<= 60 && !sps
) sps
= mDNSSleepProxyMetric_IncidentalHardware
;
6838 // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
6839 // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
6840 if (sps
&& OfferSleepProxyService
&& OfferSleepProxyService
< 100) sps
= OfferSleepProxyService
;
6842 #ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI
6843 // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active.
6846 NetworkInterfaceInfo
*intf
= mDNSNULL
;
6847 mDNSEthAddr bssid
= zeroEthAddr
;
6848 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
6850 if (intf
->InterfaceID
== AWDLInterfaceID
) continue;
6851 bssid
= GetBSSID(intf
->ifname
);
6852 if (!mDNSSameEthAddress(&bssid
, &zeroEthAddr
))
6854 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
6860 #endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI
6862 mDNSCoreBeSleepProxyServer(m
, sps
, SPMetricPortability
, SPMetricMarginalPower
, SPMetricTotalPower
, SPMetricFeatures
);
6865 // The definitions below should eventually come from some externally-supplied header file.
6866 // However, since these definitions can't really be changed without breaking binary compatibility,
6867 // they should never change, so in practice it should not be a big problem to have them defined here.
6870 { // commands from the daemon to the driver
6871 cmd_mDNSOffloadRR
= 21, // give the mdns update buffer to the driver
6874 typedef union { void *ptr
; mDNSOpaque64 sixtyfourbits
; } FatPtr
;
6877 { // cmd_mDNSOffloadRR structure
6878 uint32_t command
; // set to OffloadRR
6879 uint32_t rrBufferSize
; // number of bytes of RR records
6880 uint32_t numUDPPorts
; // number of SRV UDP ports
6881 uint32_t numTCPPorts
; // number of SRV TCP ports
6882 uint32_t numRRRecords
; // number of RR records
6883 uint32_t compression
; // rrRecords - compression is base for compressed strings
6884 FatPtr rrRecords
; // address of array of pointers to the rr records
6885 FatPtr udpPorts
; // address of udp port list (SRV)
6886 FatPtr tcpPorts
; // address of tcp port list (SRV)
6889 #include <IOKit/IOKitLib.h>
6890 #include <dns_util.h>
6892 mDNSlocal mDNSu32
GetPortArray(int trans
, mDNSIPPort
*portarray
)
6894 mDNS
*const m
= &mDNSStorage
;
6895 const domainlabel
*const tp
= (trans
== mDNSTransport_UDP
) ? (const domainlabel
*)"\x4_udp" : (const domainlabel
*)"\x4_tcp";
6899 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6901 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainLabel(ThirdLabel(rr
->resrec
.name
)->c
, tp
->c
))
6908 for (i
= 0; i
< count
; i
++)
6909 if (mDNSSameIPPort(portarray
[i
], rr
->resrec
.rdata
->u
.srv
.port
))
6912 // Add it into the port list only if it not already present in the list
6914 portarray
[count
++] = rr
->resrec
.rdata
->u
.srv
.port
;
6919 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
6920 if (trans
== mDNSTransport_UDP
&& m
->AutoTunnelNAT
.clientContext
)
6922 LogSPS("GetPortArray Back to My Mac at %u", count
);
6923 if (portarray
) portarray
[count
] = IPSECPort
;
6929 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6930 mDNSlocal mDNSBool
SupportsTCPKeepAlive()
6932 IOReturn ret
= kIOReturnSuccess
;
6933 CFTypeRef obj
= NULL
;
6934 mDNSBool supports
= mDNSfalse
;
6936 ret
= IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj
);
6937 if ((kIOReturnSuccess
== ret
) && (obj
!= NULL
))
6939 supports
= (obj
== kCFBooleanTrue
)? mDNStrue
: mDNSfalse
;
6942 LogSPS("%s: The hardware %s TCP Keep Alive", __func__
, (supports
? "supports" : "does not support"));
6946 mDNSlocal mDNSBool
OnBattery(void)
6948 CFTypeRef powerInfo
= IOPSCopyPowerSourcesInfo();
6949 CFTypeRef powerSrc
= IOPSGetProvidingPowerSourceType(powerInfo
);
6950 mDNSBool result
= mDNSfalse
;
6952 if (powerInfo
!= NULL
)
6954 result
= CFEqual(CFSTR(kIOPSBatteryPowerValue
), powerSrc
);
6955 CFRelease(powerInfo
);
6957 LogSPS("%s: The system is on %s", __func__
, (result
)? "Battery" : "AC Power");
6961 #endif // !TARGET_OS_EMBEDDED
6963 #define TfrRecordToNIC(RR) \
6964 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
6966 mDNSlocal mDNSu32
CountProxyRecords(uint32_t *const numbytes
, mDNSBool TCPKAOnly
, mDNSBool supportsTCPKA
)
6968 mDNS
*const m
= &mDNSStorage
;
6971 mDNSBool isKeepAliveRecord
= mDNSfalse
;
6975 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6977 if (!(rr
->AuthFlags
& AuthFlagsWakeOnly
) && rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
6979 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6980 isKeepAliveRecord
= mDNS_KeepaliveRecord(&rr
->resrec
);
6981 // Skip over all other records if we are registering TCP KeepAlive records only
6982 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
6983 if ((TCPKAOnly
&& !isKeepAliveRecord
) || (isKeepAliveRecord
&& !supportsTCPKA
))
6986 (void) TCPKAOnly
; // unused
6987 (void) supportsTCPKA
; // unused
6989 if (TfrRecordToNIC(rr
))
6991 // For KeepAlive records, use an estimated length of 256, which is the maximum size.
6992 const uint32_t rdataLen
= isKeepAliveRecord
? ((uint32_t)sizeof(UTF8str255
)) : rr
->resrec
.rdestimate
;
6993 const uint32_t recordSize
= DomainNameLength(rr
->resrec
.name
) + 10 + rdataLen
;
6994 *numbytes
+= recordSize
;
6995 LogSPS("CountProxyRecords: %3u size %5u total %5u %s", count
, recordSize
, *numbytes
, ARDisplayString(m
,rr
));
7003 mDNSlocal
void GetProxyRecords(DNSMessage
*const msg
, uint32_t *const numbytes
, FatPtr
*const records
,
7004 uint32_t *outRecordCount
, NetworkInterfaceInfo
*const intf
, mDNSBool TCPKAOnly
, mDNSBool supportsTCPKA
)
7006 mDNS
*const m
= &mDNSStorage
;
7007 mDNSu8
*p
= msg
->data
;
7008 const mDNSu8
*const limit
= p
+ *numbytes
;
7009 InitializeDNSMessage(&msg
->h
, zeroID
, zeroID
);
7014 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
7016 if (!(rr
->AuthFlags
& AuthFlagsWakeOnly
) && rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
7018 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7019 const mDNSBool isKeepAliveRecord
= mDNS_KeepaliveRecord(&rr
->resrec
);
7021 // Skip over all other records if we are registering TCP KeepAlive records only
7022 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
7023 if ((TCPKAOnly
&& !isKeepAliveRecord
) || (isKeepAliveRecord
&& !supportsTCPKA
))
7026 // Update the record before calculating the number of bytes required
7027 // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
7028 // attempt to update the record again.
7029 if (isKeepAliveRecord
)
7031 if (UpdateKeepaliveRData(m
, rr
, intf
, mDNSfalse
, mDNSNULL
) != mStatus_NoError
)
7033 LogSPS("GetProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m
, rr
));
7036 // Offload only Valid Keepalive records
7037 if (!mDNSValidKeepAliveRecord(rr
))
7043 (void) intf
; // unused
7044 (void) TCPKAOnly
; // unused
7045 (void) supportsTCPKA
; // unused
7046 #endif // APPLE_OSX_mDNSResponder
7048 if (TfrRecordToNIC(rr
))
7050 records
[count
].sixtyfourbits
= zeroOpaque64
;
7051 records
[count
].ptr
= p
;
7052 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
7053 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the 'unique' bit so PutResourceRecord will set it
7054 p
= PutResourceRecordTTLWithLimit(msg
, p
, &msg
->h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
, limit
);
7055 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear 'unique' bit back to normal state
7056 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
7057 count
, records
[count
].ptr
, p
, p
- (mDNSu8
*)records
[count
].ptr
, p
- msg
->data
, ARDisplayString(m
,rr
));
7062 *numbytes
= p
- msg
->data
;
7063 if (outRecordCount
) *outRecordCount
= count
;
7066 mDNSexport mDNSBool
SupportsInNICProxy(NetworkInterfaceInfo
*const intf
)
7068 if(!UseInternalSleepProxy
)
7070 LogMsg("SupportsInNICProxy: Internal Sleep Proxy is disabled");
7073 return CheckInterfaceSupport(intf
, mDNS_IOREG_KEY
);
7076 // Called with the lock held
7077 mDNSexport mStatus
ActivateLocalProxy(NetworkInterfaceInfo
*const intf
, mDNSBool offloadKeepAlivesOnly
, mDNSBool
*keepaliveOnly
)
7079 mStatus result
= mStatus_UnknownErr
;
7080 mDNSBool TCPKAOnly
= mDNSfalse
;
7081 mDNSBool supportsTCPKA
= mDNSfalse
;
7082 io_service_t service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOBSDNameMatching(kIOMasterPortDefault
, 0, intf
->ifname
));
7084 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7085 // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
7086 supportsTCPKA
= (InterfaceSupportsKeepAlive(intf
) && SupportsTCPKeepAlive()) ? mDNStrue
: mDNSfalse
;
7087 if (!offloadKeepAlivesOnly
)
7089 // Only TCP Keepalive records are to be offloaded if
7090 // - The system is on battery
7091 // - OR wake for network access is not set but powernap is enabled
7092 TCPKAOnly
= supportsTCPKA
&& ((mDNSStorage
.SystemWakeOnLANEnabled
== mDNS_WakeOnBattery
) || OnBattery());
7096 TCPKAOnly
= mDNStrue
;
7099 (void)offloadKeepAlivesOnly
; // Unused.
7101 if (!service
) { LogMsg("ActivateLocalProxy: No service for interface %s", intf
->ifname
); return(mStatus_UnknownErr
); }
7104 IOObjectGetClass(service
, n1
);
7108 kern_return_t kr
= RegistryEntrySearchCFPropertyAndIOObject(service
, kIOServicePlane
, CFSTR(mDNS_IOREG_KEY
), &ref
, &parent
);
7109 IOObjectRelease(service
);
7110 if (kr
!= KERN_SUCCESS
) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s kr %d", intf
->ifname
, n1
, kr
);
7113 IOObjectGetClass(parent
, n2
);
7114 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf
->ifname
, n1
, n2
);
7116 if (CFGetTypeID(ref
) != CFStringGetTypeID() || !CFEqual(ref
, CFSTR(mDNS_IOREG_VALUE
)))
7117 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
7118 intf
->ifname
, n1
, n2
, CFStringGetCStringPtr(ref
, mDNSNULL
), mDNS_IOREG_VALUE
);
7119 else if (!UseInternalSleepProxy
)
7120 LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf
->ifname
);
7123 io_connect_t conObj
;
7124 kr
= IOServiceOpen(parent
, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE
, &conObj
);
7125 if (kr
!= KERN_SUCCESS
) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf
->ifname
, n1
, n2
, kr
);
7129 mDNSPlatformMemZero(&cmd
, sizeof(cmd
)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
7130 cmd
.command
= cmd_mDNSOffloadRR
;
7131 cmd
.numUDPPorts
= TCPKAOnly
? 0 : GetPortArray(mDNSTransport_UDP
, mDNSNULL
);
7132 cmd
.numTCPPorts
= TCPKAOnly
? 0 : GetPortArray(mDNSTransport_TCP
, mDNSNULL
);
7133 cmd
.numRRRecords
= CountProxyRecords(&cmd
.rrBufferSize
, TCPKAOnly
, supportsTCPKA
);
7134 cmd
.compression
= sizeof(DNSMessageHeader
);
7136 DNSMessage
*msg
= (DNSMessage
*)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader
) + cmd
.rrBufferSize
);
7137 cmd
.rrRecords
.ptr
= cmd
.numRRRecords
? mallocL("mDNSOffloadCmd rrRecords", cmd
.numRRRecords
* sizeof(FatPtr
)) : NULL
;
7138 cmd
.udpPorts
.ptr
= cmd
.numUDPPorts
? mallocL("mDNSOffloadCmd udpPorts" , cmd
.numUDPPorts
* sizeof(mDNSIPPort
)) : NULL
;
7139 cmd
.tcpPorts
.ptr
= cmd
.numTCPPorts
? mallocL("mDNSOffloadCmd tcpPorts" , cmd
.numTCPPorts
* sizeof(mDNSIPPort
)) : NULL
;
7141 LogSPS("ActivateLocalProxy: msg %p %u RR %p %u, UDP %p %u, TCP %p %u",
7142 msg
, cmd
.rrBufferSize
,
7143 cmd
.rrRecords
.ptr
, cmd
.numRRRecords
,
7144 cmd
.udpPorts
.ptr
, cmd
.numUDPPorts
,
7145 cmd
.tcpPorts
.ptr
, cmd
.numTCPPorts
);
7147 if (msg
&& cmd
.rrRecords
.ptr
)
7149 GetProxyRecords(msg
, &cmd
.rrBufferSize
, cmd
.rrRecords
.ptr
, &cmd
.numRRRecords
, intf
, TCPKAOnly
, supportsTCPKA
);
7151 if (cmd
.udpPorts
.ptr
) cmd
.numUDPPorts
= TCPKAOnly
? 0 : GetPortArray(mDNSTransport_UDP
, cmd
.udpPorts
.ptr
);
7152 if (cmd
.tcpPorts
.ptr
) cmd
.numTCPPorts
= TCPKAOnly
? 0 : GetPortArray(mDNSTransport_TCP
, cmd
.tcpPorts
.ptr
);
7155 size_t outputDataSize
= sizeof(outputData
);
7156 kr
= IOConnectCallStructMethod(conObj
, 0, &cmd
, sizeof(cmd
), outputData
, &outputDataSize
);
7157 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf
->ifname
, n1
, n2
, kr
);
7158 if (kr
== KERN_SUCCESS
) result
= mStatus_NoError
;
7160 if (cmd
.tcpPorts
.ptr
) freeL("mDNSOffloadCmd udpPorts", cmd
.tcpPorts
.ptr
);
7161 if (cmd
.udpPorts
.ptr
) freeL("mDNSOffloadCmd tcpPorts", cmd
.udpPorts
.ptr
);
7162 if (cmd
.rrRecords
.ptr
) freeL("mDNSOffloadCmd rrRecords", cmd
.rrRecords
.ptr
);
7163 if (msg
) freeL("mDNSOffloadCmd msg", msg
);
7164 IOServiceClose(conObj
);
7168 IOObjectRelease(parent
);
7170 *keepaliveOnly
= (TCPKAOnly
&& supportsTCPKA
) ? mDNStrue
: mDNSfalse
;
7174 #endif // APPLE_OSX_mDNSResponder
7176 mDNSlocal mDNSu8
SystemWakeForNetworkAccess(void)
7179 mDNSu8 ret
= (mDNSu8
)mDNS_NoWake
;
7182 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7186 if (DisableSleepProxyClient
)
7188 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7192 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val
);
7194 ret
= (mDNSu8
)(val
!= 0) ? mDNS_WakeOnAC
: mDNS_NoWake
;
7196 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7197 // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
7198 // Further policy decisions on whether to offload the records is handled during sleep processing.
7199 if ((ret
== mDNS_NoWake
) && SupportsTCPKeepAlive())
7200 ret
= (mDNSu8
)mDNS_WakeOnBattery
;
7201 #endif // APPLE_OSX_mDNSResponder
7203 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret
);
7207 mDNSlocal mDNSBool
SystemSleepOnlyIfWakeOnLAN(void)
7210 // PrioritizeNetworkReachabilityOverSleep has been deprecated.
7211 // GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
7212 // Statically set the PrioritizeNetworkReachabilityOverSleep value to 1 for AppleTV
7215 return val
!= 0 ? mDNStrue
: mDNSfalse
;
7219 #if APPLE_OSX_mDNSResponder
7220 // When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
7221 // gets deregistered, so that older peers are forced to connect over direct UDP instead of
7224 // When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
7225 // service records are deregistered, so they do not appear in peers' Finder sidebars.
7226 // We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
7227 // depend on their associated SRV record and therefore will be deregistered together in a
7228 // single update with the SRV record.
7230 // Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
7231 // its presence shouldn't delay sleep.
7233 // Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
7234 // relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
7236 // Also note that returning false here will not delay sleep past the maximum of 10 seconds.
7237 mDNSexport mDNSBool
RecordReadyForSleep(AuthRecord
*rr
)
7239 mDNS
*const m
= &mDNSStorage
;
7240 if (!AuthRecord_uDNS(rr
)) return mDNStrue
;
7242 if ((rr
->resrec
.rrtype
== kDNSType_AAAA
) && SameDomainLabel(rr
->namestorage
.c
, (const mDNSu8
*)"\x0c_autotunnel6"))
7244 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m
, rr
));
7248 if ((mDNSIPPortIsZero(m
->AutoTunnelNAT
.ExternalPort
) || m
->AutoTunnelNAT
.Result
))
7250 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& rr
->state
!= regState_NoTarget
&& rr
->zone
7251 && !SameDomainLabel(rr
->namestorage
.c
, (const mDNSu8
*)"\x0b_autotunnel"))
7253 DomainAuthInfo
*info
= GetAuthInfoForName_internal(m
, rr
->zone
);
7254 if (info
&& info
->AutoTunnel
)
7256 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m
, rr
));
7265 // Caller must hold the lock
7266 mDNSexport
void RemoveAutoTunnel6Record(mDNS
*const m
)
7268 DomainAuthInfo
*info
;
7269 // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
7270 // deregister the record, and the MemFree callback won't re-register.
7271 m
->AutoTunnelRelayAddr
= zerov6Addr
;
7272 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
7273 if (info
->AutoTunnel
)
7274 UpdateAutoTunnel6Record(m
, info
);
7276 #endif /* APPLE_OSX_mDNSResponder */
7278 #if MDNSRESPONDER_BTMM_SUPPORT
7279 mDNSlocal mDNSBool
IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr
, char *ifname
)
7281 struct ifaddrs
*ifa
;
7282 struct ifaddrs
*ifaddrs
;
7285 if (if_nametoindex(ifname
) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname
); return mDNSfalse
;}
7287 if (getifaddrs(&ifaddrs
) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse
;}
7289 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
7291 if (strncmp(ifa
->ifa_name
, ifname
, IFNAMSIZ
) != 0)
7293 if ((ifa
->ifa_flags
& IFF_UP
) == 0 || !ifa
->ifa_addr
|| ifa
->ifa_addr
->sa_family
!= AF_INET6
)
7295 if (SetupAddr(&addr
, ifa
->ifa_addr
) != mStatus_NoError
)
7297 LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
7300 if (mDNSSameIPv6Address(ipv6Addr
, *(mDNSv6Addr
*)&addr
.ip
.v6
))
7302 LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr
);
7306 freeifaddrs(ifaddrs
);
7310 mDNSlocal mDNSv6Addr
IPv6AddressFromString(char* buf
)
7313 struct addrinfo hints
;
7314 struct addrinfo
*res0
;
7316 memset(&hints
, 0, sizeof(hints
));
7317 hints
.ai_family
= AF_INET6
;
7318 hints
.ai_flags
= AI_NUMERICHOST
;
7320 int err
= getaddrinfo(buf
, NULL
, &hints
, &res0
);
7324 retVal
= *(mDNSv6Addr
*)&((struct sockaddr_in6
*)res0
->ai_addr
)->sin6_addr
;
7331 mDNSlocal CFDictionaryRef
CopyConnectivityBackToMyMacDict()
7333 CFDictionaryRef connd
= NULL
;
7334 CFDictionaryRef BTMMDict
= NULL
;
7336 connd
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_BTMMConnectivity
);
7339 LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
7343 BTMMDict
= CFDictionaryGetValue(connd
, CFSTR("BackToMyMac"));
7346 LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
7350 // Non-dictionary is treated as non-existent dictionary
7351 if (CFGetTypeID(BTMMDict
) != CFDictionaryGetTypeID())
7354 LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
7361 if (connd
) CFRelease(connd
);
7366 #define MAX_IPV6_TEXTUAL 40
7368 mDNSlocal mDNSv6Addr
ParseBackToMyMacAddr(CFDictionaryRef BTMMDict
, CFStringRef ifKey
, CFStringRef addrKey
)
7370 mDNSv6Addr retVal
= zerov6Addr
;
7371 CFTypeRef string
= NULL
;
7372 char ifname
[IFNAMSIZ
];
7373 char address
[MAX_IPV6_TEXTUAL
];
7378 if (!CFDictionaryGetValueIfPresent(BTMMDict
, ifKey
, &string
))
7380 LogInfo("ParseBackToMyMacAddr: interface key does not exist");
7384 if (!CFStringGetCString(string
, ifname
, IFNAMSIZ
, kCFStringEncodingUTF8
))
7386 LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
7390 if (!CFDictionaryGetValueIfPresent(BTMMDict
, addrKey
, &string
))
7392 LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
7396 if (!CFStringGetCString(string
, address
, sizeof(address
), kCFStringEncodingUTF8
))
7398 LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
7402 retVal
= IPv6AddressFromString(address
);
7403 LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname
, address
, &retVal
);
7405 if (mDNSIPv6AddressIsZero(retVal
))
7408 if (!IPv6AddressIsOnInterface(retVal
, ifname
))
7410 LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal
, ifname
);
7417 mDNSlocal CFDictionaryRef
GetBackToMyMacZones(CFDictionaryRef BTMMDict
)
7419 CFTypeRef zones
= NULL
;
7424 if (!CFDictionaryGetValueIfPresent(BTMMDict
, CFSTR("Zones"), &zones
))
7426 LogInfo("CopyBTMMZones: Zones key does not exist");
7433 mDNSlocal mDNSv6Addr
ParseBackToMyMacZone(CFDictionaryRef zones
, DomainAuthInfo
* info
)
7435 mDNSv6Addr addr
= zerov6Addr
;
7436 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
7437 CFStringRef domain
= NULL
;
7438 CFTypeRef theZone
= NULL
;
7443 ConvertDomainNameToCString(&info
->domain
, buffer
);
7444 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
7448 if (CFDictionaryGetValueIfPresent(zones
, domain
, &theZone
))
7449 addr
= ParseBackToMyMacAddr(theZone
, CFSTR("Interface"), CFSTR("Address"));
7456 mDNSlocal
void SetupBackToMyMacInnerAddresses(CFDictionaryRef BTMMDict
)
7458 mDNS
*const m
= &mDNSStorage
;
7459 DomainAuthInfo
* info
;
7460 CFDictionaryRef zones
= GetBackToMyMacZones(BTMMDict
);
7463 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
7465 if (!info
->AutoTunnel
)
7468 newAddr
= ParseBackToMyMacZone(zones
, info
);
7470 if (mDNSSameIPv6Address(newAddr
, info
->AutoTunnelInnerAddress
))
7473 info
->AutoTunnelInnerAddress
= newAddr
;
7474 DeregisterAutoTunnelHostRecord(m
, info
);
7475 UpdateAutoTunnelHostRecord(m
, info
);
7476 UpdateAutoTunnelDomainStatus(info
);
7480 // MUST be called holding the lock
7481 mDNSlocal
void ProcessConndConfigChanges(void)
7483 mDNS
*const m
= &mDNSStorage
;
7484 CFDictionaryRef dict
= CopyConnectivityBackToMyMacDict();
7486 LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
7487 mDNSv6Addr relayAddr
= ParseBackToMyMacAddr(dict
, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
7489 LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr
);
7491 SetupBackToMyMacInnerAddresses(dict
);
7493 if (dict
) CFRelease(dict
);
7495 if (!mDNSSameIPv6Address(relayAddr
, m
->AutoTunnelRelayAddr
))
7497 m
->AutoTunnelRelayAddr
= relayAddr
;
7499 DomainAuthInfo
* info
;
7500 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
7501 if (info
->AutoTunnel
)
7503 DeregisterAutoTunnel6Record(m
, info
);
7504 UpdateAutoTunnel6Record(m
, info
);
7505 UpdateAutoTunnelDomainStatus(info
);
7508 // Determine whether we need racoon to accept incoming connections
7509 UpdateAnonymousRacoonConfig(m
);
7512 // If awacsd crashes or exits for some reason, restart it
7513 UpdateBTMMRelayConnection(m
);
7515 #endif // MDNSRESPONDER_BTMM_SUPPORT
7517 mDNSlocal mDNSBool
IsAppleNetwork(mDNS
*const m
)
7520 // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
7521 for (s
= m
->DNSServers
; s
; s
= s
->next
)
7523 if (s
->addr
.ip
.v4
.b
[0] == 17)
7525 LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s
->domain
.c
, &s
->addr
);
7532 // Called with KQueueLock & mDNS lock
7533 // SetNetworkChanged is allowed to shorten (but not extend) the pause while we wait for configuration changes to settle
7534 mDNSlocal
void SetNetworkChanged(mDNSs32 delay
)
7536 mDNS
*const m
= &mDNSStorage
;
7538 if (!m
->NetworkChanged
|| m
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) > 0)
7540 m
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
7541 LogInfo("SetNetworkChanged: Scheduling in %d ticks", delay
);
7544 LogInfo("SetNetworkChanged: *NOT* increasing delay from %d to %d", m
->NetworkChanged
- m
->timenow
, delay
);
7547 // Called with KQueueLock & mDNS lock
7548 mDNSlocal
void SetKeyChainTimer(mDNSs32 delay
)
7550 mDNS
*const m
= &mDNSStorage
;
7551 // If it's not set or it needs to happen sooner than when it's currently set
7552 if (!m
->p
->KeyChainTimer
|| m
->p
->KeyChainTimer
- NonZeroTime(m
->timenow
+ delay
) > 0)
7554 m
->p
->KeyChainTimer
= NonZeroTime(m
->timenow
+ delay
);
7555 LogInfo("SetKeyChainTimer: %d", delay
);
7559 mDNSexport
void mDNSMacOSXNetworkChanged(void)
7561 mDNS
*const m
= &mDNSStorage
;
7562 LogInfo("*** Network Configuration Change *** %d ticks late%s",
7563 m
->NetworkChanged
? mDNS_TimeNow(m
) - m
->NetworkChanged
: 0,
7564 m
->NetworkChanged
? "" : " (no scheduled configuration change)");
7565 m
->NetworkChanged
= 0; // If we received a network change event and deferred processing, we're now dealing with it
7567 // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring
7568 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
7571 mDNSBool tentative
= mDNSfalse
;
7572 struct ifaddrs
*ifa
= myGetIfAddrs(1);
7575 if (ifa
->ifa_addr
&& ifa
->ifa_addr
->sa_family
== AF_INET6
)
7577 struct in6_ifreq ifr6
;
7578 mDNSPlatformMemZero((char *)&ifr6
, sizeof(ifr6
));
7579 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
7580 ifr6
.ifr_addr
= *(struct sockaddr_in6
*)ifa
->ifa_addr
;
7581 // We need to check for IN6_IFF_TENTATIVE here, not IN6_IFF_NOTREADY, because
7582 // IN6_IFF_NOTREADY includes both IN6_IFF_TENTATIVE and IN6_IFF_DUPLICATED addresses.
7583 // We can expect that an IN6_IFF_TENTATIVE address will shortly become ready,
7584 // but an IN6_IFF_DUPLICATED address may not.
7585 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
7587 if (ifr6
.ifr_ifru
.ifru_flags6
& IN6_IFF_TENTATIVE
)
7589 LogInfo("*** Network Configuration Change *** IPv6 address %.16a TENTATIVE, will retry", &ifr6
.ifr_addr
.sin6_addr
);
7590 tentative
= mDNStrue
;
7591 // no need to check other interfaces if we already found out that one interface is TENTATIVE
7596 ifa
= ifa
->ifa_next
;
7602 SetNetworkChanged(mDNSPlatformOneSecond
/ 2);
7606 LogInfo("*** Network Configuration Change *** No IPv6 address TENTATIVE, will continue");
7609 mDNSs32 utc
= mDNSPlatformUTC();
7610 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
7611 m
->SystemSleepOnlyIfWakeOnLAN
= SystemSleepOnlyIfWakeOnLAN();
7612 MarkAllInterfacesInactive(utc
);
7613 UpdateInterfaceList(utc
);
7614 ClearInactiveInterfaces(utc
);
7615 SetupActiveInterfaces(utc
);
7616 ReorderInterfaceList();
7618 #if APPLE_OSX_mDNSResponder
7619 #if !TARGET_OS_EMBEDDED
7620 #if MDNSRESPONDER_BTMM_SUPPORT
7622 ProcessConndConfigChanges();
7626 // Scan to find client tunnels whose questions have completed,
7627 // but whose local inner/outer addresses have changed since the tunnel was set up
7629 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
7630 if (p
->q
.ThisQInterval
< 0)
7632 DomainAuthInfo
* info
= GetAuthInfoForName(m
, &p
->dstname
);
7635 LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p
->dstname
.c
);
7636 AutoTunnelSetKeys(p
, mDNSfalse
);
7640 mDNSv6Addr inner
= info
->AutoTunnelInnerAddress
;
7642 if (!mDNSIPPortIsZero(p
->rmt_outer_port
))
7644 mDNSAddr tmpSrc
= zeroAddr
;
7645 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
7646 tmpDst
.ip
.v4
= p
->rmt_outer
;
7647 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
7648 if (!mDNSSameIPv6Address(p
->loc_inner
, inner
) ||
7649 !mDNSSameIPv4Address(p
->loc_outer
, tmpSrc
.ip
.v4
))
7651 AutoTunnelSetKeys(p
, mDNSfalse
);
7652 p
->loc_inner
= inner
;
7653 p
->loc_outer
= tmpSrc
.ip
.v4
;
7654 AutoTunnelSetKeys(p
, mDNStrue
);
7659 if (!mDNSSameIPv6Address(p
->loc_inner
, inner
) ||
7660 !mDNSSameIPv6Address(p
->loc_outer6
, m
->AutoTunnelRelayAddr
))
7662 AutoTunnelSetKeys(p
, mDNSfalse
);
7663 p
->loc_inner
= inner
;
7664 p
->loc_outer6
= m
->AutoTunnelRelayAddr
;
7665 AutoTunnelSetKeys(p
, mDNStrue
);
7670 #endif //!TARGET_OS_EMBEDDED
7674 NetworkInterfaceInfoOSX
*i
;
7675 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
7677 if (!m
->SPSSocket
) // Not being Sleep Proxy Server; close any open BPF fds
7679 if (i
->BPF_fd
>= 0 && CountProxyTargets(i
, mDNSNULL
, mDNSNULL
) == 0)
7682 else // else, we're Sleep Proxy Server; open BPF fds
7684 if (i
->Exists
&& (i
->Registered
== i
) && SPSInterface(i
) && i
->BPF_fd
== -1)
7686 LogMsg("%s mDNSMacOSXNetworkChanged: requesting BPF", i
->ifinfo
.ifname
);
7693 #endif // APPLE_OSX_mDNSResponder
7695 uDNS_SetupDNSConfig(m
);
7696 mDNS_ConfigChanged(m
);
7698 if (IsAppleNetwork(m
) != mDNS_McastTracingEnabled
)
7700 mDNS_McastTracingEnabled
= mDNS_McastTracingEnabled
? mDNSfalse
: mDNStrue
;
7701 LogInfo("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled
? "Enabled" : "Disabled");
7707 // Copy the fourth slash-delimited element from either:
7708 // State:/Network/Interface/<bsdname>/IPv4
7710 // Setup:/Network/Service/<servicename>/Interface
7711 mDNSlocal CFStringRef
CopyNameFromKey(CFStringRef key
)
7714 CFStringRef name
= NULL
;
7716 a
= CFStringCreateArrayBySeparatingStrings(NULL
, key
, CFSTR("/"));
7717 if (a
&& CFArrayGetCount(a
) == 5) name
= CFRetain(CFArrayGetValueAtIndex(a
, 3));
7718 if (a
!= NULL
) CFRelease(a
);
7723 // Whether a key from a network change notification corresponds to
7724 // an IP service that is explicitly configured for IPv4 Link Local
7725 mDNSlocal
int ChangedKeysHaveIPv4LL(CFArrayRef inkeys
)
7727 CFDictionaryRef dict
= NULL
;
7728 CFMutableArrayRef a
;
7729 const void **keys
= NULL
, **vals
= NULL
;
7730 CFStringRef pattern
= NULL
;
7734 jc
= CFArrayGetCount(inkeys
);
7737 a
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
7738 if (a
== NULL
) goto done
;
7740 // Setup:/Network/Service/[^/]+/Interface
7741 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetInterface
);
7742 if (pattern
== NULL
) goto done
;
7743 CFArrayAppendValue(a
, pattern
);
7746 // Setup:/Network/Service/[^/]+/IPv4
7747 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetIPv4
);
7748 if (pattern
== NULL
) goto done
;
7749 CFArrayAppendValue(a
, pattern
);
7752 dict
= SCDynamicStoreCopyMultiple(NULL
, NULL
, a
);
7757 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
7761 ic
= CFDictionaryGetCount(dict
);
7762 vals
= mDNSPlatformMemAllocate(sizeof (void *) * ic
);
7763 keys
= mDNSPlatformMemAllocate(sizeof (void *) * ic
);
7764 CFDictionaryGetKeysAndValues(dict
, keys
, vals
);
7766 // For each key we were given...
7767 for (j
= 0; j
< jc
; j
++)
7769 CFStringRef key
= CFArrayGetValueAtIndex(inkeys
, j
);
7770 CFStringRef ifname
= NULL
;
7774 // It would be nice to use a regex here
7775 if (!CFStringHasPrefix(key
, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key
, kSCEntNetIPv4
)) continue;
7777 if ((ifname
= CopyNameFromKey(key
)) == NULL
) continue;
7778 if (mDNS_LoggingEnabled
)
7780 if (!CFStringGetCString(ifname
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7781 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf
);
7784 // Loop over the interfaces to find matching the ifname, and see if that one has kSCValNetIPv4ConfigMethodLinkLocal
7785 for (i
= 0; i
< ic
; i
++)
7787 CFDictionaryRef ipv4dict
;
7789 CFStringRef serviceid
;
7790 CFStringRef configmethod
;
7792 if (!CFStringHasSuffix(keys
[i
], kSCEntNetInterface
)) continue;
7794 if (CFDictionaryGetTypeID() != CFGetTypeID(vals
[i
])) continue;
7796 if ((name
= CFDictionaryGetValue(vals
[i
], kSCPropNetInterfaceDeviceName
)) == NULL
) continue;
7798 if (!CFEqual(ifname
, name
)) continue;
7800 if ((serviceid
= CopyNameFromKey(keys
[i
])) == NULL
) continue;
7801 if (mDNS_LoggingEnabled
)
7803 if (!CFStringGetCString(serviceid
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7804 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf
);
7807 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceid
, kSCEntNetIPv4
);
7808 CFRelease(serviceid
);
7809 if (pattern
== NULL
) continue;
7811 ipv4dict
= CFDictionaryGetValue(dict
, pattern
);
7813 if (!ipv4dict
|| CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict
)) continue;
7815 configmethod
= CFDictionaryGetValue(ipv4dict
, kSCPropNetIPv4ConfigMethod
);
7816 if (!configmethod
) continue;
7818 if (mDNS_LoggingEnabled
)
7820 if (!CFStringGetCString(configmethod
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7821 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf
);
7824 if (CFEqual(configmethod
, kSCValNetIPv4ConfigMethodLinkLocal
)) { found
++; break; }
7831 if (vals
!= NULL
) mDNSPlatformMemFree(vals
);
7832 if (keys
!= NULL
) mDNSPlatformMemFree(keys
);
7833 if (dict
!= NULL
) CFRelease(dict
);
7838 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
7840 (void)store
; // Parameter not used
7841 mDNS
*const m
= (mDNS
*const)context
;
7845 //mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
7846 const mDNSs32 delay
= (mDNSPlatformOneSecond
+ 39) / 40; // 25 ms delay
7848 const int c
= CFArrayGetCount(changedKeys
); // Count changes
7849 CFRange range
= { 0, c
};
7850 const int c_host
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Hostnames
) != 0);
7851 const int c_comp
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Computername
) != 0);
7852 const int c_udns
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DNS
) != 0);
7853 const int c_ddns
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DynamicDNS
) != 0);
7854 #if MDNSRESPONDER_BTMM_SUPPORT
7855 const int c_btmm
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_BackToMyMac
) != 0);
7857 const int c_btmm
= 0;
7859 const int c_v4ll
= ChangedKeysHaveIPv4LL(changedKeys
);
7862 // Do immediate network changed processing for "p2p*" interfaces and
7863 // for interfaces with the IFEF_DIRECTLINK or IFEF_AWDL flag set or association with a CarPlay
7868 for (int i
= 0; i
< c
; i
++)
7870 CFStringRef key
= CFArrayGetValueAtIndex(changedKeys
, i
);
7872 // Only look at keys with prefix "State:/Network/Interface/"
7873 if (!CFStringHasPrefix(key
, NetworkChangedKey_StateInterfacePrefix
))
7876 // And suffix "IPv6" or "IPv4".
7877 if (!CFStringHasSuffix(key
, kSCEntNetIPv6
) && !CFStringHasSuffix(key
, kSCEntNetIPv4
))
7880 labels
= CFStringCreateArrayBySeparatingStrings(NULL
, key
, CFSTR("/"));
7883 n
= CFArrayGetCount(labels
);
7885 // Interface changes will have keys of the form:
7886 // State:/Network/Interface/<interfaceName>/IPv6
7887 // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
7892 // The 4th label (index = 3) should be the interface name.
7893 if (CFStringGetCString(CFArrayGetValueAtIndex(labels
, 3), buf
, sizeof(buf
), kCFStringEncodingUTF8
)
7894 && (strstr(buf
, "p2p") || (getExtendedFlags(buf
) & (IFEF_DIRECTLINK
| IFEF_AWDL
)) || IsCarPlaySSID(buf
)))
7896 LogInfo("NetworkChanged: interface %s qualifies for reduced change handling delay", buf
);
7906 //if (c && c - c_host - c_comp - c_udns - c_ddns - c_btmm - c_v4ll - c_fast == 0)
7907 // delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
7909 if (mDNS_LoggingEnabled
)
7915 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys
, i
), buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7916 LogInfo("*** Network Configuration Change *** SC key: %s", buf
);
7918 LogInfo("*** Network Configuration Change *** %d change%s %s%s%s%s%s%s%sdelay %d%s",
7920 c_host
? "(Local Hostname) " : "",
7921 c_comp
? "(Computer Name) " : "",
7922 c_udns
? "(DNS) " : "",
7923 c_ddns
? "(DynamicDNS) " : "",
7924 c_btmm
? "(BTMM) " : "",
7925 c_v4ll
? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
7926 c_fast
? "(P2P/IFEF_DIRECTLINK/IFEF_AWDL/IsCarPlaySSID) " : "",
7928 (c_ddns
|| c_btmm
) ? " + SetKeyChainTimer" : "");
7931 SetNetworkChanged(delay
);
7933 // Other software might pick up these changes to register or browse in WAB or BTMM domains,
7934 // so in order for secure updates to be made to the server, make sure to read the keychain and
7935 // setup the DomainAuthInfo before handing the network change.
7936 // If we don't, then we will first try to register services in the clear, then later setup the
7937 // DomainAuthInfo, which is incorrect.
7938 if (c_ddns
|| c_btmm
)
7939 SetKeyChainTimer(delay
);
7941 // Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
7944 KQueueUnlock("NetworkChanged");
7947 #if APPLE_OSX_mDNSResponder
7948 mDNSlocal
void RefreshSPSStatus(const void *key
, const void *value
, void *context
)
7953 CFStringRef ifnameStr
= (CFStringRef
)key
;
7954 CFArrayRef array
= (CFArrayRef
)value
;
7955 if (!CFStringGetCString(ifnameStr
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
7958 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf
, CFArrayGetCount(array
));
7959 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState
, buf
, value
);
7963 mDNSlocal
void DynamicStoreReconnected(SCDynamicStoreRef store
, void *info
)
7965 mDNS
*const m
= (mDNS
*const)info
;
7968 KQueueLock(); // serialize with KQueueLoop()
7970 LogInfo("DynamicStoreReconnected: Reconnected");
7972 // State:/Network/MulticastDNS
7975 // State:/Network/DynamicDNS
7977 mDNSPlatformDynDNSHostNameStatusChanged(&m
->FQDN
, 1);
7979 // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
7980 // as we receive network change notifications and thus not necessary. But we leave it here
7981 // so that if things are done differently in the future, this code still works.
7983 // State:/Network/PrivateDNS
7984 if (privateDnsArray
)
7985 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, mDNSNULL
, privateDnsArray
);
7987 #if APPLE_OSX_mDNSResponder
7988 // State:/Network/BackToMyMac
7989 UpdateAutoTunnelDomainStatuses(m
);
7991 // State:/Network/Interface/en0/SleepProxyServers
7993 CFDictionaryApplyFunction(spsStatusDict
, RefreshSPSStatus
, NULL
);
7995 KQueueUnlock("DynamicStoreReconnected");
7998 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
8001 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
8002 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
8003 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
8004 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
8005 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
8006 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
8008 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
8009 if (!keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
8011 CFArrayAppendValue(keys
, NetworkChangedKey_IPv4
);
8012 CFArrayAppendValue(keys
, NetworkChangedKey_IPv6
);
8013 CFArrayAppendValue(keys
, NetworkChangedKey_Hostnames
);
8014 CFArrayAppendValue(keys
, NetworkChangedKey_Computername
);
8015 CFArrayAppendValue(keys
, NetworkChangedKey_DNS
);
8016 CFArrayAppendValue(keys
, NetworkChangedKey_DynamicDNS
);
8017 CFArrayAppendValue(keys
, NetworkChangedKey_PowerSettings
);
8018 #if MDNSRESPONDER_BTMM_SUPPORT
8019 CFArrayAppendValue(keys
, NetworkChangedKey_BackToMyMac
);
8020 CFArrayAppendValue(keys
, NetworkChangedKey_BTMMConnectivity
);
8022 CFArrayAppendValue(patterns
, pattern1
);
8023 CFArrayAppendValue(patterns
, pattern2
);
8024 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
8025 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
8026 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
8028 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8029 if (!SCDynamicStoreSetDispatchQueue(store
, dispatch_get_main_queue()))
8030 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
8032 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
8033 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
8034 CFRunLoopAddSource(CFRunLoopGetMain(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
8036 SCDynamicStoreSetDisconnectCallBack(store
, DynamicStoreReconnected
);
8037 m
->p
->Store
= store
;
8042 if (store
) CFRelease(store
);
8045 if (patterns
) CFRelease(patterns
);
8046 if (pattern2
) CFRelease(pattern2
);
8047 if (pattern1
) CFRelease(pattern1
);
8048 if (keys
) CFRelease(keys
);
8053 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8055 mDNSlocal
void mDNSSetPacketFilterRules(char * ifname
, const ResourceRecord
*const excludeRecord
)
8057 mDNS
*const m
= &mDNSStorage
;
8059 pfArray_t portArray
;
8060 pfArray_t protocolArray
;
8063 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
8065 if ((rr
->resrec
.rrtype
== kDNSServiceType_SRV
)
8066 && ((rr
->ARType
== AuthRecordAnyIncludeP2P
) || (rr
->ARType
== AuthRecordAnyIncludeAWDLandP2P
)))
8070 if (count
>= PFPortArraySize
)
8072 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize
, ARDisplayString(m
, rr
));
8076 if (excludeRecord
&& IdenticalResourceRecord(&rr
->resrec
, excludeRecord
))
8078 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m
, rr
));
8082 LogMsg("mDNSSetPacketFilterRules: found %s", ARDisplayString(m
, rr
));
8084 portArray
[count
] = rr
->resrec
.rdata
->u
.srv
.port
.NotAnInteger
;
8086 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
8087 p
= rr
->resrec
.name
->c
;
8089 // Skip to App Protocol
8093 // Skip to Transport Protocol
8097 if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_tcp"))
8099 protocolArray
[count
] = IPPROTO_TCP
;
8101 else if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_udp"))
8103 protocolArray
[count
] = IPPROTO_UDP
;
8107 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
8108 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m
, rr
));
8114 mDNSPacketFilterControl(PF_SET_RULES
, ifname
, count
, portArray
, protocolArray
);
8117 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
8118 mDNSexport
void mDNSUpdatePacketFilter(const ResourceRecord
*const excludeRecord
)
8120 mDNS
*const m
= &mDNSStorage
;
8122 NetworkInterfaceInfo
*intf
= GetFirstActiveInterface(m
->HostInterfaces
);
8125 if (strncmp(intf
->ifname
, "p2p", 3) == 0)
8127 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf
->ifname
);
8128 mDNSSetPacketFilterRules(intf
->ifname
, excludeRecord
);
8131 intf
= GetFirstActiveInterface(intf
->next
);
8135 #else // !TARGET_OS_EMBEDDED
8137 // Currently no packet filter setup required on embedded platforms.
8138 mDNSexport
void mDNSUpdatePacketFilter(const ResourceRecord
*const excludeRecord
)
8140 (void) excludeRecord
; // unused
8143 #endif // !TARGET_OS_EMBEDDED
8145 // AWDL should no longer generate KEV_DL_MASTER_ELECTED events, so just log a message if we receive one.
8146 mDNSlocal
void newMasterElected(struct net_event_data
* ptr
)
8148 char ifname
[IFNAMSIZ
];
8149 mDNSu32 interfaceIndex
;
8151 snprintf(ifname
, IFNAMSIZ
, "%s%d", ptr
->if_name
, ptr
->if_unit
);
8152 interfaceIndex
= if_nametoindex(ifname
);
8154 if (!interfaceIndex
)
8156 LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname
);
8160 LogInfo("newMasterElected: KEV_DL_MASTER_ELECTED received on ifname = %s, interfaceIndex = %d", ifname
, interfaceIndex
);
8163 // An ssth array of all zeroes indicates the peer has no services registered.
8164 mDNSlocal mDNSBool
allZeroSSTH(struct opaque_presence_indication
*op
)
8167 int *intp
= (int *) op
->ssth
;
8169 // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
8170 // it's not, print an error message and return false so that
8171 // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
8173 if (MAX_SSTH_SIZE
% sizeof(int))
8175 LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE
);
8179 for (i
= 0; i
< (int)(MAX_SSTH_SIZE
/ sizeof(int)); i
++, intp
++)
8187 // Mark records from this peer for deletion from the cache.
8188 mDNSlocal
void removeCachedPeerRecords(mDNSu32 ifindex
, mDNSAddr
*ap
, bool purgeNow
)
8190 mDNS
*const m
= &mDNSStorage
;
8194 NetworkInterfaceInfoOSX
*infoOSX
;
8195 mDNSInterfaceID InterfaceID
;
8197 // Using mDNSPlatformInterfaceIDfromInterfaceIndex() would lead to recursive
8198 // locking issues, see: <rdar://problem/21332983>
8199 infoOSX
= IfindexToInterfaceInfoOSX((mDNSInterfaceID
)(uintptr_t)ifindex
);
8202 LogInfo("removeCachedPeerRecords: interface %d not yet active", ifindex
);
8205 InterfaceID
= infoOSX
->ifinfo
.InterfaceID
;
8207 FORALL_CACHERECORDS(slot
, cg
, cr
)
8209 if ((InterfaceID
== cr
->resrec
.InterfaceID
) && mDNSSameAddress(ap
, & cr
->sourceAddress
))
8211 LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
8212 DNSTypeName(cr
->resrec
.rrtype
), cr
->resrec
.name
->c
);
8215 mDNS_PurgeCacheResourceRecord(m
, cr
);
8217 mDNS_Reconfirm_internal(m
, cr
, 0); // use default minimum reconfirm time
8222 // Handle KEV_DL_NODE_PRESENCE event.
8223 mDNSlocal
void nodePresence(struct kev_dl_node_presence
* p
)
8225 struct opaque_presence_indication
*op
= (struct opaque_presence_indication
*) p
->node_service_info
;
8227 LogInfo("nodePresence: IPv6 address: %.16a, SUI %d", p
->sin6_node_address
.sin6_addr
.s6_addr
, op
->SUI
);
8229 // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
8230 // all zeroes when a node is present and has no services registered.
8231 if (allZeroSSTH(op
))
8235 peerAddr
.type
= mDNSAddrType_IPv6
;
8236 peerAddr
.ip
.v6
= *(mDNSv6Addr
*)&p
->sin6_node_address
.sin6_addr
;
8238 LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer");
8239 removeCachedPeerRecords(p
->sdl_node_address
.sdl_index
, & peerAddr
, false);
8243 // Handle KEV_DL_NODE_ABSENCE event.
8244 mDNSlocal
void nodeAbsence(struct kev_dl_node_absence
* p
)
8248 peerAddr
.type
= mDNSAddrType_IPv6
;
8249 peerAddr
.ip
.v6
= *(mDNSv6Addr
*)&p
->sin6_node_address
.sin6_addr
;
8251 LogInfo("nodeAbsence: immediately purge cached records from %.16a", p
->sin6_node_address
.sin6_addr
.s6_addr
);
8252 removeCachedPeerRecords(p
->sdl_node_address
.sdl_index
, & peerAddr
, true);
8255 mDNSlocal
void SysEventCallBack(int s1
, short __unused filter
, void *context
, __unused mDNSBool encounteredEOF
)
8257 mDNS
*const m
= (mDNS
*const)context
;
8261 struct { struct kern_event_msg k
; char extra
[256]; } msg
;
8262 int bytes
= recv(s1
, &msg
, sizeof(msg
), 0);
8264 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes
, errno
, strerror(errno
));
8267 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
8268 bytes
, msg
.k
.total_size
,
8269 msg
.k
.vendor_code
, msg
.k
.vendor_code
== KEV_VENDOR_APPLE
? "KEV_VENDOR_APPLE" : "?",
8270 msg
.k
.kev_class
, msg
.k
.kev_class
== KEV_NETWORK_CLASS
? "KEV_NETWORK_CLASS" : "?",
8271 msg
.k
.kev_subclass
, msg
.k
.kev_subclass
== KEV_DL_SUBCLASS
? "KEV_DL_SUBCLASS" : "?",
8272 msg
.k
.id
, msg
.k
.event_code
,
8273 msg
.k
.event_code
== KEV_DL_SIFFLAGS
? "KEV_DL_SIFFLAGS" :
8274 msg
.k
.event_code
== KEV_DL_SIFMETRICS
? "KEV_DL_SIFMETRICS" :
8275 msg
.k
.event_code
== KEV_DL_SIFMTU
? "KEV_DL_SIFMTU" :
8276 msg
.k
.event_code
== KEV_DL_SIFPHYS
? "KEV_DL_SIFPHYS" :
8277 msg
.k
.event_code
== KEV_DL_SIFMEDIA
? "KEV_DL_SIFMEDIA" :
8278 msg
.k
.event_code
== KEV_DL_SIFGENERIC
? "KEV_DL_SIFGENERIC" :
8279 msg
.k
.event_code
== KEV_DL_ADDMULTI
? "KEV_DL_ADDMULTI" :
8280 msg
.k
.event_code
== KEV_DL_DELMULTI
? "KEV_DL_DELMULTI" :
8281 msg
.k
.event_code
== KEV_DL_IF_ATTACHED
? "KEV_DL_IF_ATTACHED" :
8282 msg
.k
.event_code
== KEV_DL_IF_DETACHING
? "KEV_DL_IF_DETACHING" :
8283 msg
.k
.event_code
== KEV_DL_IF_DETACHED
? "KEV_DL_IF_DETACHED" :
8284 msg
.k
.event_code
== KEV_DL_LINK_OFF
? "KEV_DL_LINK_OFF" :
8285 msg
.k
.event_code
== KEV_DL_LINK_ON
? "KEV_DL_LINK_ON" :
8286 msg
.k
.event_code
== KEV_DL_PROTO_ATTACHED
? "KEV_DL_PROTO_ATTACHED" :
8287 msg
.k
.event_code
== KEV_DL_PROTO_DETACHED
? "KEV_DL_PROTO_DETACHED" :
8288 msg
.k
.event_code
== KEV_DL_LINK_ADDRESS_CHANGED
? "KEV_DL_LINK_ADDRESS_CHANGED" :
8289 msg
.k
.event_code
== KEV_DL_WAKEFLAGS_CHANGED
? "KEV_DL_WAKEFLAGS_CHANGED" :
8290 msg
.k
.event_code
== KEV_DL_IF_IDLE_ROUTE_REFCNT
? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
8291 msg
.k
.event_code
== KEV_DL_IFCAP_CHANGED
? "KEV_DL_IFCAP_CHANGED" :
8292 msg
.k
.event_code
== KEV_DL_LINK_QUALITY_METRIC_CHANGED
? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" :
8293 msg
.k
.event_code
== KEV_DL_NODE_PRESENCE
? "KEV_DL_NODE_PRESENCE" :
8294 msg
.k
.event_code
== KEV_DL_NODE_ABSENCE
? "KEV_DL_NODE_ABSENCE" :
8295 msg
.k
.event_code
== KEV_DL_MASTER_ELECTED
? "KEV_DL_MASTER_ELECTED" :
8298 if (msg
.k
.event_code
== KEV_DL_NODE_PRESENCE
)
8299 nodePresence((struct kev_dl_node_presence
*) &msg
.k
.event_data
);
8301 if (msg
.k
.event_code
== KEV_DL_NODE_ABSENCE
)
8302 nodeAbsence((struct kev_dl_node_absence
*) &msg
.k
.event_data
);
8304 if (msg
.k
.event_code
== KEV_DL_MASTER_ELECTED
)
8305 newMasterElected((struct net_event_data
*) &msg
.k
.event_data
);
8307 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
8308 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
8309 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
8310 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
8311 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
8313 if (msg
.k
.event_code
== KEV_DL_WAKEFLAGS_CHANGED
|| msg
.k
.event_code
== KEV_DL_LINK_ON
)
8314 SetNetworkChanged(mDNSPlatformOneSecond
* 2);
8316 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8318 // For p2p interfaces, need to open the advertised service port in the firewall.
8319 if (msg
.k
.event_code
== KEV_DL_IF_ATTACHED
)
8321 struct net_event_data
* p
;
8322 p
= (struct net_event_data
*) &msg
.k
.event_data
;
8324 if (strncmp(p
->if_name
, "p2p", 3) == 0)
8326 char ifname
[IFNAMSIZ
];
8327 snprintf(ifname
, IFNAMSIZ
, "%s%d", p
->if_name
, p
->if_unit
);
8329 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p
->if_family
, p
->if_unit
, p
->if_name
);
8331 mDNSSetPacketFilterRules(ifname
, NULL
);
8335 // For p2p interfaces, need to clear the firewall rules on interface detach
8336 if (msg
.k
.event_code
== KEV_DL_IF_DETACHED
)
8338 struct net_event_data
* p
;
8339 p
= (struct net_event_data
*) &msg
.k
.event_data
;
8341 if (strncmp(p
->if_name
, "p2p", 3) == 0)
8343 pfArray_t portArray
, protocolArray
; // not initialized since count is 0 for PF_CLEAR_RULES
8344 char ifname
[IFNAMSIZ
];
8345 snprintf(ifname
, IFNAMSIZ
, "%s%d", p
->if_name
, p
->if_unit
);
8347 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p
->if_family
, p
->if_unit
, p
->if_name
);
8349 mDNSPacketFilterControl(PF_CLEAR_RULES
, ifname
, 0, portArray
, protocolArray
);
8352 #endif // !TARGET_OS_EMBEDDED
8359 mDNSlocal mStatus
WatchForSysEvents(mDNS
*const m
)
8361 m
->p
->SysEventNotifier
= socket(PF_SYSTEM
, SOCK_RAW
, SYSPROTO_EVENT
);
8362 if (m
->p
->SysEventNotifier
< 0)
8363 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m
->p
->SysEventNotifier
, errno
, strerror(errno
)); return(mStatus_NoMemoryErr
); }
8365 struct kev_request kev_req
= { KEV_VENDOR_APPLE
, KEV_NETWORK_CLASS
, KEV_DL_SUBCLASS
};
8366 int err
= ioctl(m
->p
->SysEventNotifier
, SIOCSKEVFILT
, &kev_req
);
8369 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err
, errno
, strerror(errno
));
8370 close(m
->p
->SysEventNotifier
);
8371 m
->p
->SysEventNotifier
= -1;
8372 return(mStatus_UnknownErr
);
8375 m
->p
->SysEventKQueue
.KQcallback
= SysEventCallBack
;
8376 m
->p
->SysEventKQueue
.KQcontext
= m
;
8377 m
->p
->SysEventKQueue
.KQtask
= "System Event Notifier";
8378 KQueueSet(m
->p
->SysEventNotifier
, EV_ADD
, EVFILT_READ
, &m
->p
->SysEventKQueue
);
8380 return(mStatus_NoError
);
8383 #ifndef NO_SECURITYFRAMEWORK
8384 mDNSlocal OSStatus
KeychainChanged(SecKeychainEvent keychainEvent
, SecKeychainCallbackInfo
*info
, void *context
)
8386 LogInfo("*** Keychain Changed ***");
8387 mDNS
*const m
= (mDNS
*const)context
;
8389 OSStatus err
= SecKeychainCopyDefault(&skc
);
8392 if (info
->keychain
== skc
)
8394 // For delete events, attempt to verify what item was deleted fail because the item is already gone, so we just assume they may be relevant
8395 mDNSBool relevant
= (keychainEvent
== kSecDeleteEvent
);
8398 UInt32 tags
[3] = { kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
};
8399 SecKeychainAttributeInfo attrInfo
= { 3, tags
, NULL
}; // Count, array of tags, array of formats
8400 SecKeychainAttributeList
*a
= NULL
;
8401 err
= SecKeychainItemCopyAttributesAndData(info
->item
, &attrInfo
, NULL
, &a
, NULL
, NULL
);
8404 relevant
= ((a
->attr
[0].length
== 4 && (!strncasecmp(a
->attr
[0].data
, "ddns", 4) || !strncasecmp(a
->attr
[0].data
, "sndd", 4))) ||
8405 (a
->attr
[1].length
>= mDNSPlatformStrLen(dnsprefix
) && (!strncasecmp(a
->attr
[1].data
, dnsprefix
, mDNSPlatformStrLen(dnsprefix
)))));
8406 #if MDNSRESPONDER_BTMM_SUPPORT
8407 if (!relevant
&& (a
->attr
[1].length
>= mDNSPlatformStrLen(btmmprefix
)) && !strncasecmp(a
->attr
[1].data
, btmmprefix
, mDNSPlatformStrLen(btmmprefix
)))
8409 relevant
= mDNStrue
;
8412 SecKeychainItemFreeAttributesAndData(a
, NULL
);
8417 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
8419 keychainEvent
== kSecAddEvent
? "kSecAddEvent" :
8420 keychainEvent
== kSecDeleteEvent
? "kSecDeleteEvent" :
8421 keychainEvent
== kSecUpdateEvent
? "kSecUpdateEvent" : "<Unknown>");
8422 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
8426 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
8427 // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
8428 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
8430 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
8431 // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
8432 // a one second delay is ok, as we'll still converge to correctness, and there's no race
8433 // condition between the RegistrationDomain and the DomainAuthInfo.
8435 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
8436 // the timer here, as it will not get set by NetworkChanged().
8437 SetKeyChainTimer(mDNSPlatformOneSecond
);
8440 KQueueUnlock("KeychainChanged");
8450 mDNSlocal
void PowerOn(mDNS
*const m
)
8452 mDNSCoreMachineSleep(m
, false); // Will set m->SleepState = SleepState_Awake;
8454 if (m
->p
->WakeAtUTC
)
8456 long utc
= mDNSPlatformUTC();
8457 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
8458 if (m
->p
->WakeAtUTC
- utc
> 30)
8460 LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m
->p
->WakeAtUTC
- utc
);
8462 else if (utc
- m
->p
->WakeAtUTC
> 30)
8464 LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc
- m
->p
->WakeAtUTC
);
8466 else if (IsAppleTV())
8468 LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc
- m
->p
->WakeAtUTC
);
8472 LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m
->p
->WakeAtUTC
- utc
);
8473 m
->p
->RequestReSleep
= mDNS_TimeNow(m
) + 20 * mDNSPlatformOneSecond
;
8477 // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
8478 // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
8479 // We will clear this assertion as soon as we think the mainenance activities are done.
8480 mDNSPlatformPreventSleep(DARK_WAKE_TIME
, "mDNSResponder:maintenance");
8484 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
8486 mDNS
*const m
= (mDNS
*const)refcon
;
8488 (void)service
; // Parameter not used
8489 debugf("PowerChanged %X %lX", messageType
, messageArgument
);
8491 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8492 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
8496 case kIOMessageCanSystemPowerOff
: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
8497 case kIOMessageSystemWillPowerOff
: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
8498 mDNSCoreMachineSleep(m
, true);
8499 if (m
->SleepState
== SleepState_Sleeping
) mDNSMacOSXNetworkChanged();
8501 case kIOMessageSystemWillNotPowerOff
: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
8502 case kIOMessageCanSystemSleep
: LogSPS("PowerChanged kIOMessageCanSystemSleep"); break; // E0000270
8503 case kIOMessageSystemWillSleep
: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
8504 mDNSCoreMachineSleep(m
, true);
8506 case kIOMessageSystemWillNotSleep
: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
8507 case kIOMessageSystemHasPoweredOn
: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
8508 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
8511 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m
->SleepState
);
8514 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
8515 // the System Configuration Framework "network changed" event that we expect
8516 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
8518 SetNetworkChanged(mDNSPlatformOneSecond
* 2);
8522 case kIOMessageSystemWillRestart
: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
8523 case kIOMessageSystemWillPowerOn
: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
8525 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
8526 if (m
->SleepState
!= SleepState_Sleeping
)
8528 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m
->SleepState
);
8529 m
->SleepState
= SleepState_Sleeping
;
8530 mDNSMacOSXNetworkChanged();
8534 default: LogSPS("PowerChanged unknown message %X", messageType
); break;
8537 if (messageType
== kIOMessageSystemWillSleep
)
8538 m
->p
->SleepCookie
= (long)messageArgument
;
8539 else if (messageType
== kIOMessageCanSystemSleep
)
8540 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
8542 KQueueUnlock("PowerChanged Sleep/Wake");
8545 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
8546 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
8547 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
8548 mDNSlocal
void SnowLeopardPowerChanged(void *refcon
, IOPMConnection connection
, IOPMConnectionMessageToken token
, IOPMSystemPowerStateCapabilities eventDescriptor
)
8550 mDNS
*const m
= (mDNS
*const)refcon
;
8552 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
8553 connection
, token
, eventDescriptor
,
8554 eventDescriptor
& kIOPMSystemPowerStateCapabilityCPU
? " CPU" : "",
8555 eventDescriptor
& kIOPMSystemPowerStateCapabilityVideo
? " Video" : "",
8556 eventDescriptor
& kIOPMSystemPowerStateCapabilityAudio
? " Audio" : "",
8557 eventDescriptor
& kIOPMSystemPowerStateCapabilityNetwork
? " Network" : "",
8558 eventDescriptor
& kIOPMSystemPowerStateCapabilityDisk
? " Disk" : "");
8560 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8561 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
8563 if (eventDescriptor
& kIOPMSystemPowerStateCapabilityCPU
)
8565 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
8566 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
8567 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
8568 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
8571 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m
->SleepLimit
, m
->SleepState
);
8572 IOPMConnectionAcknowledgeEvent(connection
, m
->p
->SleepCookie
);
8575 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m
->SleepLimit
, m
->SleepState
);
8576 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
8577 if (m
->SleepState
!= SleepState_Awake
)
8580 // If the network notifications have already come before we got the wakeup, we ignored them and
8581 // in case we get no more, we need to trigger one.
8583 SetNetworkChanged(mDNSPlatformOneSecond
* 2);
8586 IOPMConnectionAcknowledgeEvent(connection
, token
);
8590 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
8591 // we should hear nothing more until we're told that the CPU has started executing again.
8592 if (m
->SleepState
) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor
, m
->SleepState
);
8594 //mDNSMacOSXNetworkChanged(m);
8595 mDNSCoreMachineSleep(m
, true);
8596 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
8597 m
->p
->SleepCookie
= token
;
8600 KQueueUnlock("SnowLeopardPowerChanged Sleep/Wake");
8604 #if COMPILER_LIKES_PRAGMA_MARK
8606 #pragma mark - /etc/hosts support
8609 // Implementation Notes
8611 // As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
8612 // 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
8613 // them into a hash table. The implementation need to be able to do the following things efficiently
8615 // 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
8616 // 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
8617 // 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
8618 // need to be able set the RRSet of a resource record to the first one in the list and also update when
8619 // one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
8621 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
8623 // CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
8624 // "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
8625 // of the core layer which does all of the above very efficiently
8627 #define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
8629 mDNSexport
void FreeEtcHosts(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
8634 if (result
== mStatus_MemFree
)
8636 LogInfo("FreeEtcHosts: %s", ARDisplayString(m
, rr
));
8637 freeL("etchosts", rr
);
8641 // Returns true on success and false on failure
8642 mDNSlocal mDNSBool
mDNSMacOSXCreateEtcHostsEntry(const domainname
*domain
, const struct sockaddr
*sa
, const domainname
*cname
, char *ifname
, AuthHash
*auth
)
8647 mDNSInterfaceID InterfaceID
= mDNSInterface_LocalOnly
;
8652 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
8657 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
8661 if (sa
&& sa
->sa_family
!= AF_INET
&& sa
->sa_family
!= AF_INET6
)
8663 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa
->sa_family
);
8670 mDNSu32 ifindex
= if_nametoindex(ifname
);
8673 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain
->c
, ifname
);
8676 InterfaceID
= (mDNSInterfaceID
)(uintptr_t)ifindex
;
8680 rrtype
= (sa
->sa_family
== AF_INET
? kDNSType_A
: kDNSType_AAAA
);
8682 rrtype
= kDNSType_CNAME
;
8684 // Check for duplicates. See whether we parsed an entry before like this ?
8685 namehash
= DomainNameHashValue(domain
);
8686 ag
= AuthGroupForName(auth
, namehash
, domain
);
8692 if (rr
->resrec
.rrtype
== rrtype
)
8694 if (rrtype
== kDNSType_A
)
8697 ip
.NotAnInteger
= ((struct sockaddr_in
*)sa
)->sin_addr
.s_addr
;
8698 if (mDNSSameIPv4Address(rr
->resrec
.rdata
->u
.ipv4
, ip
))
8700 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain
->c
);
8704 else if (rrtype
== kDNSType_AAAA
)
8707 ip6
.l
[0] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[0];
8708 ip6
.l
[1] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[1];
8709 ip6
.l
[2] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[2];
8710 ip6
.l
[3] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[3];
8711 if (mDNSSameIPv6Address(rr
->resrec
.rdata
->u
.ipv6
, ip6
))
8713 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain
->c
);
8717 else if (rrtype
== kDNSType_CNAME
)
8719 if (SameDomainName(&rr
->resrec
.rdata
->u
.name
, cname
))
8721 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname
->c
, domain
->c
);
8729 rr
= mallocL("etchosts", sizeof(*rr
));
8730 if (rr
== NULL
) return mDNSfalse
;
8731 mDNSPlatformMemZero(rr
, sizeof(*rr
));
8732 mDNS_SetupResourceRecord(rr
, NULL
, InterfaceID
, rrtype
, 1, kDNSRecordTypeKnownUnique
, AuthRecordLocalOnly
, FreeEtcHosts
, NULL
);
8733 AssignDomainName(&rr
->namestorage
, domain
);
8737 rr
->resrec
.rdlength
= sa
->sa_family
== AF_INET
? sizeof(mDNSv4Addr
) : sizeof(mDNSv6Addr
);
8738 if (sa
->sa_family
== AF_INET
)
8739 rr
->resrec
.rdata
->u
.ipv4
.NotAnInteger
= ((struct sockaddr_in
*)sa
)->sin_addr
.s_addr
;
8742 rr
->resrec
.rdata
->u
.ipv6
.l
[0] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[0];
8743 rr
->resrec
.rdata
->u
.ipv6
.l
[1] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[1];
8744 rr
->resrec
.rdata
->u
.ipv6
.l
[2] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[2];
8745 rr
->resrec
.rdata
->u
.ipv6
.l
[3] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[3];
8750 rr
->resrec
.rdlength
= DomainNameLength(cname
);
8751 rr
->resrec
.rdata
->u
.name
.c
[0] = 0;
8752 AssignDomainName(&rr
->resrec
.rdata
->u
.name
, cname
);
8754 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
8755 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
8756 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(&mDNSStorage
, rr
));
8757 InsertAuthRecord(&mDNSStorage
, auth
, rr
);
8761 mDNSlocal
int EtcHostsParseOneName(int start
, int length
, char *buffer
, char **name
)
8766 for (i
= start
; i
< length
; i
++)
8768 if (buffer
[i
] == '#')
8770 if (buffer
[i
] != ' ' && buffer
[i
] != ',' && buffer
[i
] != '\t')
8774 // Found the start of a name, find the end and null terminate
8775 for (i
++; i
< length
; i
++)
8777 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t')
8789 mDNSlocal
void mDNSMacOSXParseEtcHostsLine(char *buffer
, ssize_t length
, AuthHash
*auth
)
8793 char *ifname
= NULL
;
8800 //Ignore leading whitespaces and tabs
8801 while (*buffer
== ' ' || *buffer
== '\t')
8807 // Find the end of the address string
8808 for (i
= 0; i
< length
; i
++)
8810 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t' || buffer
[i
] == '%')
8812 if (buffer
[i
] == '%')
8819 // Convert the address string to an address
8820 struct addrinfo hints
;
8821 bzero(&hints
, sizeof(hints
));
8822 hints
.ai_flags
= AI_NUMERICHOST
;
8823 struct addrinfo
*gairesults
= NULL
;
8824 if (getaddrinfo(buffer
, NULL
, &hints
, &gairesults
) != 0)
8826 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
8832 // Parse the interface
8833 ifname
= &buffer
[ifStart
];
8834 for (i
= ifStart
+ 1; i
< length
; i
++)
8836 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t')
8844 i
= EtcHostsParseOneName(i
+ 1, length
, buffer
, &name1
);
8847 // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
8848 if (!MakeDomainNameFromDNSNameString(&name1d
, name1
))
8850 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1
);
8851 freeaddrinfo(gairesults
);
8854 mDNSMacOSXCreateEtcHostsEntry(&name1d
, gairesults
->ai_addr
, mDNSNULL
, ifname
, auth
);
8859 // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
8860 // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
8861 // doing the right thing.
8863 if (!MakeDomainNameFromDNSNameString(&first
, name1
))
8865 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1
);
8866 freeaddrinfo(gairesults
);
8869 mDNSMacOSXCreateEtcHostsEntry(&first
, gairesults
->ai_addr
, mDNSNULL
, ifname
, auth
);
8871 // /etc/hosts alias discussion:
8873 // If the /etc/hosts has an entry like this
8875 // ip_address cname [aliases...]
8876 // 1.2.3.4 sun star bright
8878 // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
8879 // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
8881 // To achieve this, we need to add the entry like this:
8887 // We store the first name we parsed in "first" and add the address (A/AAAA) record.
8888 // Then we parse additional names adding CNAME records till we reach the end.
8893 // Continue to parse additional aliases until we reach end of the line and
8894 // for each "alias" parsed, add a CNAME record where "alias" points to the first "name".
8895 // See also /etc/hosts alias discussion above
8897 i
= EtcHostsParseOneName(i
+ 1, length
, buffer
, &name2
);
8901 if ((aliasIndex
) && (*buffer
== *name2
))
8902 break; // break out of the loop if we wrap around
8904 if (!MakeDomainNameFromDNSNameString(&name2d
, name2
))
8906 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2
);
8907 freeaddrinfo(gairesults
);
8910 // Ignore if it points to itself
8911 if (!SameDomainName(&first
, &name2d
))
8913 if (!mDNSMacOSXCreateEtcHostsEntry(&name2d
, mDNSNULL
, &first
, ifname
, auth
))
8915 freeaddrinfo(gairesults
);
8921 LogInfo("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names first %##s, name2 %##s", first
.c
, name2d
.c
);
8925 else if (!aliasIndex
)
8927 // We have never parsed any aliases. This case happens if there
8928 // is just one name and some extra white spaces at the end.
8929 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first
.c
);
8934 freeaddrinfo(gairesults
);
8937 mDNSlocal
void mDNSMacOSXParseEtcHosts(int fd
, AuthHash
*auth
)
8940 char buf
[ETCHOSTS_BUFSIZE
];
8944 if (fd
== -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
8946 fp
= fopen("/etc/hosts", "r");
8947 if (!fp
) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
8951 good
= (fgets(buf
, ETCHOSTS_BUFSIZE
, fp
) != NULL
);
8954 // skip comment and empty lines
8955 if (buf
[0] == '#' || buf
[0] == '\r' || buf
[0] == '\n')
8959 if (!len
) break; // sanity check
8960 //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
8961 if (buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
8963 buf
[len
- 1] = '\0';
8966 // fgets always null terminates and hence even if we have no
8967 // newline at the end, it is null terminated. The callee
8968 // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
8969 // buf[length] is zero and hence we decrement len to reflect that.
8972 //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
8973 //here we need to check for just \r but taking extra caution.
8974 if (buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
8976 buf
[len
- 1] = '\0';
8980 if (!len
) //Sanity Check: len should never be zero
8982 LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
8985 mDNSMacOSXParseEtcHostsLine(buf
, len
, auth
);
8990 mDNSlocal
void mDNSMacOSXUpdateEtcHosts(mDNS
*const m
);
8992 mDNSlocal
int mDNSMacOSXGetEtcHostsFD(void)
8994 mDNS
*const m
= &mDNSStorage
;
8995 #ifdef __DISPATCH_GROUP__
8996 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
8997 static dispatch_queue_t etcq
= 0;
8998 static dispatch_source_t etcsrc
= 0;
8999 static dispatch_source_t hostssrc
= 0;
9001 // First time through? just schedule ourselves on the main queue and we'll do the work later
9004 etcq
= dispatch_get_main_queue();
9007 // Do this work on the queue, not here - solves potential synchronization issues
9008 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
9013 if (hostssrc
) return dispatch_source_get_handle(hostssrc
);
9016 int fd
= open("/etc/hosts", O_RDONLY
);
9018 #ifdef __DISPATCH_GROUP__
9019 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9022 // If the open failed and we're already watching /etc, we're done
9023 if (etcsrc
) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd
; }
9025 // we aren't watching /etc, we should be
9026 fd
= open("/etc", O_RDONLY
);
9027 if (fd
== -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
9028 etcsrc
= dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE
, fd
, DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_WRITE
| DISPATCH_VNODE_RENAME
, etcq
);
9034 dispatch_source_set_event_handler(etcsrc
,
9036 u_int32_t flags
= dispatch_source_get_data(etcsrc
);
9037 LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags
);
9038 if ((flags
& (DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_RENAME
)) != 0)
9040 dispatch_source_cancel(etcsrc
);
9041 dispatch_release(etcsrc
);
9043 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
9046 if ((flags
& DISPATCH_VNODE_WRITE
) != 0 && hostssrc
== NULL
)
9048 mDNSMacOSXUpdateEtcHosts(m
);
9051 dispatch_source_set_cancel_handler(etcsrc
, ^{close(fd
);});
9052 dispatch_resume(etcsrc
);
9054 // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
9055 fd
= open("/etc/hosts", O_RDONLY
| O_EVTONLY
);
9056 if (fd
== -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
9059 // create a dispatch source to watch for changes to hosts file
9060 hostssrc
= dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE
, fd
,
9061 (DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_WRITE
| DISPATCH_VNODE_RENAME
|
9062 DISPATCH_VNODE_ATTRIB
| DISPATCH_VNODE_EXTEND
| DISPATCH_VNODE_LINK
| DISPATCH_VNODE_REVOKE
), etcq
);
9063 if (hostssrc
== NULL
)
9068 dispatch_source_set_event_handler(hostssrc
,
9070 u_int32_t flags
= dispatch_source_get_data(hostssrc
);
9071 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags
);
9072 if ((flags
& (DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_RENAME
)) != 0)
9074 dispatch_source_cancel(hostssrc
);
9075 dispatch_release(hostssrc
);
9077 // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
9078 // the block immediately, we try to open the file and the file may not exist and may
9079 // fail to get a notification in the future. When the file does not exist and
9080 // we start to monitor the directory, on "dispatch_resume" of that source, there
9081 // is no guarantee that the file creation will be notified always because when
9082 // the dispatch_resume returns, the kevent manager may not have registered the
9083 // kevent yet but the file may have been created
9085 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
9088 if ((flags
& DISPATCH_VNODE_WRITE
) != 0)
9090 mDNSMacOSXUpdateEtcHosts(m
);
9093 dispatch_source_set_cancel_handler(hostssrc
, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd
); close(fd
);});
9094 dispatch_resume(hostssrc
);
9096 // Cleanup /etc source, no need to watch it if we already have /etc/hosts
9099 dispatch_source_cancel(etcsrc
);
9100 dispatch_release(etcsrc
);
9104 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
9105 return hostssrc
? (int)dispatch_source_get_handle(hostssrc
) : -1;
9112 // When /etc/hosts is modified, flush all the cache records as there may be local
9113 // authoritative answers now
9114 mDNSlocal
void FlushAllCacheRecords(mDNS
*const m
)
9120 FORALL_CACHERECORDS(slot
, cg
, cr
)
9123 if (cr
->resrec
.InterfaceID
) continue;
9125 // If a resource record can answer A or AAAA, they need to be flushed so that we will
9126 // never used to deliver an ADD or RMV
9127 if (RRTypeAnswersQuestionType(&cr
->resrec
, kDNSType_A
) ||
9128 RRTypeAnswersQuestionType(&cr
->resrec
, kDNSType_AAAA
))
9130 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m
, cr
));
9131 mDNS_PurgeCacheResourceRecord(m
, cr
);
9136 // Add new entries to the core. If justCheck is set, this function does not add, just returns true
9137 mDNSlocal mDNSBool
EtcHostsAddNewEntries(AuthHash
*newhosts
, mDNSBool justCheck
)
9139 mDNS
*const m
= &mDNSStorage
;
9142 AuthRecord
*rr
, *primary
, *rrnext
;
9143 for (slot
= 0; slot
< AUTH_HASH_SLOTS
; slot
++)
9144 for (ag
= newhosts
->rrauth_hash
[slot
]; ag
; ag
= ag
->next
)
9147 for (rr
= ag
->members
; rr
; rr
= rrnext
)
9152 mDNSBool found
= mDNSfalse
;
9153 ag1
= AuthGroupForRecord(&m
->rrauth
, &rr
->resrec
);
9154 if (ag1
&& ag1
->members
)
9156 if (!primary
) primary
= ag1
->members
;
9160 // We are not using InterfaceID in checking for duplicates. This means,
9161 // if there are two addresses for a given name e.g., fe80::1%en0 and
9162 // fe80::1%en1, we only add the first one. It is not clear whether
9163 // this is a common case. To fix this, we also need to modify
9164 // mDNS_Register_internal in how it handles duplicates. If it becomes a
9165 // common case, we will fix it then.
9166 if (IdenticalResourceRecord(&rr1
->resrec
, &rr
->resrec
))
9168 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m
, rr1
));
9179 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m
, rr
));
9182 RemoveAuthRecord(m
, newhosts
, rr
);
9183 // if there is no primary, point to self
9184 rr
->RRSet
= (primary
? primary
: rr
);
9186 LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m
, rr
));
9187 if (mDNS_Register_internal(m
, rr
) != mStatus_NoError
)
9188 LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m
, rr
));
9195 // Delete entries from the core that are no longer needed. If justCheck is set, this function
9196 // does not delete, just returns true
9197 mDNSlocal mDNSBool
EtcHostsDeleteOldEntries(AuthHash
*newhosts
, mDNSBool justCheck
)
9199 mDNS
*const m
= &mDNSStorage
;
9202 AuthRecord
*rr
, *rrnext
;
9203 for (slot
= 0; slot
< AUTH_HASH_SLOTS
; slot
++)
9204 for (ag
= m
->rrauth
.rrauth_hash
[slot
]; ag
; ag
= ag
->next
)
9205 for (rr
= ag
->members
; rr
; rr
= rrnext
)
9207 mDNSBool found
= mDNSfalse
;
9211 if (rr
->RecordCallback
!= FreeEtcHosts
) continue;
9212 ag1
= AuthGroupForRecord(newhosts
, &rr
->resrec
);
9218 if (IdenticalResourceRecord(&rr1
->resrec
, &rr
->resrec
))
9220 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m
, rr
));
9227 // there is no corresponding record in newhosts for the same name. This means
9228 // we should delete this from the core.
9233 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m
, rr
));
9236 // if primary is going away, make sure that the rest of the records
9237 // point to the new primary
9238 if (rr
== ag
->members
)
9240 AuthRecord
*new_primary
= rr
->next
;
9241 AuthRecord
*r
= new_primary
;
9246 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m
, r
));
9247 r
->RRSet
= new_primary
;
9249 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m
, r
), r
->resrec
.name
);
9253 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m
, rr
));
9254 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
9260 mDNSlocal
void UpdateEtcHosts(mDNS
*const m
, void *context
)
9262 AuthHash
*newhosts
= (AuthHash
*)context
;
9266 //Delete old entries from the core if they are not present in the newhosts
9267 EtcHostsDeleteOldEntries(newhosts
, mDNSfalse
);
9268 // Add the new entries to the core if not already present in the core
9269 EtcHostsAddNewEntries(newhosts
, mDNSfalse
);
9272 mDNSlocal
void FreeNewHosts(AuthHash
*newhosts
)
9275 AuthGroup
*ag
, *agnext
;
9276 AuthRecord
*rr
, *rrnext
;
9278 for (slot
= 0; slot
< AUTH_HASH_SLOTS
; slot
++)
9279 for (ag
= newhosts
->rrauth_hash
[slot
]; ag
; ag
= agnext
)
9282 for (rr
= ag
->members
; rr
; rr
= rrnext
)
9285 freeL("etchosts", rr
);
9287 freeL("AuthGroups", ag
);
9291 mDNSlocal
void mDNSMacOSXUpdateEtcHosts(mDNS
*const m
)
9295 // As we will be modifying the core, we can only have one thread running at
9296 // any point in time.
9299 mDNSPlatformMemZero(&newhosts
, sizeof(AuthHash
));
9301 // Get the file desecriptor (will trigger us to start watching for changes)
9302 int fd
= mDNSMacOSXGetEtcHostsFD();
9305 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd
);
9306 mDNSMacOSXParseEtcHosts(fd
, &newhosts
);
9308 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
9310 // Optimization: Detect whether /etc/hosts changed or not.
9312 // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
9313 // newhosts is already registered with core. If we find at least one entry that is not
9314 // registered with core, then it means we have work to do.
9316 // 2. Next, we check to see if any of the entries that are registered with core is not present
9317 // in newhosts. If we find at least one entry that is not present, it means we have work to
9320 // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
9321 // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
9322 // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
9323 // in the future and this code does not have to change.
9325 // Add the new entries to the core if not already present in the core
9326 if (!EtcHostsAddNewEntries(&newhosts
, mDNStrue
))
9328 // No new entries to add, check to see if we need to delete any old entries from the
9329 // core if they are not present in the newhosts
9330 if (!EtcHostsDeleteOldEntries(&newhosts
, mDNStrue
))
9332 LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
9333 FreeNewHosts(&newhosts
);
9335 KQueueUnlock("/etc/hosts changed");
9340 // This will flush the cache, stop and start the query so that the queries
9341 // can look at the /etc/hosts again
9345 // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
9346 // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
9347 // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
9348 // delivers these events in the right order and then calls us back to delete them.
9350 // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
9351 // is a common function that looks at all local auth records and delivers a RMV including
9352 // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
9353 // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
9354 // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
9355 // is called back where we do the Registration of the record. This results in RMV followed by ADD which
9357 mDNSCoreRestartAddressQueries(m
, mDNSfalse
, FlushAllCacheRecords
, UpdateEtcHosts
, &newhosts
);
9358 FreeNewHosts(&newhosts
);
9360 KQueueUnlock("/etc/hosts changed");
9363 #if COMPILER_LIKES_PRAGMA_MARK
9365 #pragma mark - Initialization & Teardown
9368 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
9369 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
9370 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
9371 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
9373 // Major version 13 is 10.9.x
9374 mDNSexport
void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
9376 int major
= 0, minor
= 0;
9377 char letter
= 0, prodname
[256]="<Unknown>", prodvers
[256]="<Unknown>", buildver
[256]="<Unknown>";
9378 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
9381 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
9382 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
9383 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
9385 CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
9387 CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
9388 if (cfbuildver
&& CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
))
9389 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
9395 LogMsg("Note: No Major Build Version number found; assuming 13");
9398 mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, STRINGIFY(mDNSResponderVersion
));
9399 //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
9401 // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
9402 if ((prodname
[0] & 0xDF) == 'M')
9408 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
9409 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
9410 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
9411 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
9414 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
9416 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
9419 struct sockaddr_in s5353
;
9420 s5353
.sin_family
= AF_INET
;
9421 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
9422 s5353
.sin_addr
.s_addr
= 0;
9423 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
9427 if (err
) LogMsg("No unicast UDP responses");
9428 else debugf("Unicast UDP responses okay");
9432 mDNSlocal
void CreatePTRRecord(const domainname
*domain
)
9435 const domainname
*pname
= (domainname
*)"\x9" "localhost";
9437 rr
= mallocL("localhosts", sizeof(*rr
));
9438 if (rr
== NULL
) return;
9439 mDNSPlatformMemZero(rr
, sizeof(*rr
));
9441 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, kHostNameTTL
, kDNSRecordTypeKnownUnique
, AuthRecordLocalOnly
, mDNSNULL
, mDNSNULL
);
9442 AssignDomainName(&rr
->namestorage
, domain
);
9444 rr
->resrec
.rdlength
= DomainNameLength(pname
);
9445 rr
->resrec
.rdata
->u
.name
.c
[0] = 0;
9446 AssignDomainName(&rr
->resrec
.rdata
->u
.name
, pname
);
9448 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
9449 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
9450 mDNS_Register(&mDNSStorage
, rr
);
9453 // Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
9454 // on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
9455 // fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
9456 // a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
9458 // Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
9459 // intentionally to avoid adding to the complexity of code handling /etc/hosts.
9460 mDNSlocal
void SetupLocalHostRecords(void)
9464 MakeDomainNameFromDNSNameString(&name
, "1.0.0.127.in-addr.arpa.");
9465 CreatePTRRecord(&name
);
9467 MakeDomainNameFromDNSNameString(&name
, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.");
9468 CreatePTRRecord(&name
);
9471 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
9472 mDNSlocal
void setSameDomainLabelPointer(void);
9475 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
9476 // 1) query for b._dns-sd._udp.local on LocalOnly interface
9477 // (.local manually generated via explicit callback)
9478 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
9479 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
9480 // 4) result above should generate a callback from question in (1). result added to global list
9481 // 5) global list delivered to client via GetSearchDomainList()
9482 // 6) client calls to enumerate domains now go over LocalOnly interface
9483 // (!!!KRS may add outgoing interface in addition)
9485 #if TARGET_OS_IPHONE
9486 mDNSlocal mDNSBool
IsAppleInternalBuild(void)
9488 return (os_variant_has_internal_diagnostics("com.apple.mDNSResponder") ? mDNStrue
: mDNSfalse
);
9491 mDNSlocal mStatus
RegisterLocalOnlyAddressRecord(const domainname
*const name
, mDNSu16 type
, const void *rdata
, mDNSu16 rdlength
)
9496 if (rdlength
!= 4) return (mStatus_BadParamErr
);
9500 if (rdlength
!= 16) return (mStatus_BadParamErr
);
9504 return (mStatus_BadParamErr
);
9507 AuthRecord
*rr
= mallocL("etchosts", sizeof(*rr
));
9508 if (!rr
) return (mStatus_NoMemoryErr
);
9509 mDNSPlatformMemZero(rr
, sizeof(*rr
));
9511 mDNS_SetupResourceRecord(rr
, NULL
, mDNSInterface_LocalOnly
, type
, 1, kDNSRecordTypeKnownUnique
, AuthRecordLocalOnly
, FreeEtcHosts
, NULL
);
9512 AssignDomainName(&rr
->namestorage
, name
);
9513 mDNSPlatformMemCopy(rr
->resrec
.rdata
->u
.data
, rdata
, rdlength
);
9515 const mStatus err
= mDNS_Register_internal(&mDNSStorage
, rr
);
9518 LogMsg("RegisterLocalOnlyAddressRecord: mDNS_Register error %d registering %s", err
, ARDisplayString(&mDNSStorage
, rr
));
9519 freeL("etchosts", rr
);
9524 mDNSlocal
void RegisterLocalOnlyARecord(const domainname
*const name
, const mDNSv4Addr
*const addr
)
9526 RegisterLocalOnlyAddressRecord(name
, kDNSType_A
, addr
->b
, (mDNSu16
)sizeof(mDNSv4Addr
));
9529 mDNSlocal
void RegisterLocalOnlyAAAARecord(const domainname
*const name
, const mDNSv6Addr
*const addr
)
9531 RegisterLocalOnlyAddressRecord(name
, kDNSType_AAAA
, addr
->b
, (mDNSu16
)sizeof(mDNSv6Addr
));
9535 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
9539 char HINFO_SWstring
[256] = "";
9540 mDNSMacOSXSystemBuildNumber(HINFO_SWstring
);
9542 #if APPLE_OSX_mDNSResponder
9543 setSameDomainLabelPointer();
9546 err
= mDNSHelperInit();
9550 // Store mDNSResponder Platform
9553 m
->mDNS_plat
= platform_OSX
;
9558 m
->mDNS_plat
= platform_Atv
;
9560 m
->mDNS_plat
= platform_iOS
;
9564 m
->mDNS_plat
= platform_NonApple
;
9567 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
9568 // If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
9570 for (i
=0; i
<100; i
++)
9572 domainlabel testlabel
;
9574 GetUserSpecifiedLocalHostName(&testlabel
);
9575 if (testlabel
.c
[0]) break;
9579 m
->hostlabel
.c
[0] = 0;
9581 int get_model
[2] = { CTL_HW
, HW_MODEL
};
9582 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
9584 // Normal Apple model names are of the form "iPhone2,1", and
9585 // internal code names are strings containing no commas, e.g. "N88AP".
9586 // We used to ignore internal code names, but Apple now uses these internal code names
9587 // even in released shipping products, so we no longer ignore strings containing no commas.
9588 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
9589 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
9590 HINFO_HWstring
= HINFO_HWstring_buffer
;
9592 // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
9593 // For names of the form "N88AP" containg no comma, we use the entire string.
9594 HINFO_HWstring_prefixlen
= strchr(HINFO_HWstring_buffer
, ',') ? strcspn(HINFO_HWstring
, "0123456789") : strlen(HINFO_HWstring
);
9596 if (mDNSPlatformInit_CanReceiveUnicast())
9597 m
->CanReceiveUnicastOn5353
= mDNStrue
;
9599 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
9600 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
9601 if (hlen
+ slen
< 254)
9603 m
->HIHardware
.c
[0] = hlen
;
9604 m
->HISoftware
.c
[0] = slen
;
9605 mDNSPlatformMemCopy(&m
->HIHardware
.c
[1], HINFO_HWstring
, hlen
);
9606 mDNSPlatformMemCopy(&m
->HISoftware
.c
[1], HINFO_SWstring
, slen
);
9609 m
->p
->permanentsockets
.port
= MulticastDNSPort
;
9610 m
->p
->permanentsockets
.m
= m
;
9611 m
->p
->permanentsockets
.sktv4
= -1;
9612 m
->p
->permanentsockets
.kqsv4
.KQcallback
= myKQSocketCallBack
;
9613 m
->p
->permanentsockets
.kqsv4
.KQcontext
= &m
->p
->permanentsockets
;
9614 m
->p
->permanentsockets
.kqsv4
.KQtask
= "IPv4 UDP packet reception";
9615 m
->p
->permanentsockets
.sktv6
= -1;
9616 m
->p
->permanentsockets
.kqsv6
.KQcallback
= myKQSocketCallBack
;
9617 m
->p
->permanentsockets
.kqsv6
.KQcontext
= &m
->p
->permanentsockets
;
9618 m
->p
->permanentsockets
.kqsv6
.KQtask
= "IPv6 UDP packet reception";
9620 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET
, mDNSNULL
);
9621 if (err
) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET) failed error %d errno %d (%s)", err
, errno
, strerror(errno
));
9622 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET6
, mDNSNULL
);
9623 if (err
) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET6) failed error %d errno %d (%s)", err
, errno
, strerror(errno
));
9625 struct sockaddr_in s4
;
9626 socklen_t n4
= sizeof(s4
);
9627 if (getsockname(m
->p
->permanentsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0)
9628 LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
9630 m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
9632 if (m
->p
->permanentsockets
.sktv6
>= 0)
9634 struct sockaddr_in6 s6
;
9635 socklen_t n6
= sizeof(s6
);
9636 if (getsockname(m
->p
->permanentsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
9637 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
9640 m
->p
->InterfaceList
= mDNSNULL
;
9641 m
->p
->userhostlabel
.c
[0] = 0;
9642 m
->p
->usernicelabel
.c
[0] = 0;
9643 m
->p
->prevoldnicelabel
.c
[0] = 0;
9644 m
->p
->prevnewnicelabel
.c
[0] = 0;
9645 m
->p
->prevoldhostlabel
.c
[0] = 0;
9646 m
->p
->prevnewhostlabel
.c
[0] = 0;
9647 m
->p
->NotifyUser
= 0;
9648 m
->p
->KeyChainTimer
= 0;
9649 m
->p
->WakeAtUTC
= 0;
9650 m
->p
->RequestReSleep
= 0;
9651 // Assume that everything is good to begin with. If something is not working,
9652 // we will detect that when we start sending questions.
9653 m
->p
->v4answers
= 1;
9654 m
->p
->v6answers
= 1;
9655 m
->p
->DNSTrigger
= 0;
9656 m
->p
->LastConfigGeneration
= 0;
9658 m
->AutoTunnelRelayAddr
= zerov6Addr
;
9660 NetworkChangedKey_IPv4
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
9661 NetworkChangedKey_IPv6
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
9662 NetworkChangedKey_Hostnames
= SCDynamicStoreKeyCreateHostNames(NULL
);
9663 NetworkChangedKey_Computername
= SCDynamicStoreKeyCreateComputerName(NULL
);
9664 NetworkChangedKey_DNS
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
9665 NetworkChangedKey_StateInterfacePrefix
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, CFSTR(""), NULL
);
9666 if (!NetworkChangedKey_IPv4
|| !NetworkChangedKey_IPv6
|| !NetworkChangedKey_Hostnames
|| !NetworkChangedKey_Computername
|| !NetworkChangedKey_DNS
|| !NetworkChangedKey_StateInterfacePrefix
)
9667 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr
); }
9669 err
= WatchForNetworkChanges(m
);
9670 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err
); return(err
); }
9672 err
= WatchForSysEvents(m
);
9673 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err
); return(err
); }
9675 mDNSs32 utc
= mDNSPlatformUTC();
9676 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
9678 UpdateInterfaceList(utc
);
9679 SetupActiveInterfaces(utc
);
9680 ReorderInterfaceList();
9682 // Explicitly ensure that our Keychain operations utilize the system domain.
9683 #ifndef NO_SECURITYFRAMEWORK
9684 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
9688 SetDomainSecrets(m
);
9692 #ifndef NO_SECURITYFRAMEWORK
9693 err
= SecKeychainAddCallback(KeychainChanged
, kSecAddEventMask
|kSecDeleteEventMask
|kSecUpdateEventMask
, m
);
9694 if (err
) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err
); return(err
); }
9697 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
9698 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
9701 IOReturn iopmerr
= IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU
, &c
);
9702 if (iopmerr
) LogMsg("IOPMConnectionCreate failed %d", iopmerr
);
9705 iopmerr
= IOPMConnectionSetNotification(c
, m
, SnowLeopardPowerChanged
);
9706 if (iopmerr
) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr
);
9709 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9710 IOPMConnectionSetDispatchQueue(c
, dispatch_get_main_queue());
9711 LogInfo("IOPMConnectionSetDispatchQueue is now running");
9713 iopmerr
= IOPMConnectionScheduleWithRunLoop(c
, CFRunLoopGetMain(), kCFRunLoopDefaultMode
);
9714 if (iopmerr
) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr
);
9715 LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
9716 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9719 m
->p
->IOPMConnection
= iopmerr
? mDNSNULL
: c
;
9720 if (iopmerr
) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
9721 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
9723 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &m
->p
->PowerPortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
9724 if (!m
->p
->PowerConnection
) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
9727 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9728 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, dispatch_get_main_queue());
9730 CFRunLoopAddSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
9731 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9735 #if APPLE_OSX_mDNSResponder
9736 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
9737 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
9738 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
9739 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
9740 if (!strncasecmp(HINFO_HWstring
, "Xserve", 6)) { SPMetricPortability
= 25 /* 30kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
9741 else if (!strncasecmp(HINFO_HWstring
, "RackMac", 7)) { SPMetricPortability
= 25 /* 30kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
9742 else if (!strncasecmp(HINFO_HWstring
, "MacPro", 6)) { SPMetricPortability
= 27 /* 20kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
9743 else if (!strncasecmp(HINFO_HWstring
, "PowerMac", 8)) { SPMetricPortability
= 27 /* 20kg */; SPMetricMarginalPower
= 82 /* 160W */; SPMetricTotalPower
= 83 /* 200W */; }
9744 else if (!strncasecmp(HINFO_HWstring
, "iMac", 4)) { SPMetricPortability
= 30 /* 10kg */; SPMetricMarginalPower
= 77 /* 50W */; SPMetricTotalPower
= 78 /* 60W */; }
9745 else if (!strncasecmp(HINFO_HWstring
, "Macmini", 7)) { SPMetricPortability
= 33 /* 5kg */; SPMetricMarginalPower
= 73 /* 20W */; SPMetricTotalPower
= 74 /* 25W */; }
9746 else if (!strncasecmp(HINFO_HWstring
, "TimeCapsule", 11)) { SPMetricPortability
= 34 /* 4kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 70 /* 13W */; }
9747 else if (!strncasecmp(HINFO_HWstring
, "AirPort", 7)) { SPMetricPortability
= 35 /* 3kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 70 /* 12W */; }
9748 else if ( IsAppleTV() ) { SPMetricPortability
= 35 /* 3kg */; SPMetricMarginalPower
= 60 /* 1W */; SPMetricTotalPower
= 63 /* 2W */; }
9749 else if (!strncasecmp(HINFO_HWstring
, "MacBook", 7)) { SPMetricPortability
= 37 /* 2kg */; SPMetricMarginalPower
= 71 /* 13W */; SPMetricTotalPower
= 72 /* 15W */; }
9750 else if (!strncasecmp(HINFO_HWstring
, "PowerBook", 9)) { SPMetricPortability
= 37 /* 2kg */; SPMetricMarginalPower
= 71 /* 13W */; SPMetricTotalPower
= 72 /* 15W */; }
9751 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
9752 HINFO_HWstring_prefixlen
, HINFO_HWstring
, HINFO_HWstring
, SPMetricPortability
, SPMetricMarginalPower
, SPMetricTotalPower
, SPMetricFeatures
);
9753 #endif // APPLE_OSX_mDNSResponder
9755 // Currently this is not defined. SSL code will eventually fix this. If it becomes
9756 // critical, we will define this to workaround the bug in SSL.
9757 #ifdef __SSL_NEEDS_SERIALIZATION__
9758 SSLqueue
= dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL
);
9760 SSLqueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
9762 if (SSLqueue
== mDNSNULL
) LogMsg("dispatch_queue_create: SSL queue NULL");
9764 #if TARGET_OS_IPHONE
9765 // On device OSes (iOS, tvOS, watchOS, etc.), ignore /etc/hosts unless the OS is an internal build. When the /etc/hosts
9766 // file is ignored, LocalOnly auth records will be registered for localhost and broadcasthost addresses contained in the
9767 // standard /etc/hosts file:
9769 // 127.0.0.1 localhost
9770 // 255.255.255.255 broadcasthost
9773 if (!IsAppleInternalBuild())
9775 const domainname
*const localHostName
= (const domainname
*) "\x9" "localhost";
9776 const domainname
*const broadcastHostName
= (const domainname
*) "\xd" "broadcasthost";
9777 const mDNSv4Addr localHostV4
= { { 127, 0, 0, 1 } };
9778 mDNSv6Addr localHostV6
;
9780 // Register localhost 127.0.0.1 A record.
9782 RegisterLocalOnlyARecord(localHostName
, &localHostV4
);
9784 // Register broadcasthost 255.255.255.255 A record.
9786 RegisterLocalOnlyARecord(broadcastHostName
, &onesIPv4Addr
);
9788 // Register localhost ::1 AAAA record.
9790 mDNSPlatformMemZero(&localHostV6
, sizeof(localHostV6
));
9791 localHostV6
.b
[15] = 1;
9792 RegisterLocalOnlyAAAARecord(localHostName
, &localHostV6
);
9797 mDNSMacOSXUpdateEtcHosts(m
);
9799 SetupLocalHostRecords();
9801 return(mStatus_NoError
);
9804 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
9807 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
9810 // Adding interfaces will use this flag, so set it now.
9811 m
->DivertMulticastAdvertisements
= !m
->AdvertiseLocalAddresses
;
9813 #if APPLE_OSX_mDNSResponder
9814 m
->SPSBrowseCallback
= UpdateSPSStatus
;
9815 #endif // APPLE_OSX_mDNSResponder
9817 mStatus result
= mDNSPlatformInit_setup(m
);
9819 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
9820 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
9821 if (result
== mStatus_NoError
)
9823 mDNSCoreInitComplete(m
, mStatus_NoError
);
9824 initializeD2DPlugins(m
);
9826 result
= DNSSECCryptoInit(m
);
9830 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
9832 if (m
->p
->PowerConnection
)
9834 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9835 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, NULL
);
9837 CFRunLoopRemoveSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
9839 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
9840 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
9841 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
9842 IOServiceClose ( m
->p
->PowerConnection
);
9843 IONotificationPortDestroy ( m
->p
->PowerPortRef
);
9844 m
->p
->PowerConnection
= 0;
9849 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9850 if (!SCDynamicStoreSetDispatchQueue(m
->p
->Store
, NULL
))
9851 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
9853 CFRunLoopRemoveSource(CFRunLoopGetMain(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
9854 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
9855 CFRelease(m
->p
->StoreRLS
);
9856 m
->p
->StoreRLS
= NULL
;
9858 CFRelease(m
->p
->Store
);
9864 CFRunLoopRemoveSource(CFRunLoopGetMain(), m
->p
->PMRLS
, kCFRunLoopDefaultMode
);
9865 CFRunLoopSourceInvalidate(m
->p
->PMRLS
);
9866 CFRelease(m
->p
->PMRLS
);
9870 if (m
->p
->SysEventNotifier
>= 0) { close(m
->p
->SysEventNotifier
); m
->p
->SysEventNotifier
= -1; }
9872 terminateD2DPlugins();
9874 mDNSs32 utc
= mDNSPlatformUTC();
9875 MarkAllInterfacesInactive(utc
);
9876 ClearInactiveInterfaces(utc
);
9877 CloseSocketSet(&m
->p
->permanentsockets
);
9879 #if APPLE_OSX_mDNSResponder
9881 while (m
->TunnelClients
)
9883 ClientTunnel
*cur
= m
->TunnelClients
;
9884 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur
, cur
->dstname
.c
);
9885 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
9886 AutoTunnelSetKeys(cur
, mDNSfalse
);
9887 m
->TunnelClients
= cur
->next
;
9888 freeL("ClientTunnel", cur
);
9891 if (AnonymousRacoonConfig
)
9893 AnonymousRacoonConfig
= mDNSNULL
;
9894 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel need not be done in mDNSResponder");
9896 #endif // APPLE_OSX_mDNSResponder
9899 #if COMPILER_LIKES_PRAGMA_MARK
9901 #pragma mark - General Platform Support Layer functions
9904 mDNSexport mDNSu32
mDNSPlatformRandomNumber(void)
9906 return(arc4random());
9909 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
9910 mDNSexport mDNSu32 mDNSPlatformClockDivisor
= 0;
9912 mDNSexport mStatus
mDNSPlatformTimeInit(void)
9914 // Notes: Typical values for mach_timebase_info:
9915 // tbi.numer = 1000 million
9916 // tbi.denom = 33 million
9917 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
9918 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
9919 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
9920 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
9921 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
9923 // Arithmetic notes:
9924 // tbi.denom is at least 1, and not more than 2^32-1.
9925 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
9926 // tbi.denom is at least 1, and not more than 2^32-1.
9927 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
9928 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
9929 // which is unlikely on any current or future Macintosh.
9930 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
9931 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
9932 struct mach_timebase_info tbi
;
9933 kern_return_t result
= mach_timebase_info(&tbi
);
9934 if (result
== KERN_SUCCESS
) mDNSPlatformClockDivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
9938 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
9940 if (mDNSPlatformClockDivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
9942 static uint64_t last_mach_absolute_time
= 0;
9943 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
9944 uint64_t this_mach_absolute_time
= mach_absolute_time();
9945 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
9947 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
9948 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
9949 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
9950 last_mach_absolute_time
= this_mach_absolute_time
;
9951 // Note: This bug happens all the time on 10.3
9952 NotifyOfElusiveBug("mach_absolute_time went backwards!",
9953 "This error occurs from time to time, often on newly released hardware, "
9954 "and usually the exact cause is different in each instance.\r\r"
9955 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
9956 "and assign it to Radar Component “Kernel” Version “X”.");
9958 last_mach_absolute_time
= this_mach_absolute_time
;
9960 return((mDNSs32
)(this_mach_absolute_time
/ mDNSPlatformClockDivisor
));
9963 mDNSexport mDNSs32
mDNSPlatformUTC(void)
9968 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
9969 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
9970 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
9971 mDNSexport
void mDNSPlatformStrCopy( void *dst
, const void *src
) { strcpy((char *)dst
, (const char *)src
); }
9972 mDNSexport mDNSu32
mDNSPlatformStrLCopy( void *dst
, const void *src
, mDNSu32 dstlen
) { return (strlcpy((char *)dst
, (const char *)src
, dstlen
)); }
9973 mDNSexport mDNSu32
mDNSPlatformStrLen ( const void *src
) { return(strlen((const char*)src
)); }
9974 mDNSexport
void mDNSPlatformMemCopy( void *dst
, const void *src
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
9975 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *dst
, const void *src
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
9976 mDNSexport
int mDNSPlatformMemCmp(const void *dst
, const void *src
, mDNSu32 len
) { return(memcmp(dst
, src
, len
)); }
9977 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { memset(dst
, 0, len
); }
9978 mDNSexport
void mDNSPlatformQsort ( void *base
, int nel
, int width
, int (*compar
)(const void *, const void *))
9980 return (qsort(base
, nel
, width
, compar
));
9982 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
9983 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
9985 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }
9987 mDNSexport
void mDNSPlatformSetAllowSleep(mDNSBool allowSleep
, const char *reason
)
9989 mDNS
*const m
= &mDNSStorage
;
9990 if (allowSleep
&& m
->p
->IOPMAssertion
)
9992 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__
);
9993 IOPMAssertionRelease(m
->p
->IOPMAssertion
);
9994 m
->p
->IOPMAssertion
= 0;
9996 else if (!allowSleep
)
9998 #ifdef kIOPMAssertionTypeNoIdleSleep
9999 if (m
->p
->IOPMAssertion
)
10001 IOPMAssertionRelease(m
->p
->IOPMAssertion
);
10002 m
->p
->IOPMAssertion
= 0;
10005 CFStringRef assertionName
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s.%d %s"), getprogname(), getpid(), reason
? reason
: "");
10006 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep
, kIOPMAssertionLevelOn
, assertionName
? assertionName
: CFSTR("mDNSResponder"), &m
->p
->IOPMAssertion
);
10007 if (assertionName
) CFRelease(assertionName
);
10008 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__
);
10013 mDNSexport
void mDNSPlatformPreventSleep(mDNSu32 timeout
, const char *reason
)
10015 mDNS
*const m
= &mDNSStorage
;
10016 if (m
->p
->IOPMAssertion
)
10018 LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout
, reason
);
10021 #ifdef kIOPMAssertionTypeNoIdleSleep
10023 #if TARGET_OS_EMBEDDED
10025 return; // No need for maintenance wakes on non-AppleTV embedded devices.
10028 double timeoutVal
= (double)timeout
;
10029 CFStringRef str
= CFStringCreateWithCString(NULL
, reason
, kCFStringEncodingUTF8
);
10030 CFNumberRef Timeout_num
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &timeoutVal
);
10031 CFMutableDictionaryRef assertionProperties
= CFDictionaryCreateMutable(NULL
, 0,
10032 &kCFTypeDictionaryKeyCallBacks
,
10033 &kCFTypeDictionaryValueCallBacks
);
10035 CFDictionarySetValue(assertionProperties
, kIOPMAssertionTypeKey
, kIOPMAssertPreventUserIdleSystemSleep
);
10037 CFDictionarySetValue(assertionProperties
, kIOPMAssertionTypeKey
, kIOPMAssertMaintenanceActivity
);
10039 CFDictionarySetValue(assertionProperties
, kIOPMAssertionTimeoutKey
, Timeout_num
);
10040 CFDictionarySetValue(assertionProperties
, kIOPMAssertionNameKey
, str
);
10042 IOPMAssertionCreateWithProperties(assertionProperties
, (IOPMAssertionID
*)&m
->p
->IOPMAssertion
);
10044 CFRelease(Timeout_num
);
10045 CFRelease(assertionProperties
);
10046 LogSPS("Got an idle sleep assertion for %d seconds for %s", timeout
, reason
);
10050 mDNSexport
void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID
, char *EthAddr
, char *IPAddr
, int iteration
)
10055 ifindex
= mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage
, InterfaceID
, mDNStrue
);
10058 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex
);
10061 mDNSSendWakeupPacket(ifindex
, EthAddr
, IPAddr
, iteration
);
10064 mDNSexport mDNSBool
mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID
)
10066 NetworkInterfaceInfoOSX
*info
;
10068 if (InterfaceID
== mDNSInterface_P2P
)
10071 // mDNSInterface_BLE not considered a D2D interface for the purpose of this
10072 // routine, since it's not implemented via a D2D plugin.
10073 if (InterfaceID
== mDNSInterface_BLE
)
10076 if ( (InterfaceID
== mDNSInterface_Any
)
10077 || (InterfaceID
== mDNSInterfaceMark
)
10078 || (InterfaceID
== mDNSInterface_LocalOnly
)
10079 || (InterfaceID
== mDNSInterface_Unicast
))
10082 // Compare to cached AWDL interface ID.
10083 if (AWDLInterfaceID
&& (InterfaceID
== AWDLInterfaceID
))
10086 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
10089 // this log message can print when operations are stopped on an interface that has gone away
10090 LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID
);
10094 return (mDNSBool
) info
->D2DInterface
;
10097 // Filter records send over P2P (D2D) type interfaces
10098 // Note that the terms P2P and D2D are used synonymously in the current code and comments.
10099 mDNSexport mDNSBool
mDNSPlatformValidRecordForInterface(const AuthRecord
*rr
, mDNSInterfaceID InterfaceID
)
10101 // For an explicit match to a valid interface ID, return true.
10102 if (rr
->resrec
.InterfaceID
== InterfaceID
)
10105 // Only filtering records for D2D type interfaces, return true for all other interface types.
10106 if (!mDNSPlatformInterfaceIsD2D(InterfaceID
))
10109 // If it's an AWDL interface the record must be explicitly marked to include AWDL.
10110 if (InterfaceID
== AWDLInterfaceID
)
10112 if (rr
->ARType
== AuthRecordAnyIncludeAWDL
|| rr
->ARType
== AuthRecordAnyIncludeAWDLandP2P
)
10118 // Send record if it is explicitly marked to include all other P2P type interfaces.
10119 if (rr
->ARType
== AuthRecordAnyIncludeP2P
|| rr
->ARType
== AuthRecordAnyIncludeAWDLandP2P
)
10122 // Don't send the record over this interface.
10126 // Filter questions send over P2P (D2D) type interfaces.
10127 mDNSexport mDNSBool
mDNSPlatformValidQuestionForInterface(DNSQuestion
*q
, const NetworkInterfaceInfo
*intf
)
10129 // For an explicit match to a valid interface ID, return true.
10130 if (q
->InterfaceID
== intf
->InterfaceID
)
10133 // Only filtering questions for D2D type interfaces
10134 if (!mDNSPlatformInterfaceIsD2D(intf
->InterfaceID
))
10137 // If it's an AWDL interface the question must be explicitly marked to include AWDL.
10138 if (intf
->InterfaceID
== AWDLInterfaceID
)
10140 if (q
->flags
& kDNSServiceFlagsIncludeAWDL
)
10146 // Sent question if it is explicitly marked to include all other P2P type interfaces.
10147 if (q
->flags
& kDNSServiceFlagsIncludeP2P
)
10150 // Don't send the question over this interface.
10154 // Returns true unless record was received over the AWDL interface and
10155 // the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
10156 // with the kDNSServiceFlagsIncludeAWDL flag set.
10157 mDNSexport mDNSBool
mDNSPlatformValidRecordForQuestion(const ResourceRecord
*const rr
, const DNSQuestion
*const q
)
10159 if (!rr
->InterfaceID
|| (rr
->InterfaceID
== q
->InterfaceID
))
10162 if ((rr
->InterfaceID
== AWDLInterfaceID
) && !(q
->flags
& kDNSServiceFlagsIncludeAWDL
))
10168 // formating time to RFC 4034 format
10169 mDNSexport
void mDNSPlatformFormatTime(unsigned long te
, mDNSu8
*buf
, int bufsize
)
10172 time_t t
= (time_t)te
;
10173 // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
10174 // gmtime_r first and then use strftime
10175 gmtime_r(&t
, &tmTime
);
10176 strftime((char *)buf
, bufsize
, "%Y%m%d%H%M%S", &tmTime
);
10179 mDNSexport mDNSs32
mDNSPlatformGetPID()
10184 // Schedule a function asynchronously on the main queue
10185 mDNSexport
void mDNSPlatformDispatchAsync(mDNS
*const m
, void *context
, AsyncDispatchFunc func
)
10187 // KQueueLock/Unlock is used for two purposes
10189 // 1. We can't be running along with the KQueue thread and hence acquiring the lock
10190 // serializes the access to the "core"
10192 // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
10193 // up and calls udsserver_idle which schedules the messages across the uds socket.
10194 // If "func" delivers something to the uds socket from the dispatch thread, it will
10195 // not be delivered immediately if not for the Unlock.
10196 dispatch_async(dispatch_get_main_queue(), ^{
10199 KQueueUnlock("mDNSPlatformDispatchAsync");
10200 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10201 // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
10202 // to handle any message that "func" might deliver.
10203 TriggerEventCompletion();
10208 // definitions for device-info record construction
10209 #define DEVINFO_MODEL "model="
10210 #define DEVINFO_MODEL_LEN sizeof_string(DEVINFO_MODEL)
10212 #define OSX_VER "osxvers="
10213 #define OSX_VER_LEN sizeof_string(OSX_VER)
10214 #define VER_NUM_LEN 2 // 2 digits of version number added to base string
10216 #define MODEL_COLOR "ecolor="
10217 #define MODEL_COLOR_LEN sizeof_string(MODEL_COLOR)
10218 #define MODEL_RGB_VALUE_LEN sizeof_string("255,255,255") // 'r,g,b'
10220 // Bytes available in TXT record for model name after subtracting space for other
10221 // fixed size strings and their length bytes.
10222 #define MAX_MODEL_NAME_LEN (256 - (DEVINFO_MODEL_LEN + 1) - (OSX_VER_LEN + VER_NUM_LEN + 1) - (MODEL_COLOR_LEN + MODEL_RGB_VALUE_LEN + 1))
10224 mDNSlocal mDNSu8
getModelIconColors(char *color
)
10226 mDNSPlatformMemZero(color
, MODEL_RGB_VALUE_LEN
+ 1);
10228 #if !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10233 IOReturn rGetDeviceColor
= IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey
,
10234 &red
, &green
, &blue
);
10235 if (kIOReturnSuccess
== rGetDeviceColor
)
10237 // IOKit was able to get enclosure color for the current device.
10238 return snprintf(color
, MODEL_RGB_VALUE_LEN
+ 1, "%d,%d,%d", red
, green
, blue
);
10240 #endif // !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10246 // Initialize device-info TXT record contents and return total length of record data.
10247 mDNSexport mDNSu32
initializeDeviceInfoTXT(mDNS
*m
, mDNSu8
*ptr
)
10249 mDNSu8
*bufferStart
= ptr
;
10250 mDNSu8 len
= m
->HIHardware
.c
[0] < MAX_MODEL_NAME_LEN
? m
->HIHardware
.c
[0] : MAX_MODEL_NAME_LEN
;
10252 *ptr
= DEVINFO_MODEL_LEN
+ len
; // total length of DEVINFO_MODEL string plus the hardware name string
10254 mDNSPlatformMemCopy(ptr
, DEVINFO_MODEL
, DEVINFO_MODEL_LEN
);
10255 ptr
+= DEVINFO_MODEL_LEN
;
10256 mDNSPlatformMemCopy(ptr
, m
->HIHardware
.c
+ 1, len
);
10259 // only include this string for OSX
10262 char ver_num
[VER_NUM_LEN
+ 1]; // version digits + null written by snprintf
10263 *ptr
= OSX_VER_LEN
+ VER_NUM_LEN
; // length byte
10265 mDNSPlatformMemCopy(ptr
, OSX_VER
, OSX_VER_LEN
);
10266 ptr
+= OSX_VER_LEN
;
10267 // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
10268 // WARNING: This code assumes that OSXVers is always exactly two digits
10269 snprintf(ver_num
, VER_NUM_LEN
+ 1, "%d", OSXVers
);
10270 mDNSPlatformMemCopy(ptr
, ver_num
, VER_NUM_LEN
);
10271 ptr
+= VER_NUM_LEN
;
10273 char rgb
[MODEL_RGB_VALUE_LEN
+ 1]; // RGB value + null written by snprintf
10274 len
= getModelIconColors(rgb
);
10277 *ptr
= MODEL_COLOR_LEN
+ len
; // length byte
10280 mDNSPlatformMemCopy(ptr
, MODEL_COLOR
, MODEL_COLOR_LEN
);
10281 ptr
+= MODEL_COLOR_LEN
;
10283 mDNSPlatformMemCopy(ptr
, rgb
, len
);
10288 return (ptr
- bufferStart
);
10291 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
10293 // Use the scalar version of SameDomainLabel() by default
10294 mDNSlocal mDNSBool
scalarSameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
);
10295 mDNSlocal mDNSBool
vectorSameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
);
10296 mDNSlocal
mDNSBool (*SameDomainLabelPointer
)(const mDNSu8
*a
, const mDNSu8
*b
) = scalarSameDomainLabel
;
10298 #include <System/machine/cpu_capabilities.h>
10299 #define _cpu_capabilities ((uint32_t*) _COMM_PAGE_CPU_CAPABILITIES)[0]
10301 #if TARGET_OS_EMBEDDED
10303 #include <arm_neon.h>
10305 // Cache line aligned table that returns 32 for the upper case letters.
10306 // This will take up 4 cache lines.
10307 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table
[256] = {
10308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10312 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
10313 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
10314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10318 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10319 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
10327 mDNSlocal mDNSBool
vectorSameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
10329 const int len
= *a
++;
10331 if (len
> MAX_DOMAIN_LABEL
)
10333 fprintf(stderr
, "v: Malformed label (too long)\n");
10342 uint32_t len_count
= len
;
10344 uint8x16_t vA
, vB
, vARotated
, vBRotated
, vMaskA
, vMaskB
;
10346 uint8x16_t v32
= vdupq_n_u8(32);
10347 uint8x16_t v37
= vdupq_n_u8(37);
10348 uint8x16_t v101
= vdupq_n_u8(101);
10349 #if !defined __arm64__
10350 uint32x4_t vtemp32
;
10351 uint32x2_t vtemp32d
;
10355 while(len_count
> 15)
10362 //Make vA to lowercase if there is any uppercase.
10363 vARotated
= vaddq_u8(vA
, v37
); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10364 vMaskA
= vcgtq_s8(vARotated
, v101
); //Check if anything is greater than '101' which means we have uppercase letters.
10365 vMaskA
= vandq_u8(vMaskA
, v32
); //Prepare 32 for the elements with uppercase letters.
10366 vA
= vaddq_u8(vA
, vMaskA
); //Add 32 only to the uppercase letters to make them lowercase letters.
10368 //Make vB to lowercase if there is any uppercase.
10369 vBRotated
= vaddq_u8(vB
, v37
); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10370 vMaskB
= vcgtq_s8(vBRotated
, v101
); //Check if anything is greater than '101' which means we have uppercase letters.
10371 vMaskB
= vandq_u8(vMaskB
, v32
); //Prepare 32 for the elements with uppercase letters.
10372 vB
= vaddq_u8(vB
, vMaskB
); //Add 32 only to the uppercase letters to make them lowercase letters.
10375 vA
= vceqq_u8(vA
, vB
);
10377 #if defined __arm64__
10378 //View 8-bit element as 32-bit => a3 a2 a1 a0
10379 //If min of 4 32-bit values in vA is 0xffffffff, then it means we have 0xff for all 16.
10380 if(vminvq_u32(vA
) != 0xffffffffU
)
10386 //See if any element was not same.
10387 //View 8-bit element as 16-bit => a7 a6 a5 a4 a3 a2 a1 a0
10388 //(a7+a6) (a5+a4) (a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
10389 vtemp32
= vpaddlq_u16(vA
);
10390 vtemp32d
= vpadd_u32(vget_low_u32(vtemp32
), vget_high_u32(vtemp32
));
10391 vtemp32d
= vpadd_u32(vtemp32d
, vtemp32d
);
10392 sum
= vget_lane_u32(vtemp32d
, 0);
10394 //0x0001fffe + 0x0001fffe + 0x0001fffe + 0x0001fffe = 0x0007fff8U when all same.
10395 if(sum
!= 0x0007fff8U
)
10404 uint8x8_t vAd
, vBd
, vARotatedd
, vBRotatedd
, vMaskAd
, vMaskBd
;
10406 uint8x8_t v32d
= vdup_n_u8(32);
10407 uint8x8_t v37d
= vdup_n_u8(37);
10408 uint8x8_t v101d
= vdup_n_u8(101);
10410 while(len_count
> 7)
10417 //Make vA to lowercase if there is any uppercase.
10418 vARotatedd
= vadd_u8(vAd
, v37d
); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10419 vMaskAd
= vcgt_s8(vARotatedd
, v101d
); //Check if anything is greater than '101' which means we have uppercase letters.
10420 vMaskAd
= vand_u8(vMaskAd
, v32d
); //Prepare 32 for the elements with uppercase letters.
10421 vAd
= vadd_u8(vAd
, vMaskAd
); //Add 32 only to the uppercase letters to make them lowercase letters.
10423 //Make vB to lowercase if there is any uppercase.
10424 vBRotatedd
= vadd_u8(vBd
, v37d
); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10425 vMaskBd
= vcgt_s8(vBRotatedd
, v101d
); //Check if anything is greater than '101' which means we have uppercase letters.
10426 vMaskBd
= vand_u8(vMaskBd
, v32d
); //Prepare 32 for the elements with uppercase letters.
10427 vBd
= vadd_u8(vBd
, vMaskBd
); //Add 32 only to the uppercase letters to make them lowercase letters.
10430 vAd
= vceq_u8(vAd
, vBd
);
10432 #if defined __arm64__
10433 //View 8-bit element as 32-bit => a1 a0
10434 //If min of 2 32-bit values in vAd is 0xffffffff, then it means we have 0xff for all 16.
10435 if(vminv_u32(vAd
) != 0xffffffffU
)
10441 //See if any element was not same.
10442 //View 8-bit element as 16-bit => a3 a2 a1 a0
10443 //(a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
10444 vtemp32d
= vpaddl_u16(vAd
);
10445 vtemp32d
= vpadd_u32(vtemp32d
, vtemp32d
);
10446 sum
= vget_lane_u32(vtemp32d
, 0);
10448 //0x0001fffe + 0x0001fffe = 0x0003fffc when all same.
10449 if(sum
!= 0x0003fffcU
)
10458 while(len_count
> 0)
10463 ac
+= upper_to_lower_case_table
[ac
];
10464 bc
+= upper_to_lower_case_table
[bc
];
10476 // Use vectorized implementation if it is supported on this platform.
10477 mDNSlocal
void setSameDomainLabelPointer(void)
10479 if(_cpu_capabilities
& kHasNeon
)
10482 SameDomainLabelPointer
= vectorSameDomainLabel
;
10483 LogMsg("setSameDomainLabelPointer: using vector code");
10486 LogMsg("setSameDomainLabelPointer: using scalar code");
10489 #else // TARGET_OS_EMBEDDED
10491 #include <smmintrin.h>
10493 // Cache line aligned table that returns 32 for the upper case letters.
10494 // This will take up 4 cache lines.
10495 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table
[256] = {
10496 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10497 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10498 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10499 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10500 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
10501 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
10502 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10503 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10504 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10505 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10506 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10507 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10508 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10510 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10511 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
10515 mDNSlocal mDNSBool
vectorSameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
10517 const int len
= *a
++;
10519 if (len
> MAX_DOMAIN_LABEL
)
10521 fprintf(stderr
, "v: Malformed label (too long)\n");
10530 uint32_t len_count
= len
;
10532 static const __attribute__ ((aligned(16))) unsigned char c_32
[16] = { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 };
10533 static const __attribute__ ((aligned(16))) unsigned char c_37
[16] = { 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37 };
10534 static const __attribute__ ((aligned(16))) unsigned char c_101
[16] = { 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101 };
10535 __m128i v37
= _mm_load_si128((__m128i
*)c_37
);
10536 __m128i v101
= _mm_load_si128((__m128i
*)c_101
);
10537 __m128i v32
= _mm_load_si128((__m128i
*)c_32
);
10540 __m128i vA
, vB
, vARotated
, vBRotated
, vMaskA
, vMaskB
;
10542 //AVX code that uses higher bandwidth (more elements per vector) was removed
10543 //to speed up the processing on the small sizes.
10544 //When I had them, the performance of 1 ~ 8 characters were slower by about 10% ~ 30%.
10545 while(len_count
> 15)
10547 vA
= _mm_loadu_si128((__m128i
*)a
);
10548 vB
= _mm_loadu_si128((__m128i
*)b
);
10552 //Make vA to lowercase if there is any uppercase.
10553 vARotated
= _mm_add_epi8(vA
, v37
); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10554 vMaskA
= _mm_cmpgt_epi8(vARotated
, v101
); //Check if anything is greater than '101' which means we have uppercase letters.
10555 vMaskA
= _mm_and_si128(vMaskA
, v32
); //Prepare 32 for the elements with uppercase letters.
10556 vA
= _mm_add_epi8(vA
, vMaskA
); //Add 32 only to the uppercase letters to make them lowercase letters.
10558 //Make vB to lowercase if there is any uppercase.
10559 vBRotated
= _mm_add_epi8(vB
, v37
); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10560 vMaskB
= _mm_cmpgt_epi8(vBRotated
, v101
); //Check if anything is greater than '101' which means we have uppercase letters.
10561 vMaskB
= _mm_and_si128(vMaskB
, v32
); //Prepare 32 for the elements with uppercase letters.
10562 vB
= _mm_add_epi8(vB
, vMaskB
); //Add 32 only to the uppercase letters to make them lowercase letters.
10565 vA
= _mm_cmpeq_epi8(vA
, vB
);
10567 //Return if any different.
10568 is_equal
= _mm_movemask_epi8(vA
);
10569 is_equal
= is_equal
& 0xffff;
10570 if(is_equal
!= 0xffff)
10578 while(len_count
> 0)
10583 //Table will return 32 for upper case letters only.
10584 //0 will be returned for all others.
10585 ac
+= upper_to_lower_case_table
[ac
];
10586 bc
+= upper_to_lower_case_table
[bc
];
10588 //Return if a & b are different.
10599 // Use vectorized implementation if it is supported on this platform.
10600 mDNSlocal
void setSameDomainLabelPointer(void)
10602 if(_cpu_capabilities
& kHasSSE4_1
)
10605 SameDomainLabelPointer
= vectorSameDomainLabel
;
10606 LogMsg("setSameDomainLabelPointer: using vector code");
10609 LogMsg("setSameDomainLabelPointer: using scalar code");
10612 #endif // TARGET_OS_EMBEDDED
10614 // Original SameDomainLabel() implementation.
10615 mDNSlocal mDNSBool
scalarSameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
10618 const int len
= *a
++;
10620 if (len
> MAX_DOMAIN_LABEL
)
10621 { debugf("Malformed label (too long)"); return(mDNSfalse
); }
10623 if (len
!= *b
++) return(mDNSfalse
);
10624 for (i
=0; i
<len
; i
++)
10628 if (mDNSIsUpperCase(ac
)) ac
+= 'a' - 'A';
10629 if (mDNSIsUpperCase(bc
)) bc
+= 'a' - 'A';
10630 if (ac
!= bc
) return(mDNSfalse
);
10635 mDNSexport mDNSBool
SameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
10637 return (*SameDomainLabelPointer
)(a
, b
);
10640 #endif // APPLE_OSX_mDNSResponder
10644 #include "../unittests/mdns_macosx_ut.c"