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 mDNSexport 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_controllen
< (int)sizeof(struct cmsghdr
))
858 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d",
859 s
, n
, msg
.msg_controllen
, sizeof(struct cmsghdr
), errno
);
862 if (msg
.msg_flags
& MSG_CTRUNC
)
864 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
868 *fromlen
= msg
.msg_namelen
;
870 // Parse each option out of the ancillary data.
871 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
873 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
874 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
876 dstaddr
->type
= mDNSAddrType_IPv4
;
877 dstaddr
->ip
.v4
= *(mDNSv4Addr
*)CMSG_DATA(cmPtr
);
878 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
880 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
882 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
883 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
885 mDNSPlatformMemCopy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
886 ifname
[sdl
->sdl_nlen
] = 0;
887 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
890 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
891 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
892 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
894 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
895 dstaddr
->type
= mDNSAddrType_IPv6
;
896 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
897 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
899 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
900 *ttl
= *(int*)CMSG_DATA(cmPtr
);
906 // What is this for, and why does it use xor instead of a simple quality check? -- SC
907 mDNSlocal mDNSInterfaceID
FindMyInterface(const mDNSAddr
*addr
)
909 NetworkInterfaceInfo
*intf
;
911 if (addr
->type
== mDNSAddrType_IPv4
)
913 for (intf
= mDNSStorage
.HostInterfaces
; intf
; intf
= intf
->next
)
915 if (intf
->ip
.type
== addr
->type
&& intf
->McastTxRx
)
917 if ((intf
->ip
.ip
.v4
.NotAnInteger
^ addr
->ip
.v4
.NotAnInteger
) == 0)
919 return(intf
->InterfaceID
);
925 if (addr
->type
== mDNSAddrType_IPv6
)
927 for (intf
= mDNSStorage
.HostInterfaces
; intf
; intf
= intf
->next
)
929 if (intf
->ip
.type
== addr
->type
&& intf
->McastTxRx
)
931 if (((intf
->ip
.ip
.v6
.l
[0] ^ addr
->ip
.v6
.l
[0]) == 0) &&
932 ((intf
->ip
.ip
.v6
.l
[1] ^ addr
->ip
.v6
.l
[1]) == 0) &&
933 ((intf
->ip
.ip
.v6
.l
[2] ^ addr
->ip
.v6
.l
[2]) == 0) &&
934 (((intf
->ip
.ip
.v6
.l
[3] ^ addr
->ip
.v6
.l
[3]) == 0)))
936 return(intf
->InterfaceID
);
941 return(mDNSInterface_Any
);
944 mDNSexport
void myKQSocketCallBack(int s1
, short filter
, void *context
, mDNSBool encounteredEOF
)
946 KQSocketSet
*const ss
= (KQSocketSet
*)context
;
947 mDNS
*const m
= ss
->m
;
948 int err
= 0, count
= 0, closed
= 0;
950 if (filter
!= EVFILT_READ
)
951 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter
, EVFILT_READ
);
953 if (s1
!= ss
->sktv4
&& s1
!= ss
->sktv6
)
955 LogMsg("myKQSocketCallBack: native socket %d", s1
);
956 LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss
->sktv4
, ss
->sktv6
);
961 LogMsg("myKQSocketCallBack: socket %d is no longer readable (EOF)", s1
);
964 ss
->sktv4EOF
= mDNStrue
;
965 KQueueSet(ss
->sktv4
, EV_DELETE
, EVFILT_READ
, &ss
->kqsv4
);
967 else if (s1
== ss
->sktv6
)
969 ss
->sktv6EOF
= mDNStrue
;
970 KQueueSet(ss
->sktv6
, EV_DELETE
, EVFILT_READ
, &ss
->kqsv6
);
977 mDNSAddr senderAddr
, destAddr
= zeroAddr
;
978 mDNSIPPort senderPort
;
979 struct sockaddr_storage from
;
980 size_t fromlen
= sizeof(from
);
981 char packetifname
[IF_NAMESIZE
] = "";
983 err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
986 if ((destAddr
.type
== mDNSAddrType_IPv4
&& (destAddr
.ip
.v4
.b
[0] & 0xF0) == 0xE0) ||
987 (destAddr
.type
== mDNSAddrType_IPv6
&& (destAddr
.ip
.v6
.b
[0] == 0xFF))) m
->p
->num_mcasts
++;
990 if (from
.ss_family
== AF_INET
)
992 struct sockaddr_in
*s
= (struct sockaddr_in
*)&from
;
993 senderAddr
.type
= mDNSAddrType_IPv4
;
994 senderAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
995 senderPort
.NotAnInteger
= s
->sin_port
;
996 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
998 else if (from
.ss_family
== AF_INET6
)
1000 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
1001 senderAddr
.type
= mDNSAddrType_IPv6
;
1002 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
1003 senderPort
.NotAnInteger
= sin6
->sin6_port
;
1004 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1008 LogMsg("myKQSocketCallBack from is unknown address family %d", from
.ss_family
);
1012 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1013 mDNSInterfaceID InterfaceID
= mDNSNULL
;
1014 NetworkInterfaceInfoOSX
*intf
= m
->p
->InterfaceList
;
1017 if (intf
->Exists
&& !strcmp(intf
->ifinfo
.ifname
, packetifname
))
1022 // When going to sleep we deregister all our interfaces, but if the machine
1023 // takes a few seconds to sleep we may continue to receive multicasts
1024 // during that time, which would confuse mDNSCoreReceive, because as far
1025 // as it's concerned, we should have no active interfaces any more.
1026 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1028 InterfaceID
= intf
->ifinfo
.InterfaceID
;
1029 else if (mDNSAddrIsDNSMulticast(&destAddr
))
1034 InterfaceID
= FindMyInterface(&destAddr
);
1037 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1038 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
1040 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
1041 // loop when that happens, or we may try to read from an invalid FD. We do this by
1042 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
1043 // if it closes the socketset.
1044 ss
->closeFlag
= &closed
;
1048 m
->p
->UDPProxyCallback(&m
->p
->UDPProxy
, &m
->imsg
.m
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
,
1049 senderPort
, &destAddr
, ss
->port
, InterfaceID
, NULL
);
1053 mDNSCoreReceive(m
, &m
->imsg
.m
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, ss
->port
, InterfaceID
);
1056 // if we didn't close, we can safely dereference the socketset, and should to
1057 // reset the closeFlag, since it points to something on the stack
1058 if (!closed
) ss
->closeFlag
= mDNSNULL
;
1061 // If a client application's sockets are marked as defunct
1062 // sockets we have delegated to it with SO_DELEGATED will also go defunct.
1063 // We get an ENOTCONN error for defunct sockets and should just close the socket in that case.
1064 if (err
< 0 && errno
== ENOTCONN
)
1066 LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
1071 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
1073 // Something is busted here.
1074 // kqueue says there is a packet, but myrecvfrom says there is not.
1075 // Try calling select() to get another opinion.
1076 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1077 // All of this is racy, as data may have arrived after the call to select()
1078 static unsigned int numLogMessages
= 0;
1079 const int save_errno
= errno
;
1083 socklen_t solen
= sizeof(int);
1085 struct timeval timeout
;
1088 FD_SET(s1
, &readfds
);
1090 timeout
.tv_usec
= 0;
1091 selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
1092 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
1093 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
1094 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
1095 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
1096 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
1097 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno
);
1098 if (numLogMessages
++ < 100)
1099 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1100 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
1101 if (numLogMessages
> 5)
1102 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1103 "Congratulations, you've reproduced an elusive bug.\r"
1104 "Please send email to radar-3387020@group.apple.com.)\r"
1105 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1107 sleep(1); // After logging this error, rate limit so we don't flood syslog
1111 mDNSlocal
void doTcpSocketCallback(TCPSocket
*sock
)
1113 mDNSBool c
= !sock
->connected
;
1114 sock
->connected
= mDNStrue
;
1115 sock
->callback(sock
, sock
->context
, c
, sock
->err
);
1116 // Note: the callback may call CloseConnection here, which frees the context structure!
1119 #ifndef NO_SECURITYFRAMEWORK
1121 mDNSlocal OSStatus
tlsWriteSock(SSLConnectionRef connection
, const void *data
, size_t *dataLength
)
1123 int ret
= send(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1124 if (ret
>= 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1125 if (ret
>= 0) { *dataLength
= ret
; return(noErr
); }
1127 if (errno
== EAGAIN
) return(errSSLWouldBlock
);
1128 if (errno
== ENOENT
) return(errSSLClosedGraceful
);
1129 if (errno
== EPIPE
|| errno
== ECONNRESET
) return(errSSLClosedAbort
);
1130 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket
*)connection
)->fd
, errno
, strerror(errno
));
1131 return(errSSLClosedAbort
);
1134 mDNSlocal OSStatus
tlsReadSock(SSLConnectionRef connection
, void *data
, size_t *dataLength
)
1136 int ret
= recv(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1137 if (ret
> 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1138 if (ret
> 0) { *dataLength
= ret
; return(noErr
); }
1140 if (ret
== 0 || errno
== ENOENT
) return(errSSLClosedGraceful
);
1141 if ( errno
== EAGAIN
) return(errSSLWouldBlock
);
1142 if ( errno
== ECONNRESET
) return(errSSLClosedAbort
);
1143 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno
, strerror(errno
));
1144 return(errSSLClosedAbort
);
1147 mDNSlocal OSStatus
tlsSetupSock(TCPSocket
*sock
, SSLProtocolSide pside
, SSLConnectionType ctype
)
1149 char domname_cstr
[MAX_ESCAPED_DOMAIN_NAME
];
1151 sock
->tlsContext
= SSLCreateContext(kCFAllocatorDefault
, pside
, ctype
);
1152 if (!sock
->tlsContext
)
1154 LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
1155 return(mStatus_UnknownErr
);
1158 mStatus err
= SSLSetIOFuncs(sock
->tlsContext
, tlsReadSock
, tlsWriteSock
);
1161 LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err
);
1165 err
= SSLSetConnection(sock
->tlsContext
, (SSLConnectionRef
) sock
);
1168 LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err
);
1172 // Set the default ciphersuite configuration
1173 err
= SSLSetSessionConfig(sock
->tlsContext
, CFSTR("default"));
1176 LogMsg("ERROR: tlsSetupSock: SSLSetSessionConfig failed with error code: %d", err
);
1180 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
1181 // (error not in OSStatus space) is okay.
1182 if (!sock
->hostname
.c
[0])
1184 LogMsg("ERROR: tlsSetupSock: hostname NULL");
1189 ConvertDomainNameToCString(&sock
->hostname
, domname_cstr
);
1190 err
= SSLSetPeerDomainName(sock
->tlsContext
, domname_cstr
, strlen(domname_cstr
));
1193 LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr
, err
);
1200 if (sock
->tlsContext
)
1201 CFRelease(sock
->tlsContext
);
1205 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1206 mDNSlocal
void doSSLHandshake(TCPSocket
*sock
)
1208 mStatus err
= SSLHandshake(sock
->tlsContext
);
1210 //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
1211 //defined, KQueueLock is a noop. Hence we need to serialize here
1213 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
1214 //We need the rest of the logic also. Otherwise, we can enable the READ
1215 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
1216 //ConnFailed which means we are going to free the tcpInfo. While it
1217 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
1218 //and potentially call doTCPCallback with error which can close the fd and free the
1219 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
1222 dispatch_async(dispatch_get_main_queue(), ^{
1224 LogInfo("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
1226 if (sock
->handshake
== handshake_to_be_closed
)
1228 LogInfo("SSLHandshake completed after close");
1229 mDNSPlatformTCPCloseConnection(sock
);
1233 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1234 else LogMsg("doSSLHandshake: sock->fd is -1");
1236 if (err
== errSSLWouldBlock
)
1237 sock
->handshake
= handshake_required
;
1242 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
1243 CFRelease(sock
->tlsContext
);
1244 sock
->tlsContext
= NULL
;
1247 sock
->err
= err
? mStatus_ConnFailed
: 0;
1248 sock
->handshake
= handshake_completed
;
1250 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
1251 doTcpSocketCallback(sock
);
1255 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
1259 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1260 mDNSlocal
void *doSSLHandshake(TCPSocket
*sock
)
1262 // Warning: Touching sock without the kqueue lock!
1263 // We're protected because sock->handshake == handshake_in_progress
1264 mStatus err
= SSLHandshake(sock
->tlsContext
);
1267 debugf("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
1269 if (sock
->handshake
== handshake_to_be_closed
)
1271 LogInfo("SSLHandshake completed after close");
1272 mDNSPlatformTCPCloseConnection(sock
);
1276 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1277 else LogMsg("doSSLHandshake: sock->fd is -1");
1279 if (err
== errSSLWouldBlock
)
1280 sock
->handshake
= handshake_required
;
1285 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
1286 CFRelease(sock
->tlsContext
);
1287 sock
->tlsContext
= NULL
;
1290 sock
->err
= err
? mStatus_ConnFailed
: 0;
1291 sock
->handshake
= handshake_completed
;
1293 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
1294 doTcpSocketCallback(sock
);
1298 debugf("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
1299 KQueueUnlock("doSSLHandshake");
1302 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1304 mDNSlocal
void spawnSSLHandshake(TCPSocket
* sock
)
1306 debugf("spawnSSLHandshake %p: entry", sock
);
1308 if (sock
->handshake
!= handshake_required
) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock
->handshake
);
1309 sock
->handshake
= handshake_in_progress
;
1310 KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_READ
, sock
->kqEntry
);
1312 // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
1313 // to limit the number of threads used for SSLHandshake
1314 dispatch_async(SSLqueue
, ^{doSSLHandshake(sock
);});
1316 debugf("spawnSSLHandshake %p: done for %d", sock
, sock
->fd
);
1319 #endif /* NO_SECURITYFRAMEWORK */
1321 mDNSlocal
void tcpKQSocketCallback(__unused
int fd
, short filter
, void *context
, __unused mDNSBool encounteredEOF
)
1323 TCPSocket
*sock
= context
;
1324 sock
->err
= mStatus_NoError
;
1326 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1327 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1328 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1329 if (filter
== EVFILT_WRITE
)
1330 KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_WRITE
, sock
->kqEntry
);
1332 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1334 #ifndef NO_SECURITYFRAMEWORK
1337 sock
->setup
= mDNStrue
;
1338 sock
->err
= tlsSetupSock(sock
, kSSLClientSide
, kSSLStreamType
);
1341 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock
->err
);
1345 if (sock
->handshake
== handshake_required
)
1347 spawnSSLHandshake(sock
);
1350 else if (sock
->handshake
== handshake_in_progress
|| sock
->handshake
== handshake_to_be_closed
)
1354 else if (sock
->handshake
!= handshake_completed
)
1357 sock
->err
= mStatus_UnknownErr
;
1358 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock
->handshake
);
1360 #else /* NO_SECURITYFRAMEWORK */
1361 sock
->err
= mStatus_UnsupportedErr
;
1362 #endif /* NO_SECURITYFRAMEWORK */
1365 doTcpSocketCallback(sock
);
1368 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1369 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, KQueueEntry
*const entryRef
)
1371 dispatch_queue_t queue
= dispatch_get_main_queue();
1372 dispatch_source_t source
;
1373 if (flags
== EV_DELETE
)
1375 if (filter
== EVFILT_READ
)
1377 dispatch_source_cancel(entryRef
->readSource
);
1378 dispatch_release(entryRef
->readSource
);
1379 entryRef
->readSource
= mDNSNULL
;
1380 debugf("KQueueSet: source cancel for read %p, %p", entryRef
->readSource
, entryRef
->writeSource
);
1382 else if (filter
== EVFILT_WRITE
)
1384 dispatch_source_cancel(entryRef
->writeSource
);
1385 dispatch_release(entryRef
->writeSource
);
1386 entryRef
->writeSource
= mDNSNULL
;
1387 debugf("KQueueSet: source cancel for write %p, %p", entryRef
->readSource
, entryRef
->writeSource
);
1390 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter
);
1393 if (flags
!= EV_ADD
) LogMsg("KQueueSet: Invalid flags %d", flags
);
1395 if (filter
== EVFILT_READ
)
1397 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, fd
, 0, queue
);
1399 else if (filter
== EVFILT_WRITE
)
1401 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE
, fd
, 0, queue
);
1405 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter
);
1408 if (!source
) return -1;
1409 dispatch_source_set_event_handler(source
, ^{
1411 mDNSs32 stime
= mDNSPlatformRawTime();
1412 entryRef
->KQcallback(fd
, filter
, entryRef
->KQcontext
);
1413 mDNSs32 etime
= mDNSPlatformRawTime();
1414 if (etime
- stime
>= WatchDogReportingThreshold
)
1415 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime
- stime
);
1417 // Trigger the event delivery to the application. Even though we trigger the
1418 // event completion after handling every event source, these all will hopefully
1420 TriggerEventCompletion();
1423 dispatch_source_set_cancel_handler(source
, ^{
1424 if (entryRef
->fdClosed
)
1426 //LogMsg("CancelHandler: closing fd %d", fd);
1430 dispatch_resume(source
);
1431 if (filter
== EVFILT_READ
)
1432 entryRef
->readSource
= source
;
1434 entryRef
->writeSource
= source
;
1439 mDNSexport
void KQueueLock()
1442 mDNSexport
void KQueueUnlock(const char const *task
)
1444 (void)task
; //unused
1447 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, const KQueueEntry
*const entryRef
)
1449 struct kevent new_event
;
1450 EV_SET(&new_event
, fd
, filter
, flags
, 0, 0, (void*)entryRef
);
1451 return (kevent(KQueueFD
, &new_event
, 1, NULL
, 0, NULL
) < 0) ? errno
: 0;
1454 mDNSexport
void KQueueLock()
1456 mDNS
*const m
= &mDNSStorage
;
1457 pthread_mutex_lock(&m
->p
->BigMutex
);
1458 m
->p
->BigMutexStartTime
= mDNSPlatformRawTime();
1461 mDNSexport
void KQueueUnlock(const char* task
)
1463 mDNS
*const m
= &mDNSStorage
;
1464 mDNSs32 end
= mDNSPlatformRawTime();
1466 if (end
- m
->p
->BigMutexStartTime
>= WatchDogReportingThreshold
)
1467 LogInfo("WARNING: %s took %dms to complete", task
, end
- m
->p
->BigMutexStartTime
);
1469 pthread_mutex_unlock(&m
->p
->BigMutex
);
1472 if (send(m
->p
->WakeKQueueLoopFD
, &wake
, sizeof(wake
), 0) == -1)
1473 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno
, strerror(errno
));
1477 mDNSexport
void mDNSPlatformCloseFD(KQueueEntry
*kq
, int fd
)
1479 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1483 dispatch_source_cancel(kq
->readSource
);
1484 kq
->readSource
= mDNSNULL
;
1486 if (kq
->writeSource
)
1488 dispatch_source_cancel(kq
->writeSource
);
1489 kq
->writeSource
= mDNSNULL
;
1491 // Close happens in the cancellation handler
1492 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd
);
1493 kq
->fdClosed
= mDNStrue
;
1500 mDNSlocal mStatus
SetupTCPSocket(TCPSocket
*sock
, u_short sa_family
, mDNSIPPort
*port
, mDNSBool useBackgroundTrafficClass
)
1502 KQSocketSet
*cp
= &sock
->ss
;
1503 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1504 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1505 const int on
= 1; // "on" for setsockopt
1508 int skt
= socket(sa_family
, SOCK_STREAM
, IPPROTO_TCP
);
1509 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
));return(skt
); }
1511 // for TCP sockets, the traffic class is set once and not changed
1512 setTrafficClass(skt
, useBackgroundTrafficClass
);
1514 if (sa_family
== AF_INET
)
1517 struct sockaddr_in addr
;
1518 mDNSPlatformMemZero(&addr
, sizeof(addr
));
1519 addr
.sin_family
= AF_INET
;
1520 addr
.sin_port
= port
->NotAnInteger
;
1521 err
= bind(skt
, (struct sockaddr
*) &addr
, sizeof(addr
));
1522 if (err
< 0) { LogMsg("ERROR: bind %s", strerror(errno
)); close(skt
); return err
; }
1524 // Receive interface identifiers
1525 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1526 if (err
< 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
)); close(skt
); return err
; }
1528 mDNSPlatformMemZero(&addr
, sizeof(addr
));
1529 socklen_t len
= sizeof(addr
);
1530 err
= getsockname(skt
, (struct sockaddr
*) &addr
, &len
);
1531 if (err
< 0) { LogMsg("getsockname - %s", strerror(errno
)); close(skt
); return err
; }
1533 port
->NotAnInteger
= addr
.sin_port
;
1538 struct sockaddr_in6 addr6
;
1539 mDNSPlatformMemZero(&addr6
, sizeof(addr6
));
1540 addr6
.sin6_family
= AF_INET6
;
1541 addr6
.sin6_port
= port
->NotAnInteger
;
1542 err
= bind(skt
, (struct sockaddr
*) &addr6
, sizeof(addr6
));
1543 if (err
< 0) { LogMsg("ERROR: bind6 %s", strerror(errno
)); close(skt
); return err
; }
1545 // We want to receive destination addresses and receive interface identifiers
1546 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
1547 if (err
< 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno
)); close(skt
); return err
; }
1549 mDNSPlatformMemZero(&addr6
, sizeof(addr6
));
1550 socklen_t len
= sizeof(addr6
);
1551 err
= getsockname(skt
, (struct sockaddr
*) &addr6
, &len
);
1552 if (err
< 0) { LogMsg("getsockname6 - %s", strerror(errno
)); close(skt
); return err
; }
1554 port
->NotAnInteger
= addr6
.sin6_port
;
1558 k
->KQcallback
= tcpKQSocketCallback
;
1559 k
->KQcontext
= sock
;
1560 k
->KQtask
= "mDNSPlatformTCPSocket";
1561 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1562 k
->readSource
= mDNSNULL
;
1563 k
->writeSource
= mDNSNULL
;
1564 k
->fdClosed
= mDNSfalse
;
1566 return mStatus_NoError
;
1569 mDNSexport TCPSocket
*mDNSPlatformTCPSocket(TCPSocketFlags flags
, mDNSIPPort
*port
, mDNSBool useBackgroundTrafficClass
)
1573 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket
));
1574 if (!sock
) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL
); }
1576 mDNSPlatformMemZero(sock
, sizeof(TCPSocket
));
1578 sock
->ss
.m
= &mDNSStorage
;
1579 sock
->ss
.sktv4
= -1;
1580 sock
->ss
.sktv6
= -1;
1581 err
= SetupTCPSocket(sock
, AF_INET
, port
, useBackgroundTrafficClass
);
1585 err
= SetupTCPSocket(sock
, AF_INET6
, port
, useBackgroundTrafficClass
);
1586 if (err
) { mDNSPlatformCloseFD(&sock
->ss
.kqsv4
, sock
->ss
.sktv4
); sock
->ss
.sktv4
= -1; }
1590 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock
->fd
, errno
, strerror(errno
));
1591 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1594 // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
1595 sock
->fd
= sock
->ss
.sktv4
;
1596 sock
->callback
= mDNSNULL
;
1597 sock
->flags
= flags
;
1598 sock
->context
= mDNSNULL
;
1599 sock
->setup
= mDNSfalse
;
1600 sock
->connected
= mDNSfalse
;
1601 sock
->handshake
= handshake_required
;
1602 sock
->m
= &mDNSStorage
;
1603 sock
->err
= mStatus_NoError
;
1608 mDNSexport mStatus
mDNSPlatformTCPConnect(TCPSocket
*sock
, const mDNSAddr
*dst
, mDNSOpaque16 dstport
, domainname
*hostname
, mDNSInterfaceID InterfaceID
, TCPConnectionCallback callback
, void *context
)
1610 KQSocketSet
*cp
= &sock
->ss
;
1611 int *s
= (dst
->type
== mDNSAddrType_IPv4
) ? &cp
->sktv4
: &cp
->sktv6
;
1612 KQueueEntry
*k
= (dst
->type
== mDNSAddrType_IPv4
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1613 mStatus err
= mStatus_NoError
;
1614 struct sockaddr_storage ss
;
1616 sock
->callback
= callback
;
1617 sock
->context
= context
;
1618 sock
->setup
= mDNSfalse
;
1619 sock
->connected
= mDNSfalse
;
1620 sock
->handshake
= handshake_required
;
1621 sock
->err
= mStatus_NoError
;
1623 if (hostname
) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname
->c
); AssignDomainName(&sock
->hostname
, hostname
); }
1625 if (dst
->type
== mDNSAddrType_IPv4
)
1627 struct sockaddr_in
*saddr
= (struct sockaddr_in
*)&ss
;
1628 mDNSPlatformMemZero(saddr
, sizeof(*saddr
));
1629 saddr
->sin_family
= AF_INET
;
1630 saddr
->sin_port
= dstport
.NotAnInteger
;
1631 saddr
->sin_len
= sizeof(*saddr
);
1632 saddr
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1636 struct sockaddr_in6
*saddr6
= (struct sockaddr_in6
*)&ss
;
1637 mDNSPlatformMemZero(saddr6
, sizeof(*saddr6
));
1638 saddr6
->sin6_family
= AF_INET6
;
1639 saddr6
->sin6_port
= dstport
.NotAnInteger
;
1640 saddr6
->sin6_len
= sizeof(*saddr6
);
1641 saddr6
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1644 // Watch for connect complete (write is ready)
1645 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1646 if (KQueueSet(*s
, EV_ADD
/* | EV_ONESHOT */, EVFILT_WRITE
, k
))
1648 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1652 // Watch for incoming data
1653 if (KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
))
1655 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1659 if (fcntl(*s
, F_SETFL
, fcntl(*s
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
1661 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1662 return mStatus_UnknownErr
;
1665 // We bind to the interface and all subsequent packets including the SYN will be sent out
1666 // on this interface
1668 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
1669 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
1670 if (InterfaceID
&& InterfaceID
!= mDNSInterface_Unicast
)
1672 NetworkInterfaceInfoOSX
*info
= IfindexToInterfaceInfoOSX(InterfaceID
);
1673 if (dst
->type
== mDNSAddrType_IPv4
)
1676 if (info
) setsockopt(*s
, IPPROTO_IP
, IP_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1677 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID
); return mStatus_BadParamErr
; }
1679 (void)InterfaceID
; // Unused
1680 (void)info
; // Unused
1685 #ifdef IPV6_BOUND_IF
1686 if (info
) setsockopt(*s
, IPPROTO_IPV6
, IPV6_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1687 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID
); return mStatus_BadParamErr
; }
1689 (void)InterfaceID
; // Unused
1690 (void)info
; // Unused
1695 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
1696 // from which we can infer the destination address family. Hence we need to remember that here.
1697 // Instead of remembering the address family, we remember the right fd.
1700 // initiate connection wth peer
1701 if (connect(*s
, (struct sockaddr
*)&ss
, ss
.ss_len
) < 0)
1703 if (errno
== EINPROGRESS
) return mStatus_ConnPending
;
1704 if (errno
== EHOSTUNREACH
|| errno
== EADDRNOTAVAIL
|| errno
== ENETDOWN
)
1705 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock
->fd
, errno
, strerror(errno
));
1707 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock
->fd
, errno
, strerror(errno
), ss
.ss_len
);
1708 return mStatus_ConnFailed
;
1711 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1712 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1716 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1717 mDNSexport TCPSocket
*mDNSPlatformTCPAccept(TCPSocketFlags flags
, int fd
)
1719 mStatus err
= mStatus_NoError
;
1721 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket
));
1722 if (!sock
) return(mDNSNULL
);
1724 mDNSPlatformMemZero(sock
, sizeof(*sock
));
1726 sock
->flags
= flags
;
1728 if (flags
& kTCPSocketFlags_UseTLS
)
1730 #ifndef NO_SECURITYFRAMEWORK
1731 if (!ServerCerts
) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err
= mStatus_UnknownErr
; goto exit
; }
1733 err
= tlsSetupSock(sock
, kSSLServerSide
, kSSLStreamType
);
1734 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err
); goto exit
; }
1736 err
= SSLSetCertificate(sock
->tlsContext
, ServerCerts
);
1737 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err
); goto exit
; }
1739 err
= mStatus_UnsupportedErr
;
1740 #endif /* NO_SECURITYFRAMEWORK */
1742 #ifndef NO_SECURITYFRAMEWORK
1746 if (err
) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock
); return(mDNSNULL
); }
1750 mDNSexport mDNSu16
mDNSPlatformGetUDPPort(UDPSocket
*sock
)
1757 port
= sock
->ss
.port
.NotAnInteger
;
1762 mDNSlocal
void CloseSocketSet(KQSocketSet
*ss
)
1764 if (ss
->sktv4
!= -1)
1766 mDNSPlatformCloseFD(&ss
->kqsv4
, ss
->sktv4
);
1769 if (ss
->sktv6
!= -1)
1771 mDNSPlatformCloseFD(&ss
->kqsv6
, ss
->sktv6
);
1774 if (ss
->closeFlag
) *ss
->closeFlag
= 1;
1777 mDNSexport
void mDNSPlatformTCPCloseConnection(TCPSocket
*sock
)
1781 #ifndef NO_SECURITYFRAMEWORK
1782 if (sock
->tlsContext
)
1784 if (sock
->handshake
== handshake_in_progress
) // SSLHandshake thread using this sock (esp. tlsContext)
1786 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
1787 // When we come back from SSLHandshake, we will notice that a close was here and
1788 // call this function again which will do the cleanup then.
1789 sock
->handshake
= handshake_to_be_closed
;
1793 SSLClose(sock
->tlsContext
);
1794 CFRelease(sock
->tlsContext
);
1795 sock
->tlsContext
= NULL
;
1797 #endif /* NO_SECURITYFRAMEWORK */
1798 if (sock
->ss
.sktv4
!= -1)
1799 shutdown(sock
->ss
.sktv4
, 2);
1800 if (sock
->ss
.sktv6
!= -1)
1801 shutdown(sock
->ss
.sktv6
, 2);
1802 CloseSocketSet(&sock
->ss
);
1805 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock
);
1809 mDNSexport
long mDNSPlatformReadTCP(TCPSocket
*sock
, void *buf
, unsigned long buflen
, mDNSBool
*closed
)
1812 *closed
= mDNSfalse
;
1814 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1816 #ifndef NO_SECURITYFRAMEWORK
1817 if (sock
->handshake
== handshake_required
) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
1818 else if (sock
->handshake
== handshake_in_progress
) return 0;
1819 else if (sock
->handshake
!= handshake_completed
) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock
->handshake
);
1821 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
1822 mStatus err
= SSLRead(sock
->tlsContext
, buf
, buflen
, (size_t *)&nread
);
1823 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
1824 if (err
== errSSLClosedGraceful
) { nread
= 0; *closed
= mDNStrue
; }
1825 else if (err
&& err
!= errSSLWouldBlock
)
1826 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err
); nread
= -1; *closed
= mDNStrue
; }
1830 #endif /* NO_SECURITYFRAMEWORK */
1834 static int CLOSEDcount
= 0;
1835 static int EAGAINcount
= 0;
1836 nread
= recv(sock
->fd
, buf
, buflen
, 0);
1842 } // On success, clear our error counters
1843 else if (nread
== 0)
1846 if ((++CLOSEDcount
% 1000) == 0)
1848 LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock
->fd
, CLOSEDcount
);
1849 assert(CLOSEDcount
< 1000);
1850 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
1851 // crash mDNSResponder using assert() and restart fresh. See advantages below:
1852 // 1.Better User Experience
1853 // 2.CrashLogs frequency can be monitored
1854 // 3.StackTrace can be used for more info
1857 // else nread is negative -- see what kind of error we got
1858 else if (errno
== ECONNRESET
) { nread
= 0; *closed
= mDNStrue
; }
1859 else if (errno
!= EAGAIN
) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno
, strerror(errno
)); nread
= -1; }
1860 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
1863 if ((++EAGAINcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock
->fd
, EAGAINcount
); sleep(1); }
1870 mDNSexport
long mDNSPlatformWriteTCP(TCPSocket
*sock
, const char *msg
, unsigned long len
)
1874 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1876 #ifndef NO_SECURITYFRAMEWORK
1878 if (sock
->handshake
== handshake_required
) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
1879 if (sock
->handshake
== handshake_in_progress
) return 0;
1880 else if (sock
->handshake
!= handshake_completed
) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock
->handshake
);
1882 mStatus err
= SSLWrite(sock
->tlsContext
, msg
, len
, &processed
);
1884 if (!err
) nsent
= (int) processed
;
1885 else if (err
== errSSLWouldBlock
) nsent
= 0;
1886 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err
); nsent
= -1; }
1889 #endif /* NO_SECURITYFRAMEWORK */
1893 nsent
= send(sock
->fd
, msg
, len
, 0);
1896 if (errno
== EAGAIN
) nsent
= 0;
1897 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno
)); nsent
= -1; }
1904 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
1909 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1910 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1911 mDNSlocal mStatus
SetupSocket(KQSocketSet
*cp
, const mDNSIPPort port
, u_short sa_family
, mDNSIPPort
*const outport
)
1913 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1914 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1916 const int twofivefive
= 255;
1917 mStatus err
= mStatus_NoError
;
1918 char *errstr
= mDNSNULL
;
1922 cp
->closeFlag
= mDNSNULL
;
1924 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1925 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
));return(skt
); }
1927 // set default traffic class
1928 setTrafficClass(skt
, mDNSfalse
);
1930 #ifdef SO_RECV_ANYIF
1931 // Enable inbound packets on IFEF_AWDL interface.
1932 // Only done for multicast sockets, since we don't expect unicast socket operations
1933 // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
1934 if (mDNSSameIPPort(port
, MulticastDNSPort
))
1936 err
= setsockopt(skt
, SOL_SOCKET
, SO_RECV_ANYIF
, &on
, sizeof(on
));
1937 if (err
< 0) { errstr
= "setsockopt - SO_RECV_ANYIF"; goto fail
; }
1939 #endif // SO_RECV_ANYIF
1941 // ... with a shared UDP port, if it's for multicast receiving
1942 if (mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSSameIPPort(port
, NATPMPAnnouncementPort
))
1944 err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
1945 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
1948 // Don't want to wake from sleep for inbound packets on the mDNS sockets
1949 if (mDNSSameIPPort(port
, MulticastDNSPort
))
1952 if (setsockopt(skt
, SOL_SOCKET
, SO_NOWAKEFROMSLEEP
, &nowake
, sizeof(nowake
)) == -1)
1953 LogInfo("SetupSocket: SO_NOWAKEFROMSLEEP failed %s", strerror(errno
));
1956 if (sa_family
== AF_INET
)
1958 // We want to receive destination addresses
1959 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
1960 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
1962 // We want to receive interface identifiers
1963 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1964 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
1966 // We want to receive packet TTL value so we can check it
1967 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
1968 if (err
< 0) { errstr
= "setsockopt - IP_RECVTTL"; goto fail
; }
1970 // Send unicast packets with TTL 255
1971 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
1972 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
1974 // And multicast packets with TTL 255 too
1975 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
1976 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
1978 // And start listening for packets
1979 struct sockaddr_in listening_sockaddr
;
1980 listening_sockaddr
.sin_family
= AF_INET
;
1981 listening_sockaddr
.sin_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
1982 listening_sockaddr
.sin_addr
.s_addr
= mDNSSameIPPort(port
, NATPMPAnnouncementPort
) ? AllHosts_v4
.NotAnInteger
: 0;
1983 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
1984 if (err
) { errstr
= "bind"; goto fail
; }
1985 if (outport
) outport
->NotAnInteger
= listening_sockaddr
.sin_port
;
1987 else if (sa_family
== AF_INET6
)
1989 // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
1990 if (mDNSSameIPPort(port
, NATPMPAnnouncementPort
)) { if (outport
) *outport
= zeroIPPort
; close(skt
); return mStatus_NoError
; }
1992 // We want to receive destination addresses and receive interface identifiers
1993 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
1994 if (err
< 0) { errstr
= "setsockopt - IPV6_RECVPKTINFO"; goto fail
; }
1996 // We want to receive packet hop count value so we can check it
1997 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &on
, sizeof(on
));
1998 if (err
< 0) { errstr
= "setsockopt - IPV6_RECVHOPLIMIT"; goto fail
; }
2000 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
2001 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
2002 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
2003 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
2005 // Send unicast packets with TTL 255
2006 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
2007 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
2009 // And multicast packets with TTL 255 too
2010 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
2011 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
2013 // Want to receive our own packets
2014 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
2015 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
2017 // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
2018 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_USE_MIN_MTU
, &mtu
, sizeof(mtu
));
2019 if (err
< 0) // Since it is an optimization if we fail just log the err, no need to close the skt
2020 LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
2021 skt
, err
, errno
, strerror(errno
));
2023 // And start listening for packets
2024 struct sockaddr_in6 listening_sockaddr6
;
2025 mDNSPlatformMemZero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
2026 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
2027 listening_sockaddr6
.sin6_family
= AF_INET6
;
2028 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
2029 listening_sockaddr6
.sin6_flowinfo
= 0;
2030 listening_sockaddr6
.sin6_addr
= in6addr_any
; // Want to receive multicasts AND unicasts on this socket
2031 listening_sockaddr6
.sin6_scope_id
= 0;
2032 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
2033 if (err
) { errstr
= "bind"; goto fail
; }
2034 if (outport
) outport
->NotAnInteger
= listening_sockaddr6
.sin6_port
;
2037 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
2038 fcntl(skt
, F_SETFD
, 1); // set close-on-exec
2040 k
->KQcallback
= myKQSocketCallBack
;
2042 k
->KQtask
= "UDP packet reception";
2043 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2044 k
->readSource
= mDNSNULL
;
2045 k
->writeSource
= mDNSNULL
;
2046 k
->fdClosed
= mDNSfalse
;
2048 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
2050 return(mStatus_NoError
);
2053 saved_errno
= errno
;
2054 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
2055 if (strcmp(errstr
, "bind") || mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSIPPortIsZero(port
))
2056 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr
, skt
, mDNSVal16(port
), err
, saved_errno
, strerror(saved_errno
));
2058 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
2059 if (!strcmp(errstr
, "bind") && saved_errno
== EADDRINUSE
)
2062 if (mDNSSameIPPort(port
, MulticastDNSPort
))
2063 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
2064 "Congratulations, you've reproduced an elusive bug.\r"
2065 "Please contact the current assignee of <rdar://problem/3814904>.\r"
2066 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2067 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2070 mDNSPlatformCloseFD(k
, skt
);
2074 mDNSexport UDPSocket
*mDNSPlatformUDPSocket(const mDNSIPPort requestedport
)
2077 mDNSIPPort port
= requestedport
;
2078 mDNSBool randomizePort
= mDNSIPPortIsZero(requestedport
);
2079 int i
= 10000; // Try at most 10000 times to get a unique random port
2080 UDPSocket
*p
= mallocL("UDPSocket", sizeof(UDPSocket
));
2081 if (!p
) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL
); }
2082 mDNSPlatformMemZero(p
, sizeof(UDPSocket
));
2083 p
->ss
.port
= zeroIPPort
;
2084 p
->ss
.m
= &mDNSStorage
;
2087 p
->ss
.proxy
= mDNSfalse
;
2091 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
2092 if (randomizePort
) port
= mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
2093 err
= SetupSocket(&p
->ss
, port
, AF_INET
, &p
->ss
.port
);
2096 err
= SetupSocket(&p
->ss
, port
, AF_INET6
, &p
->ss
.port
);
2097 if (err
) { mDNSPlatformCloseFD(&p
->ss
.kqsv4
, p
->ss
.sktv4
); p
->ss
.sktv4
= -1; }
2100 } while (err
== EADDRINUSE
&& randomizePort
&& i
);
2104 // In customer builds we don't want to log failures with port 5351, because this is a known issue
2105 // of failing to bind to this port when Internet Sharing has already bound to it
2106 // We also don't want to log about port 5350, due to a known bug when some other
2107 // process is bound to it.
2108 if (mDNSSameIPPort(requestedport
, NATPMPPort
) || mDNSSameIPPort(requestedport
, NATPMPAnnouncementPort
))
2109 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
2110 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
2111 freeL("UDPSocket", p
);
2120 mDNSexport
void mDNSPlatformUDPClose(UDPSocket
*sock
)
2122 CloseSocketSet(&sock
->ss
);
2123 freeL("UDPSocket", sock
);
2127 mDNSexport mDNSBool
mDNSPlatformUDPSocketEncounteredEOF(const UDPSocket
*sock
)
2129 return (sock
->ss
.sktv4EOF
|| sock
->ss
.sktv6EOF
);
2132 #if COMPILER_LIKES_PRAGMA_MARK
2134 #pragma mark - BPF Raw packet sending/receiving
2137 #if APPLE_OSX_mDNSResponder
2139 mDNSexport
void mDNSPlatformSendRawPacket(const void *const msg
, const mDNSu8
*const end
, mDNSInterfaceID InterfaceID
)
2141 if (!InterfaceID
) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2142 NetworkInterfaceInfoOSX
*info
;
2144 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
2147 LogMsg("mDNSPlatformSendRawPacket: Invalid interface index %p", InterfaceID
);
2150 if (info
->BPF_fd
< 0)
2151 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info
->ifinfo
.ifname
, info
->BPF_fd
);
2154 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
2155 if (write(info
->BPF_fd
, msg
, end
- (mDNSu8
*)msg
) < 0)
2156 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info
->BPF_fd
, errno
, strerror(errno
));
2160 mDNSexport
void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr
*const tpa
, const mDNSEthAddr
*const tha
, mDNSInterfaceID InterfaceID
)
2162 if (!InterfaceID
) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
2163 NetworkInterfaceInfoOSX
*info
;
2164 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
2165 if (info
== NULL
) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID
); return; }
2166 // Manually inject an entry into our local ARP cache.
2167 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
2168 if (!mDNS_AddressIsLocalSubnet(&mDNSStorage
, InterfaceID
, tpa
))
2169 LogSPS("Don't need address cache entry for %s %#a %.6a", info
->ifinfo
.ifname
, tpa
, tha
);
2172 int result
= mDNSSetLocalAddressCacheEntry(info
->scope_id
, tpa
->type
, tpa
->ip
.v6
.b
, tha
->b
);
2173 if (result
) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info
->ifinfo
.ifname
, tpa
, tha
, result
);
2174 else LogSPS("Set local address cache entry for %s %#a %.6a", info
->ifinfo
.ifname
, tpa
, tha
);
2178 mDNSlocal
void CloseBPF(NetworkInterfaceInfoOSX
*const i
)
2180 LogSPS("%s closing BPF fd %d", i
->ifinfo
.ifname
, i
->BPF_fd
);
2181 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2182 // close will happen in the cancel handler
2183 dispatch_source_cancel(i
->BPF_source
);
2186 // Note: MUST NOT close() the underlying native BSD sockets.
2187 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
2188 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
2189 CFRunLoopRemoveSource(CFRunLoopGetMain(), i
->BPF_rls
, kCFRunLoopDefaultMode
);
2190 CFRelease(i
->BPF_rls
);
2191 CFSocketInvalidate(i
->BPF_cfs
);
2192 CFRelease(i
->BPF_cfs
);
2195 if (i
->BPF_mcfd
>= 0) { close(i
->BPF_mcfd
); i
->BPF_mcfd
= -1; }
2198 mDNSlocal
void bpf_callback_common(NetworkInterfaceInfoOSX
*info
)
2202 // 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
2203 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
2204 if (info
->BPF_fd
< 0) goto exit
;
2206 ssize_t n
= read(info
->BPF_fd
, &info
->m
->imsg
, info
->BPF_len
);
2207 const mDNSu8
*ptr
= (const mDNSu8
*)&info
->m
->imsg
;
2208 const mDNSu8
*end
= (const mDNSu8
*)&info
->m
->imsg
+ n
;
2209 debugf("%3d: bpf_callback got %d bytes on %s", info
->BPF_fd
, n
, info
->ifinfo
.ifname
);
2213 /* <rdar://problem/10287386>
2214 * sometimes there can be a race condition btw when the bpf socket
2215 * gets data and the callback get scheduled and when we call BIOCSETF (which
2216 * clears the socket). this can cause the read to hang for a really long time
2217 * and effectively prevent us from responding to requests for long periods of time.
2218 * to prevent this make the socket non blocking and just bail if we dont get anything
2220 if (errno
== EAGAIN
)
2222 LogMsg("bpf_callback got EAGAIN bailing");
2225 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info
->ifinfo
.ifname
, info
->BPF_fd
, errno
, strerror(errno
));
2232 const struct bpf_hdr
*const bh
= (const struct bpf_hdr
*)ptr
;
2233 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
2234 info
->BPF_fd
, ptr
, bh
->bh_hdrlen
, ptr
+ bh
->bh_hdrlen
, bh
->bh_caplen
, bh
->bh_datalen
,
2235 ptr
+ BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
), end
- (ptr
+ BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
)));
2236 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
2237 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
2238 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
2239 mDNSCoreReceiveRawPacket(info
->m
, ptr
+ bh
->bh_hdrlen
, ptr
+ bh
->bh_hdrlen
+ bh
->bh_caplen
, info
->ifinfo
.InterfaceID
);
2240 ptr
+= BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
);
2243 KQueueUnlock("bpf_callback");
2245 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2246 mDNSlocal
void bpf_callback_dispatch(NetworkInterfaceInfoOSX
*const info
)
2248 bpf_callback_common(info
);
2251 mDNSlocal
void bpf_callback(const CFSocketRef cfs
, const CFSocketCallBackType CallBackType
, const CFDataRef address
, const void *const data
, void *const context
)
2257 bpf_callback_common((NetworkInterfaceInfoOSX
*)context
);
2261 mDNSexport
void mDNSPlatformSendKeepalive(mDNSAddr
*sadd
, mDNSAddr
*dadd
, mDNSIPPort
*lport
, mDNSIPPort
*rport
, mDNSu32 seq
, mDNSu32 ack
, mDNSu16 win
)
2263 LogMsg("mDNSPlatformSendKeepalive called\n");
2264 mDNSSendKeepalive(sadd
->ip
.v6
.b
, dadd
->ip
.v6
.b
, lport
->NotAnInteger
, rport
->NotAnInteger
, seq
, ack
, win
);
2267 mDNSexport mStatus
mDNSPlatformClearSPSData(void)
2269 CFStringRef spsAddressKey
= NULL
;
2270 CFStringRef ownerOPTRecKey
= NULL
;
2271 SCDynamicStoreRef addrStore
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:SPSAddresses"), NULL
, NULL
);
2272 SCDynamicStoreRef optStore
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:SPSOPTRecord"), NULL
, NULL
);
2274 spsAddressKey
= SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, CFSTR("BonjourSleepProxyAddress"));
2275 if (spsAddressKey
!= NULL
)
2277 CFArrayRef keyList
= SCDynamicStoreCopyKeyList(addrStore
, spsAddressKey
);
2278 if (keyList
!= NULL
)
2280 if (SCDynamicStoreSetMultiple(addrStore
, NULL
, keyList
, NULL
) == false)
2281 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr( spsAddressKey
, kCFStringEncodingASCII
), SCErrorString(SCError()));
2283 if (keyList
) CFRelease(keyList
);
2285 ownerOPTRecKey
= SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, CFSTR("BonjourSleepProxyOPTRecord"));
2286 if(ownerOPTRecKey
!= NULL
)
2288 CFArrayRef keyList
= SCDynamicStoreCopyKeyList(addrStore
, ownerOPTRecKey
);
2289 if (keyList
!= NULL
)
2291 if (SCDynamicStoreSetMultiple(optStore
, NULL
, keyList
, NULL
) == false)
2292 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr(ownerOPTRecKey
, kCFStringEncodingASCII
), SCErrorString(SCError()));
2294 if (keyList
) CFRelease(keyList
);
2297 if (addrStore
) CFRelease(addrStore
);
2298 if (optStore
) CFRelease(optStore
);
2299 if (spsAddressKey
) CFRelease(spsAddressKey
);
2300 if (ownerOPTRecKey
) CFRelease(ownerOPTRecKey
);
2301 return KERN_SUCCESS
;
2304 mDNSlocal
int getMACAddress(int family
, v6addr_t raddr
, v6addr_t gaddr
, int *gfamily
, ethaddr_t eth
)
2308 struct rt_msghdr m_rtm
;
2312 struct rt_msghdr
*rtm
= &(m_rtmsg
.m_rtm
);
2313 char *cp
= m_rtmsg
.m_space
;
2314 int seq
= 6367, sock
, rlen
, i
;
2315 struct sockaddr_in
*sin
= NULL
;
2316 struct sockaddr_in6
*sin6
= NULL
;
2317 struct sockaddr_dl
*sdl
= NULL
;
2318 struct sockaddr_storage sins
;
2319 struct sockaddr_dl sdl_m
;
2321 #define NEXTADDR(w, s, len) \
2322 if (rtm->rtm_addrs & (w)) \
2324 bcopy((char *)s, cp, len); \
2328 bzero(&sins
, sizeof(struct sockaddr_storage
));
2329 bzero(&sdl_m
, sizeof(struct sockaddr_dl
));
2330 bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
2332 sock
= socket(PF_ROUTE
, SOCK_RAW
, 0);
2335 const int socket_errno
= errno
;
2336 LogMsg("getMACAddress: Can not open the socket - %s", strerror(socket_errno
));
2337 return socket_errno
;
2340 rtm
->rtm_addrs
|= RTA_DST
| RTA_GATEWAY
;
2341 rtm
->rtm_type
= RTM_GET
;
2343 rtm
->rtm_version
= RTM_VERSION
;
2344 rtm
->rtm_seq
= ++seq
;
2346 sdl_m
.sdl_len
= sizeof(sdl_m
);
2347 sdl_m
.sdl_family
= AF_LINK
;
2348 if (family
== AF_INET
)
2350 sin
= (struct sockaddr_in
*)&sins
;
2351 sin
->sin_family
= AF_INET
;
2352 sin
->sin_len
= sizeof(struct sockaddr_in
);
2353 memcpy(&sin
->sin_addr
, raddr
, sizeof(struct in_addr
));
2354 NEXTADDR(RTA_DST
, sin
, sin
->sin_len
);
2356 else if (family
== AF_INET6
)
2358 sin6
= (struct sockaddr_in6
*)&sins
;
2359 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
2360 sin6
->sin6_family
= AF_INET6
;
2361 memcpy(&sin6
->sin6_addr
, raddr
, sizeof(struct in6_addr
));
2362 NEXTADDR(RTA_DST
, sin6
, sin6
->sin6_len
);
2364 NEXTADDR(RTA_GATEWAY
, &sdl_m
, sdl_m
.sdl_len
);
2365 rtm
->rtm_msglen
= rlen
= cp
- (char *)&m_rtmsg
;
2367 if (write(sock
, (char *)&m_rtmsg
, rlen
) < 0)
2369 const int write_errno
= errno
;
2370 LogMsg("getMACAddress: writing to routing socket: %s", strerror(write_errno
));
2377 rlen
= read(sock
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
2379 while (rlen
> 0 && (rtm
->rtm_seq
!= seq
|| rtm
->rtm_pid
!= getpid()));
2382 LogMsg("getMACAddress: Read from routing socket failed");
2384 if (family
== AF_INET
)
2386 sin
= (struct sockaddr_in
*) (rtm
+ 1);
2387 sdl
= (struct sockaddr_dl
*) (sin
->sin_len
+ (char *) sin
);
2389 else if (family
== AF_INET6
)
2391 sin6
= (struct sockaddr_in6
*) (rtm
+1);
2392 sdl
= (struct sockaddr_dl
*) (sin6
->sin6_len
+ (char *) sin6
);
2397 LogMsg("getMACAddress: sdl is NULL for family %d", family
);
2402 // If the address is not on the local net, we get the IP address of the gateway.
2403 // We would have to repeat the process to get the MAC address of the gateway
2404 *gfamily
= sdl
->sdl_family
;
2405 if (sdl
->sdl_family
== AF_INET
)
2409 struct sockaddr_in
*new_sin
= (struct sockaddr_in
*)(sin
->sin_len
+(char*) sin
);
2410 memcpy(gaddr
, &new_sin
->sin_addr
, sizeof(struct in_addr
));
2414 LogMsg("getMACAddress: sin is NULL");
2419 else if (sdl
->sdl_family
== AF_INET6
)
2423 struct sockaddr_in6
*new_sin6
= (struct sockaddr_in6
*)(sin6
->sin6_len
+(char*) sin6
);
2424 memcpy(gaddr
, &new_sin6
->sin6_addr
, sizeof(struct in6_addr
));
2428 LogMsg("getMACAddress: sin6 is NULL");
2434 unsigned char *ptr
= (unsigned char *)LLADDR(sdl
);
2435 for (i
= 0; i
< ETHER_ADDR_LEN
; i
++)
2436 (eth
)[i
] = *(ptr
+i
);
2440 return KERN_SUCCESS
;
2443 mDNSlocal
int GetRemoteMacinternal(int family
, v6addr_t raddr
, ethaddr_t eth
)
2452 ret
= getMACAddress(family
, raddr
, gateway
, &gfamily
, eth
);
2455 memcpy(raddr
, gateway
, sizeof(family
));
2460 while ((ret
== -1) && (count
< 5));
2464 mDNSlocal
int StoreSPSMACAddressinternal(int family
, v6addr_t spsaddr
, const char *ifname
)
2467 char spsip
[INET6_ADDRSTRLEN
];
2469 CFStringRef sckey
= NULL
;
2470 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL
, NULL
);
2471 SCDynamicStoreRef ipstore
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL
, NULL
);
2472 CFMutableDictionaryRef dict
= NULL
;
2473 CFStringRef entityname
= NULL
;
2474 CFDictionaryRef ipdict
= NULL
;
2475 CFArrayRef addrs
= NULL
;
2477 if ((store
== NULL
) || (ipstore
== NULL
))
2479 LogMsg("StoreSPSMACAddressinternal: Unable to accesss SC Dynamic Store");
2484 // Get the MAC address of the Sleep Proxy Server
2485 memset(eth
, 0, sizeof(eth
));
2486 ret
= GetRemoteMacinternal(family
, spsaddr
, eth
);
2489 LogMsg("StoreSPSMACAddressinternal: Failed to determine the MAC address");
2493 // Create/Update the dynamic store entry for the specified interface
2494 sckey
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname
, "/BonjourSleepProxyAddress");
2495 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2498 LogMsg("StoreSPSMACAddressinternal: SPSCreateDict() Could not create CFDictionary dict");
2503 CFStringRef macaddr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
2504 CFDictionarySetValue(dict
, CFSTR("MACAddress"), macaddr
);
2505 if (NULL
!= macaddr
)
2508 if( NULL
== inet_ntop(family
, (void *)spsaddr
, spsip
, sizeof(spsip
)))
2510 LogMsg("StoreSPSMACAddressinternal: inet_ntop failed: %s", strerror(errno
));
2515 CFStringRef ipaddr
= CFStringCreateWithCString(NULL
, spsip
, kCFStringEncodingUTF8
);
2516 CFDictionarySetValue(dict
, CFSTR("IPAddress"), ipaddr
);
2520 // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup
2521 if ((entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/IPv6"), ifname
)) != NULL
)
2523 if ((ipdict
= SCDynamicStoreCopyValue(ipstore
, entityname
)) != NULL
)
2525 if((addrs
= CFDictionaryGetValue(ipdict
, CFSTR("Addresses"))) != NULL
)
2527 addrs
= CFRetain(addrs
);
2528 CFDictionarySetValue(dict
, CFSTR("RegisteredAddresses"), addrs
);
2532 SCDynamicStoreSetValue(store
, sckey
, dict
);
2535 if (store
) CFRelease(store
);
2536 if (ipstore
) CFRelease(ipstore
);
2537 if (sckey
) CFRelease(sckey
);
2538 if (dict
) CFRelease(dict
);
2539 if (ipdict
) CFRelease(ipdict
);
2540 if (entityname
) CFRelease(entityname
);
2541 if (addrs
) CFRelease(addrs
);
2546 mDNSlocal
void mDNSStoreSPSMACAddress(int family
, v6addr_t spsaddr
, char *ifname
)
2554 mDNSPlatformMemCopy(addr
.saddr
, spsaddr
, sizeof(v6addr_t
));
2556 err
= StoreSPSMACAddressinternal(family
, (uint8_t *)addr
.saddr
, ifname
);
2558 LogMsg("mDNSStoreSPSMACAddress : failed");
2561 mDNSexport mStatus
mDNSPlatformStoreSPSMACAddr(mDNSAddr
*spsaddr
, char *ifname
)
2563 int family
= (spsaddr
->type
== mDNSAddrType_IPv4
) ? AF_INET
: AF_INET6
;
2565 LogInfo("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr
, ifname
);
2566 mDNSStoreSPSMACAddress(family
, spsaddr
->ip
.v6
.b
, ifname
);
2568 return KERN_SUCCESS
;
2572 mDNSexport mStatus
mDNSPlatformStoreOwnerOptRecord(char *ifname
, DNSMessage
* msg
, int length
)
2575 CFStringRef sckey
= NULL
;
2576 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:StoreOwnerOPTRecord"), NULL
, NULL
);
2577 CFMutableDictionaryRef dict
= NULL
;
2581 LogMsg("mDNSPlatformStoreOwnerOptRecord: Unable to accesss SC Dynamic Store");
2586 // Create/Update the dynamic store entry for the specified interface
2587 sckey
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname
, "/BonjourSleepProxyOPTRecord");
2588 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2591 LogMsg("mDNSPlatformStoreOwnerOptRecord: Could not create CFDictionary dictionary to store OPT Record");
2596 CFDataRef optRec
= NULL
;
2597 optRec
= CFDataCreate(NULL
, (const uint8_t *)msg
, (CFIndex
)length
);
2598 CFDictionarySetValue(dict
, CFSTR("OwnerOPTRecord"), optRec
);
2599 if (NULL
!= optRec
) CFRelease(optRec
);
2601 SCDynamicStoreSetValue(store
, sckey
, dict
);
2604 if (NULL
!= store
) CFRelease(store
);
2605 if (NULL
!= sckey
) CFRelease(sckey
);
2606 if (NULL
!= dict
) CFRelease(dict
);
2610 mDNSlocal
void mDNSGet_RemoteMAC(int family
, v6addr_t raddr
)
2613 IPAddressMACMapping
*addrMapping
;
2614 int kr
= KERN_FAILURE
;
2620 bzero(eth
, sizeof(ethaddr_t
));
2621 mDNSPlatformMemCopy(dst
.addr
, raddr
, sizeof(v6addr_t
));
2623 kr
= GetRemoteMacinternal(family
, (uint8_t *)dst
.addr
, eth
);
2625 // If the call to get the remote MAC address succeeds, allocate and copy
2626 // the values and schedule a task to update the MAC address in the TCP Keepalive record.
2629 addrMapping
= mDNSPlatformMemAllocate(sizeof(IPAddressMACMapping
));
2630 snprintf(addrMapping
->ethaddr
, sizeof(addrMapping
->ethaddr
), "%02x:%02x:%02x:%02x:%02x:%02x",
2631 eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
2632 if (family
== AF_INET
)
2634 addrMapping
->ipaddr
.type
= mDNSAddrType_IPv4
;
2635 mDNSPlatformMemCopy(addrMapping
->ipaddr
.ip
.v4
.b
, raddr
, sizeof(v6addr_t
));
2639 addrMapping
->ipaddr
.type
= mDNSAddrType_IPv6
;
2640 mDNSPlatformMemCopy(addrMapping
->ipaddr
.ip
.v6
.b
, raddr
, sizeof(v6addr_t
));
2642 UpdateRMAC(&mDNSStorage
, addrMapping
);
2646 mDNSexport mStatus
mDNSPlatformGetRemoteMacAddr(mDNSAddr
*raddr
)
2648 int family
= (raddr
->type
== mDNSAddrType_IPv4
) ? AF_INET
: AF_INET6
;
2650 LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC");
2651 mDNSGet_RemoteMAC(family
, raddr
->ip
.v6
.b
);
2653 return KERN_SUCCESS
;
2656 mDNSexport mStatus
mDNSPlatformRetrieveTCPInfo(mDNSAddr
*laddr
, mDNSIPPort
*lport
, mDNSAddr
*raddr
, mDNSIPPort
*rport
, mDNSTCPInfo
*mti
)
2660 int family
= (laddr
->type
== mDNSAddrType_IPv4
) ? AF_INET
: AF_INET6
;
2662 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
);
2663 if (error
!= KERN_SUCCESS
)
2665 LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__
, error
);
2668 mti
->IntfId
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, intfid
);
2672 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2674 mDNSlocal
int CountProxyTargets(NetworkInterfaceInfoOSX
*x
, int *p4
, int *p6
)
2676 int numv4
= 0, numv6
= 0;
2679 for (rr
= mDNSStorage
.ResourceRecords
; rr
; rr
=rr
->next
)
2680 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2682 if (p4
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv4
, &rr
->AddressProxy
.ip
.v4
);
2686 for (rr
= mDNSStorage
.ResourceRecords
; rr
; rr
=rr
->next
)
2687 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
2689 if (p6
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv6
, &rr
->AddressProxy
.ip
.v6
);
2693 if (p4
) *p4
= numv4
;
2694 if (p6
) *p6
= numv6
;
2695 return(numv4
+ numv6
);
2698 mDNSexport
void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID
)
2700 mDNS
*const m
= &mDNSStorage
;
2701 NetworkInterfaceInfoOSX
*x
;
2703 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
2704 for (x
= m
->p
->InterfaceList
; x
; x
= x
->next
) if ((x
->ifinfo
.InterfaceID
== InterfaceID
) && (x
->BPF_fd
>= 0)) break;
2706 if (!x
) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID
); return; }
2708 #define MAX_BPF_ADDRS 250
2709 int numv4
= 0, numv6
= 0;
2711 if (CountProxyTargets(x
, &numv4
, &numv6
) > MAX_BPF_ADDRS
)
2713 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4
, numv6
);
2714 if (numv4
> MAX_BPF_ADDRS
) numv4
= MAX_BPF_ADDRS
;
2715 numv6
= MAX_BPF_ADDRS
- numv4
;
2718 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x
->BPF_fd
, x
->ifinfo
.ifname
, &x
->ifinfo
.MAC
, numv4
, numv6
);
2720 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
2721 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
2722 static struct bpf_insn filter
[17 + MAX_BPF_ADDRS
] =
2724 BPF_STMT(BPF_LD
+ BPF_H
+ BPF_ABS
, 12), // 0 Read Ethertype (bytes 12,13)
2726 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
2727 BPF_STMT(BPF_RET
+ BPF_K
, 42), // 2 Return 42-byte ARP
2729 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
2731 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
2732 BPF_STMT(BPF_LD
+ BPF_H
+ BPF_ABS
, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
2733 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
2734 BPF_STMT(BPF_RET
+ BPF_K
, 86), // 7 Return 86-byte ND
2736 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
2737 BPF_STMT(BPF_LD
+ BPF_W
+ BPF_ABS
, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
2740 // Special filter program to use when there are no address proxy records
2741 static struct bpf_insn nullfilter
[] =
2743 BPF_STMT(BPF_RET
| BPF_K
, 0) // 0 Match no packets and return size 0
2746 struct bpf_program prog
;
2747 if (!numv4
&& !numv6
)
2749 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
2750 if (m
->timenow
== 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
2752 // Cancel any previous ND group memberships we had
2753 if (x
->BPF_mcfd
>= 0)
2759 // Schedule check to see if we can close this BPF_fd now
2760 if (!m
->NetworkChanged
) m
->NetworkChanged
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2);
2761 if (x
->BPF_fd
< 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
2763 prog
.bf_insns
= nullfilter
;
2767 struct bpf_insn
*pc
= &filter
[9];
2768 struct bpf_insn
*chk6
= pc
+ numv4
+ 1; // numv4 address checks, plus a "return 0"
2769 struct bpf_insn
*fail
= chk6
+ 1 + numv6
; // Get v6 Dst LSW, plus numv6 address checks
2770 struct bpf_insn
*ret4
= fail
+ 1;
2771 struct bpf_insn
*ret6
= ret4
+ 4;
2773 static const struct bpf_insn rf
= BPF_STMT(BPF_RET
+ BPF_K
, 0); // No match: Return nothing
2775 static const struct bpf_insn g6
= BPF_STMT(BPF_LD
+ BPF_W
+ BPF_ABS
, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
2777 static const struct bpf_insn r4a
= BPF_STMT(BPF_LDX
+ BPF_B
+ BPF_MSH
, 14); // Get IP Header length (normally 20)
2778 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)
2779 static const struct bpf_insn r4c
= BPF_STMT(BPF_ALU
+ BPF_ADD
+ BPF_X
, 0); // A += IP Header length
2780 static const struct bpf_insn r4d
= BPF_STMT(BPF_RET
+ BPF_A
, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
2782 static const struct bpf_insn r6a
= BPF_STMT(BPF_RET
+ BPF_K
, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
2784 BPF_SetOffset(&filter
[4], jf
, fail
); // If Ethertype not ARP, IPv4, or IPv6, fail
2785 BPF_SetOffset(&filter
[6], jf
, chk6
); // If IPv6 but not ICMPv6, go to IPv6 address list check
2787 // BPF Byte-Order Note
2788 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
2789 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
2790 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
2791 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
2792 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
2793 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
2794 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
2795 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
2796 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
2797 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
2799 // IPSEC capture size notes:
2800 // 8 bytes UDP header
2801 // 4 bytes Non-ESP Marker
2802 // 28 bytes IKE Header
2804 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
2807 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2808 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2810 mDNSv4Addr a
= rr
->AddressProxy
.ip
.v4
;
2811 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
2812 BPF_SetOffset(pc
, jt
, ret4
);
2814 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];
2819 if (pc
!= chk6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc
, chk6
);
2820 *pc
++ = g6
; // chk6 points here
2822 // First cancel any previous ND group memberships we had, then create a fresh socket
2823 if (x
->BPF_mcfd
>= 0) close(x
->BPF_mcfd
);
2824 x
->BPF_mcfd
= socket(AF_INET6
, SOCK_DGRAM
, 0);
2826 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2827 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
2829 const mDNSv6Addr
*const a
= &rr
->AddressProxy
.ip
.v6
;
2830 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
2831 BPF_SetOffset(pc
, jt
, ret6
);
2833 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];
2836 struct ipv6_mreq i6mr
;
2837 i6mr
.ipv6mr_interface
= x
->scope_id
;
2838 i6mr
.ipv6mr_multiaddr
= *(const struct in6_addr
*)&NDP_prefix
;
2839 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xD] = a
->b
[0xD];
2840 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xE] = a
->b
[0xE];
2841 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xF] = a
->b
[0xF];
2843 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
2844 mStatus err
= setsockopt(x
->BPF_mcfd
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
2845 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
2846 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2848 err
= setsockopt(x
->BPF_mcfd
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
2849 if (err
< 0 && (errno
!= EADDRINUSE
)) // Joining same group twice can give "Address already in use" error -- no need to report that
2850 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2852 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr
.ipv6mr_multiaddr
, a
);
2855 if (pc
!= fail
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc
, fail
);
2856 *pc
++ = rf
; // fail points here
2858 if (pc
!= ret4
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc
, ret4
);
2859 *pc
++ = r4a
; // ret4 points here
2864 if (pc
!= ret6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc
, ret6
);
2865 *pc
++ = r6a
; // ret6 points here
2867 // For debugging BPF filter program
2869 for (q
=0; q
<prog
.bf_len
; q
++)
2870 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
);
2872 prog
.bf_len
= (u_int
)(pc
- filter
);
2873 prog
.bf_insns
= filter
;
2876 if (ioctl(x
->BPF_fd
, BIOCSETFNR
, &prog
) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog
.bf_len
, errno
, strerror(errno
));
2877 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog
.bf_len
);
2880 mDNSexport
void mDNSPlatformReceiveBPF_fd(int fd
)
2882 mDNS
*const m
= &mDNSStorage
;
2885 NetworkInterfaceInfoOSX
*i
;
2886 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
) if (i
->BPF_fd
== -2) break;
2887 if (!i
) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd
); close(fd
); }
2890 LogSPS("%s using BPF fd %d", i
->ifinfo
.ifname
, fd
);
2892 struct bpf_version v
;
2893 if (ioctl(fd
, BIOCVERSION
, &v
) < 0)
2894 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2895 else if (BPF_MAJOR_VERSION
!= v
.bv_major
|| BPF_MINOR_VERSION
!= v
.bv_minor
)
2896 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
2897 fd
, i
->ifinfo
.ifname
, BPF_MAJOR_VERSION
, BPF_MINOR_VERSION
, v
.bv_major
, v
.bv_minor
);
2899 if (ioctl(fd
, BIOCGBLEN
, &i
->BPF_len
) < 0)
2900 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2902 if (i
->BPF_len
> sizeof(m
->imsg
))
2904 i
->BPF_len
= sizeof(m
->imsg
);
2905 if (ioctl(fd
, BIOCSBLEN
, &i
->BPF_len
) < 0)
2906 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2908 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd
, i
->ifinfo
.ifname
, i
->BPF_len
);
2911 static const u_int opt_one
= 1;
2912 if (ioctl(fd
, BIOCIMMEDIATE
, &opt_one
) < 0)
2913 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2915 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
2916 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2918 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
2919 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2921 /* <rdar://problem/10287386>
2922 * make socket non blocking see comments in bpf_callback_common for more info
2924 if (fcntl(fd
, F_SETFL
, fcntl(fd
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
2926 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2930 mDNSPlatformMemZero(&ifr
, sizeof(ifr
));
2931 strlcpy(ifr
.ifr_name
, i
->ifinfo
.ifname
, sizeof(ifr
.ifr_name
));
2932 if (ioctl(fd
, BIOCSETIF
, &ifr
) < 0)
2933 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
)); i
->BPF_fd
= -3; }
2936 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2938 i
->BPF_source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, fd
, 0, dispatch_get_main_queue());
2939 if (!i
->BPF_source
) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
2940 dispatch_source_set_event_handler(i
->BPF_source
, ^{bpf_callback_dispatch(i
);});
2941 dispatch_source_set_cancel_handler(i
->BPF_source
, ^{close(fd
);});
2942 dispatch_resume(i
->BPF_source
);
2944 CFSocketContext myCFSocketContext
= { 0, i
, NULL
, NULL
, NULL
};
2946 i
->BPF_cfs
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
, bpf_callback
, &myCFSocketContext
);
2947 i
->BPF_rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, i
->BPF_cfs
, 0);
2948 CFRunLoopAddSource(CFRunLoopGetMain(), i
->BPF_rls
, kCFRunLoopDefaultMode
);
2950 mDNSPlatformUpdateProxyList(i
->ifinfo
.InterfaceID
);
2957 #endif // APPLE_OSX_mDNSResponder
2959 #if COMPILER_LIKES_PRAGMA_MARK
2961 #pragma mark - Key Management
2964 #ifndef NO_SECURITYFRAMEWORK
2965 mDNSlocal CFArrayRef
CopyCertChain(SecIdentityRef identity
)
2967 CFMutableArrayRef certChain
= NULL
;
2968 if (!identity
) { LogMsg("CopyCertChain: identity is NULL"); return(NULL
); }
2969 SecCertificateRef cert
;
2970 OSStatus err
= SecIdentityCopyCertificate(identity
, &cert
);
2971 if (err
|| !cert
) LogMsg("CopyCertChain: SecIdentityCopyCertificate() returned %d", (int) err
);
2974 #pragma clang diagnostic push
2975 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2976 SecPolicySearchRef searchRef
;
2977 err
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, &CSSMOID_APPLE_X509_BASIC
, NULL
, &searchRef
);
2978 if (err
|| !searchRef
) LogMsg("CopyCertChain: SecPolicySearchCreate() returned %d", (int) err
);
2981 SecPolicyRef policy
;
2982 err
= SecPolicySearchCopyNext(searchRef
, &policy
);
2983 if (err
|| !policy
) LogMsg("CopyCertChain: SecPolicySearchCopyNext() returned %d", (int) err
);
2986 CFArrayRef wrappedCert
= CFArrayCreate(NULL
, (const void**) &cert
, 1, &kCFTypeArrayCallBacks
);
2987 if (!wrappedCert
) LogMsg("CopyCertChain: wrappedCert is NULL");
2991 err
= SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
);
2992 if (err
|| !trust
) LogMsg("CopyCertChain: SecTrustCreateWithCertificates() returned %d", (int) err
);
2995 err
= SecTrustEvaluate(trust
, NULL
);
2996 if (err
) LogMsg("CopyCertChain: SecTrustEvaluate() returned %d", (int) err
);
2999 CFArrayRef rawCertChain
;
3000 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
3001 err
= SecTrustGetResult(trust
, NULL
, &rawCertChain
, &statusChain
);
3002 if (err
|| !rawCertChain
|| !statusChain
) LogMsg("CopyCertChain: SecTrustGetResult() returned %d", (int) err
);
3005 certChain
= CFArrayCreateMutableCopy(NULL
, 0, rawCertChain
);
3006 if (!certChain
) LogMsg("CopyCertChain: certChain is NULL");
3009 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
3010 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
3011 CFArraySetValueAtIndex(certChain
, 0, identity
);
3012 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
3013 if (CFArrayGetCount(certChain
) > 1) CFArrayRemoveValueAtIndex(certChain
, CFArrayGetCount(certChain
) - 1);
3015 CFRelease(rawCertChain
);
3016 // Do not free statusChain:
3017 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
3018 // certChain: Call the CFRelease function to release this object when you are finished with it.
3019 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
3024 CFRelease(wrappedCert
);
3028 CFRelease(searchRef
);
3030 #pragma clang diagnostic pop
3035 #endif /* NO_SECURITYFRAMEWORK */
3037 mDNSexport mStatus
mDNSPlatformTLSSetupCerts(void)
3039 #ifdef NO_SECURITYFRAMEWORK
3040 return mStatus_UnsupportedErr
;
3042 SecIdentityRef identity
= nil
;
3043 SecIdentitySearchRef srchRef
= nil
;
3046 #pragma clang diagnostic push
3047 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3048 // search for "any" identity matching specified key use
3049 // In this app, we expect there to be exactly one
3050 err
= SecIdentitySearchCreate(NULL
, CSSM_KEYUSE_DECRYPT
, &srchRef
);
3051 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err
); return err
; }
3053 err
= SecIdentitySearchCopyNext(srchRef
, &identity
);
3054 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err
); return err
; }
3055 #pragma clang diagnostic pop
3057 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
3058 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr
; }
3060 // Found one. Call CopyCertChain to create the correct certificate chain.
3061 ServerCerts
= CopyCertChain(identity
);
3062 if (ServerCerts
== nil
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: CopyCertChain error"); return mStatus_UnknownErr
; }
3064 return mStatus_NoError
;
3065 #endif /* NO_SECURITYFRAMEWORK */
3068 mDNSexport
void mDNSPlatformTLSTearDownCerts(void)
3070 #ifndef NO_SECURITYFRAMEWORK
3071 if (ServerCerts
) { CFRelease(ServerCerts
); ServerCerts
= NULL
; }
3072 #endif /* NO_SECURITYFRAMEWORK */
3075 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
3076 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
3078 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
3079 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
3082 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
3087 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
3088 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
3090 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
3093 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
3098 mDNSexport mDNSBool
DictionaryIsEnabled(CFDictionaryRef dict
)
3101 CFNumberRef state
= (CFNumberRef
)CFDictionaryGetValue(dict
, CFSTR("Enabled"));
3102 if (!state
) return mDNSfalse
;
3103 if (!CFNumberGetValue(state
, kCFNumberSInt32Type
, &val
))
3104 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse
; }
3105 return val
? mDNStrue
: mDNSfalse
;
3108 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
3110 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
3112 if (sa
->sa_family
== AF_INET
)
3114 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
3115 ip
->type
= mDNSAddrType_IPv4
;
3116 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
3117 return(mStatus_NoError
);
3120 if (sa
->sa_family
== AF_INET6
)
3122 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
3123 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
3124 // value into the second word of the IPv6 link-local address, so they can just
3125 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
3126 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
3127 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
3128 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
3129 ip
->type
= mDNSAddrType_IPv6
;
3130 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
3131 return(mStatus_NoError
);
3134 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
3135 return(mStatus_Invalid
);
3138 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
3140 mDNSEthAddr eth
= zeroEthAddr
;
3142 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
3145 CFDictionaryRef dict
= SCDynamicStoreCopyValue(NULL
, entityname
);
3148 CFRange range
= { 0, 6 }; // Offset, length
3149 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
3150 if (data
&& CFDataGetLength(data
) == 6)
3151 CFDataGetBytes(data
, range
, eth
.b
);
3154 CFRelease(entityname
);
3160 mDNSlocal
int GetMAC(mDNSEthAddr
*eth
, u_short ifindex
)
3162 struct ifaddrs
*ifa
;
3163 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
3164 if (ifa
->ifa_addr
&& ifa
->ifa_addr
->sa_family
== AF_LINK
)
3166 const struct sockaddr_dl
*const sdl
= (const struct sockaddr_dl
*)ifa
->ifa_addr
;
3167 if (sdl
->sdl_index
== ifindex
)
3168 { mDNSPlatformMemCopy(eth
->b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6); return 0; }
3174 #ifndef SIOCGIFWAKEFLAGS
3175 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
3178 #ifndef IF_WAKE_ON_MAGIC_PACKET
3179 #define IF_WAKE_ON_MAGIC_PACKET 0x01
3182 #ifndef ifr_wake_flags
3183 #define ifr_wake_flags ifr_ifru.ifru_intval
3186 mDNSlocal mDNSBool
CheckInterfaceSupport(NetworkInterfaceInfo
*const intf
, const char *key
)
3188 io_service_t service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOBSDNameMatching(kIOMasterPortDefault
, 0, intf
->ifname
));
3191 LogSPS("CheckInterfaceSupport: No service for interface %s", intf
->ifname
);
3196 IOObjectGetClass(service
, n1
);
3197 io_object_t parent
= IO_OBJECT_NULL
;
3198 mDNSBool ret
= mDNSfalse
;
3200 kern_return_t kr
= IORegistryEntryGetParentEntry(service
, kIOServicePlane
, &parent
);
3201 if (kr
== KERN_SUCCESS
)
3203 CFStringRef keystr
= CFStringCreateWithCString(NULL
, key
, kCFStringEncodingUTF8
);
3204 IOObjectGetClass(parent
, n2
);
3205 LogSPS("CheckInterfaceSupport: Interface %s service %s parent %s", intf
->ifname
, n1
, n2
);
3206 CFTypeRef ref
= mDNSNULL
;
3208 // Currently, the key can be in a different part of the IOKit hierarchy on the AppleTV.
3209 // TODO: revist if it is ok to have the same call for all platforms.
3211 ref
= IORegistryEntrySearchCFProperty(parent
, kIOServicePlane
, keystr
, kCFAllocatorDefault
, kIORegistryIterateParents
| kIORegistryIterateRecursively
);
3213 ref
= IORegistryEntryCreateCFProperty(parent
, keystr
, kCFAllocatorDefault
, mDNSNULL
);
3217 LogSPS("CheckInterfaceSupport: No %s for interface %s/%s/%s", key
, intf
->ifname
, n1
, n2
);
3225 IOObjectRelease(parent
);
3230 LogSPS("CheckInterfaceSupport: IORegistryEntryGetParentEntry for %s/%s failed %d", intf
->ifname
, n1
, kr
);
3234 IOObjectRelease(service
);
3239 mDNSlocal mDNSBool
InterfaceSupportsKeepAlive(NetworkInterfaceInfo
*const intf
)
3241 return CheckInterfaceSupport(intf
, mDNS_IOREG_KA_KEY
);
3244 mDNSlocal mDNSBool
NetWakeInterface(NetworkInterfaceInfoOSX
*i
)
3246 // We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D.
3247 if (!MulticastInterface(i
) || (i
->ifa_flags
& IFF_LOOPBACK
) || i
->D2DInterface
)
3249 LogSPS("NetWakeInterface: returning false for %s", i
->ifinfo
.ifname
);
3253 // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
3254 // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
3255 // when the power source is not AC Power.
3256 if (InterfaceSupportsKeepAlive(&i
->ifinfo
))
3258 LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i
->ifinfo
.ifname
);
3262 int s
= socket(AF_INET
, SOCK_DGRAM
, 0);
3263 if (s
< 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i
->ifinfo
.ifname
, s
, errno
, strerror(errno
)); return(mDNSfalse
); }
3266 strlcpy(ifr
.ifr_name
, i
->ifinfo
.ifname
, sizeof(ifr
.ifr_name
));
3267 if (ioctl(s
, SIOCGIFWAKEFLAGS
, &ifr
) < 0)
3269 const int ioctl_errno
= errno
;
3270 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
3271 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
3272 // error code is being returned from the kernel, we need to use the kernel version.
3273 #define KERNEL_EOPNOTSUPP 102
3274 if (ioctl_errno
!= KERNEL_EOPNOTSUPP
) // "Operation not supported on socket", the expected result on Leopard and earlier
3275 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i
->ifinfo
.ifname
, ioctl_errno
, strerror(ioctl_errno
));
3276 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
3277 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
3278 ifr
.ifr_wake_flags
= (ioctl_errno
== KERNEL_EOPNOTSUPP
&& !(i
)->BSSID
.l
[0] && i
->m
->SystemWakeOnLANEnabled
) ? IF_WAKE_ON_MAGIC_PACKET
: 0;
3283 // 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
3285 LogSPS("NetWakeInterface: %-6s %#-14a %s WOMP", i
->ifinfo
.ifname
, &i
->ifinfo
.ip
, (ifr
.ifr_wake_flags
& IF_WAKE_ON_MAGIC_PACKET
) ? "supports" : "no");
3287 return((ifr
.ifr_wake_flags
& IF_WAKE_ON_MAGIC_PACKET
) != 0);
3290 mDNSlocal u_int64_t
getExtendedFlags(char * ifa_name
)
3295 sockFD
= socket(AF_INET
, SOCK_DGRAM
, 0);
3298 LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno
, strerror(errno
));
3302 ifr
.ifr_addr
.sa_family
= AF_INET
;
3303 strlcpy(ifr
.ifr_name
, ifa_name
, sizeof(ifr
.ifr_name
));
3305 if (ioctl(sockFD
, SIOCGIFEFLAGS
, (caddr_t
)&ifr
) == -1)
3307 LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno
, strerror(errno
));
3312 return ifr
.ifr_eflags
;
3316 // IFRTYPE_FUNCTIONAL_INTCOPROC type interfaces on macOS do not support Bonjour discovery.
3317 mDNSlocal mDNSBool
isCoprocessorInterface(int sockFD
, char * ifa_name
)
3323 LogMsg("isCoprocessorInterface: invalid socket FD passed: %d", sockFD
);
3327 memset(&ifr
, 0, sizeof(struct ifreq
));
3328 strlcpy(ifr
.ifr_name
, ifa_name
, sizeof(ifr
.ifr_name
));
3330 if (ioctl(sockFD
, SIOCGIFFUNCTIONALTYPE
, (caddr_t
)&ifr
) == -1)
3332 LogMsg("isCoprocessorInterface: SIOCGIFFUNCTIONALTYPE failed, errno = %d (%s)", errno
, strerror(errno
));
3336 if (ifr
.ifr_functional_type
== IFRTYPE_FUNCTIONAL_INTCOPROC
)
3338 LogMsg("isCoprocessorInterface: %s marked as coprocessor interface", ifa_name
);
3345 #else // TARGET_OS_OSX
3346 #define isCoprocessorInterface(A, B) mDNSfalse
3347 #endif // TARGET_OS_OSX
3349 #if TARGET_OS_IPHONE
3351 // Function pointers for the routines we use in the MobileWiFi framework.
3352 static WiFiManagerClientRef (*WiFiManagerClientCreate_p
)(CFAllocatorRef allocator
, WiFiClientType type
) = mDNSNULL
;
3353 static CFArrayRef (*WiFiManagerClientCopyDevices_p
)(WiFiManagerClientRef manager
) = mDNSNULL
;
3354 static WiFiNetworkRef (*WiFiDeviceClientCopyCurrentNetwork_p
)(WiFiDeviceClientRef device
) = mDNSNULL
;
3355 static bool (*WiFiNetworkIsCarPlay_p
)(WiFiNetworkRef network
) = mDNSNULL
;
3357 mDNSlocal mDNSBool
MobileWiFiLibLoad(void)
3359 static mDNSBool isInitialized
= mDNSfalse
;
3360 static void *MobileWiFiLib_p
= mDNSNULL
;
3361 static const char path
[] = "/System/Library/PrivateFrameworks/MobileWiFi.framework/MobileWiFi";
3365 if (!MobileWiFiLib_p
)
3367 MobileWiFiLib_p
= dlopen(path
, RTLD_LAZY
| RTLD_LOCAL
);
3368 if (!MobileWiFiLib_p
)
3370 LogInfo("MobileWiFiLibLoad: dlopen() failed.");
3375 if (!WiFiManagerClientCreate_p
)
3377 WiFiManagerClientCreate_p
= dlsym(MobileWiFiLib_p
, "WiFiManagerClientCreate");
3378 if (!WiFiManagerClientCreate_p
)
3380 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCreate symbol failed.");
3385 if (!WiFiManagerClientCopyDevices_p
)
3387 WiFiManagerClientCopyDevices_p
= dlsym(MobileWiFiLib_p
, "WiFiManagerClientCopyDevices");
3388 if (!WiFiManagerClientCopyDevices_p
)
3390 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCopyDevices symbol failed.");
3395 if (!WiFiDeviceClientCopyCurrentNetwork_p
)
3397 WiFiDeviceClientCopyCurrentNetwork_p
= dlsym(MobileWiFiLib_p
, "WiFiDeviceClientCopyCurrentNetwork");
3398 if (!WiFiDeviceClientCopyCurrentNetwork_p
)
3400 LogInfo("MobileWiFiLibLoad: load of WiFiDeviceClientCopyCurrentNetwork symbol failed.");
3405 if (!WiFiNetworkIsCarPlay_p
)
3407 WiFiNetworkIsCarPlay_p
= dlsym(MobileWiFiLib_p
, "WiFiNetworkIsCarPlay");
3408 if (!WiFiNetworkIsCarPlay_p
)
3410 LogInfo("MobileWiFiLibLoad: load of WiFiNetworkIsCarPlay symbol failed.");
3415 isInitialized
= mDNStrue
;
3419 return isInitialized
;
3422 #define CARPLAY_DEBUG 0
3424 // Return true if the interface is associate to a CarPlay hosted SSID.
3425 // If we have associated with a CarPlay hosted SSID, then use the same
3426 // optimizations that are used when an interface has the IFEF_DIRECTLINK flag set.
3427 mDNSlocal mDNSBool
IsCarPlaySSID(char *ifa_name
)
3429 static WiFiManagerClientRef manager
= NULL
;
3431 WiFiDeviceClientRef device
;
3432 WiFiNetworkRef network
;
3433 mDNSBool rvalue
= mDNSfalse
;
3435 if (!MobileWiFiLibLoad())
3437 LogInfo("IsCarPlaySSID: MobileWiFiLibLoad() failed!");
3441 // Cache the WiFiManagerClientRef.
3442 if (manager
== NULL
)
3443 manager
= WiFiManagerClientCreate_p(NULL
, kWiFiClientTypeNormal
);
3445 if (manager
== NULL
)
3447 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3451 devices
= WiFiManagerClientCopyDevices_p(manager
);
3453 // If the first call fails, update the cached WiFiManagerClientRef pointer and try again.
3454 if (devices
== NULL
)
3456 LogInfo("IsCarPlaySSID: First call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name
);
3458 // Release the previously cached WiFiManagerClientRef which is apparently now stale.
3460 manager
= WiFiManagerClientCreate_p(NULL
, kWiFiClientTypeNormal
);
3461 if (manager
== NULL
)
3463 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3466 devices
= WiFiManagerClientCopyDevices_p(manager
);
3467 if (devices
== NULL
)
3469 LogInfo("IsCarPlaySSID: Second call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name
);
3474 device
= (WiFiDeviceClientRef
)CFArrayGetValueAtIndex(devices
, 0);
3475 network
= WiFiDeviceClientCopyCurrentNetwork_p(device
);
3476 if (network
!= NULL
)
3478 if (WiFiNetworkIsCarPlay_p(network
))
3480 LogInfo("IsCarPlaySSID: %s is CarPlay hosted", ifa_name
);
3485 LogInfo("IsCarPlaySSID: %s is NOT CarPlay hosted", ifa_name
);
3486 #endif // CARPLAY_DEBUG
3491 LogInfo("IsCarPlaySSID: WiFiDeviceClientCopyCurrentNetwork() returned NULL for %s", ifa_name
);
3498 #else // TARGET_OS_IPHONE
3500 mDNSlocal mDNSBool
IsCarPlaySSID(char *ifa_name
)
3502 (void)ifa_name
; // unused
3504 // OSX WifiManager currently does not implement WiFiNetworkIsCarPlay()
3508 #endif // TARGET_OS_IPHONE
3510 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
3511 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
3512 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
3513 // (e.g. sa_family not AF_INET or AF_INET6)
3514 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(struct ifaddrs
*ifa
, mDNSs32 utc
)
3516 mDNS
*const m
= &mDNSStorage
;
3517 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
3518 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
3519 u_int64_t eflags
= getExtendedFlags(ifa
->ifa_name
);
3522 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
3523 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
3525 NetworkInterfaceInfoOSX
**p
;
3526 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
3527 if (scope_id
== (*p
)->scope_id
&&
3528 mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) &&
3529 mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
3531 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
);
3532 // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
3533 // When interfaces are created with same MAC address, kernel resurrects the old interface.
3534 // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
3535 // we get the corresponding name for the interface index on which the packet was received and check against
3536 // the InterfaceList for a matching name. So, keep the name in sync
3537 strlcpy((*p
)->ifinfo
.ifname
, ifa
->ifa_name
, sizeof((*p
)->ifinfo
.ifname
));
3539 // Determine if multicast state has changed.
3540 const mDNSBool txrx
= MulticastInterface(*p
);
3541 if ((*p
)->ifinfo
.McastTxRx
!= txrx
)
3543 (*p
)->ifinfo
.McastTxRx
= txrx
;
3544 (*p
)->Exists
= MulticastStateChanged
; // State change; need to deregister and reregister this interface
3547 (*p
)->Exists
= mDNStrue
;
3549 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
3550 if ((*p
)->LastSeen
!= utc
) (*p
)->AppearanceTime
= utc
;
3552 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
3553 // we may need to start or stop or sleep proxy browse operation
3554 const mDNSBool NetWake
= NetWakeInterface(*p
);
3555 if ((*p
)->ifinfo
.NetWake
!= NetWake
)
3557 (*p
)->ifinfo
.NetWake
= NetWake
;
3558 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
3559 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
3560 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
3561 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
3562 if ((*p
)->Registered
)
3565 if (NetWake
) mDNS_ActivateNetWake_internal (m
, &(*p
)->ifinfo
);
3566 else mDNS_DeactivateNetWake_internal(m
, &(*p
)->ifinfo
);
3570 // Reset the flag if it has changed this time.
3571 (*p
)->ifinfo
.IgnoreIPv4LL
= ((eflags
& IFEF_ARPLL
) != 0) ? mDNSfalse
: mDNStrue
;
3576 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
3577 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
3578 if (!i
) return(mDNSNULL
);
3579 mDNSPlatformMemZero(i
, sizeof(NetworkInterfaceInfoOSX
));
3580 i
->ifinfo
.InterfaceID
= (mDNSInterfaceID
)(uintptr_t)scope_id
;
3582 i
->ifinfo
.mask
= mask
;
3583 strlcpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
3584 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
3585 // We can be configured to disable multicast advertisement, but we want to to support
3586 // local-only services, which need a loopback address record.
3587 i
->ifinfo
.Advertise
= m
->DivertMulticastAdvertisements
? ((ifa
->ifa_flags
& IFF_LOOPBACK
) ? mDNStrue
: mDNSfalse
) : m
->AdvertiseLocalAddresses
;
3588 i
->ifinfo
.Loopback
= ((ifa
->ifa_flags
& IFF_LOOPBACK
) != 0) ? mDNStrue
: mDNSfalse
;
3589 i
->ifinfo
.IgnoreIPv4LL
= ((eflags
& IFEF_ARPLL
) != 0) ? mDNSfalse
: mDNStrue
;
3591 // Setting DirectLink indicates we can do the optimization of skipping the probe phase
3592 // for the interface address records since they should be unique.
3593 // Unfortunately, the legacy p2p* interfaces do not set the IFEF_LOCALNET_PRIVATE
3594 // or IFEF_DIRECTLINK flags, so we have to match against the name.
3595 if ((eflags
& (IFEF_DIRECTLINK
| IFEF_AWDL
)) || (strncmp(i
->ifinfo
.ifname
, "p2p", 3) == 0))
3596 i
->ifinfo
.DirectLink
= mDNStrue
;
3598 i
->ifinfo
.DirectLink
= IsCarPlaySSID(ifa
->ifa_name
);
3600 if (i
->ifinfo
.DirectLink
)
3601 LogInfo("AddInterfaceToList: DirectLink set for %s", ifa
->ifa_name
);
3605 i
->Exists
= mDNStrue
;
3606 i
->Flashing
= mDNSfalse
;
3607 i
->Occulting
= mDNSfalse
;
3609 i
->D2DInterface
= ((eflags
& IFEF_LOCALNET_PRIVATE
) || (strncmp(i
->ifinfo
.ifname
, "p2p", 3) == 0)) ? mDNStrue
: mDNSfalse
;
3610 if (i
->D2DInterface
)
3611 LogInfo("AddInterfaceToList: D2DInterface set for %s", ifa
->ifa_name
);
3613 i
->isExpensive
= (eflags
& IFEF_EXPENSIVE
) ? mDNStrue
: mDNSfalse
;
3614 i
->isAWDL
= (eflags
& IFEF_AWDL
) ? mDNStrue
: mDNSfalse
;
3615 i
->isCLAT46
= (eflags
& IFEF_CLAT46
) ? mDNStrue
: mDNSfalse
;
3616 if (eflags
& IFEF_AWDL
)
3618 // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
3619 // limited AWDL resources so we don't set the kDNSQClass_UnicastResponse bit in
3620 // Bonjour requests over the AWDL interface.
3621 i
->ifinfo
.SupportsUnicastMDNSResponse
= mDNSfalse
;
3622 AWDLInterfaceID
= i
->ifinfo
.InterfaceID
;
3623 LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID
);
3627 i
->ifinfo
.SupportsUnicastMDNSResponse
= mDNStrue
;
3629 i
->AppearanceTime
= utc
; // Brand new interface; AppearanceTime is now
3631 i
->ifa_flags
= ifa
->ifa_flags
;
3632 i
->scope_id
= scope_id
;
3634 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
3638 i
->Registered
= mDNSNULL
;
3640 // MulticastInterface() depends on the "m" and "ifa_flags" values being initialized above.
3641 i
->ifinfo
.McastTxRx
= MulticastInterface(i
);
3642 // Do this AFTER i->BSSID has been set up
3643 i
->ifinfo
.NetWake
= (eflags
& IFEF_EXPENSIVE
)? mDNSfalse
: NetWakeInterface(i
);
3644 GetMAC(&i
->ifinfo
.MAC
, scope_id
);
3645 if (i
->ifinfo
.NetWake
&& !i
->ifinfo
.MAC
.l
[0])
3646 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i
->ifinfo
.MAC
, scope_id
, i
->ifinfo
.ifname
, &ip
);
3652 #if APPLE_OSX_mDNSResponder
3654 #if COMPILER_LIKES_PRAGMA_MARK
3656 #pragma mark - AutoTunnel
3659 #define kRacoonPort 4500
3661 static DomainAuthInfo
* AnonymousRacoonConfig
= mDNSNULL
;
3663 #ifndef NO_SECURITYFRAMEWORK
3665 static CFMutableDictionaryRef domainStatusDict
= NULL
;
3667 mDNSlocal mStatus
CheckQuestionForStatus(const DNSQuestion
*const q
)
3671 if (q
->servAddr
.type
== mDNSAddrType_IPv4
&& mDNSIPv4AddressIsOnes(q
->servAddr
.ip
.v4
))
3672 return mStatus_NoSuchRecord
;
3673 else if (q
->state
== LLQ_Poll
)
3674 return mStatus_PollingMode
;
3675 else if (q
->state
!= LLQ_Established
&& !q
->DuplicateOf
)
3676 return mStatus_TransientErr
;
3679 return mStatus_NoError
;
3682 mDNSlocal mStatus
UpdateLLQStatus(char *buffer
, int bufsz
, const DomainAuthInfo
*const info
)
3684 mStatus status
= mStatus_NoError
;
3685 DNSQuestion
* q
, *worst_q
= mDNSNULL
;
3686 for (q
= mDNSStorage
.Questions
; q
; q
=q
->next
)
3687 if (q
->AuthInfo
== info
)
3689 mStatus newStatus
= CheckQuestionForStatus(q
);
3690 if (newStatus
== mStatus_NoSuchRecord
) { status
= newStatus
; worst_q
= q
; break; }
3691 else if (newStatus
== mStatus_PollingMode
) { status
= newStatus
; worst_q
= q
; }
3692 else if (newStatus
== mStatus_TransientErr
&& status
== mStatus_NoError
) { status
= newStatus
; worst_q
= q
; }
3695 if (status
== mStatus_NoError
) mDNS_snprintf(buffer
, bufsz
, "Success");
3696 else if (status
== mStatus_NoSuchRecord
) mDNS_snprintf(buffer
, bufsz
, "GetZoneData %s: %##s", worst_q
->nta
? "not yet complete" : "failed", worst_q
->qname
.c
);
3697 else if (status
== mStatus_PollingMode
) mDNS_snprintf(buffer
, bufsz
, "Query polling %##s", worst_q
->qname
.c
);
3698 else if (status
== mStatus_TransientErr
) mDNS_snprintf(buffer
, bufsz
, "Query not yet established %##s", worst_q
->qname
.c
);
3702 mDNSlocal mStatus
UpdateRRStatus(char *buffer
, int bufsz
, const DomainAuthInfo
*const info
)
3706 if (info
->deltime
) return mStatus_NoError
;
3707 for (r
= mDNSStorage
.ResourceRecords
; r
; r
= r
->next
)
3709 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
3710 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
3711 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
3712 // has already checked
3713 const domainname
*n
= r
->resrec
.name
;
3716 DomainAuthInfo
*ptr
;
3717 for (ptr
= mDNSStorage
.AuthInfoList
; ptr
; ptr
= ptr
->next
)
3718 if (SameDomainName(&ptr
->domain
, n
))
3720 if (ptr
== info
&& (r
->updateError
== mStatus_BadSig
|| r
->updateError
== mStatus_BadKey
|| r
->updateError
== mStatus_BadTime
))
3722 mDNS_snprintf(buffer
, bufsz
, "Resource record update failed for %##s", r
->resrec
.name
);
3723 return r
->updateError
;
3726 n
= (const domainname
*)(n
->c
+ 1 + n
->c
[0]);
3729 return mStatus_NoError
;
3732 #endif // ndef NO_SECURITYFRAMEWORK
3734 // MUST be called with lock held
3735 mDNSlocal
void UpdateAutoTunnelDomainStatus(const DomainAuthInfo
*const info
)
3737 #ifdef NO_SECURITYFRAMEWORK
3740 // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
3741 // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
3742 mDNS
*const m
= &mDNSStorage
;
3743 const NATTraversalInfo
*const llq
= m
->LLQNAT
.clientCallback
? &m
->LLQNAT
: mDNSNULL
;
3744 const NATTraversalInfo
*const tun
= m
->AutoTunnelNAT
.clientContext
? &m
->AutoTunnelNAT
: mDNSNULL
;
3746 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3747 CFStringRef domain
= NULL
;
3748 CFStringRef tmp
= NULL
;
3749 CFNumberRef num
= NULL
;
3750 mStatus status
= mStatus_NoError
;
3751 mStatus llqStatus
= mStatus_NoError
;
3752 char llqBuffer
[1024];
3756 if (!domainStatusDict
)
3758 domainStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3759 if (!domainStatusDict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
3762 if (!dict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
3764 mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", info
->domain
.c
);
3765 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3766 if (!domain
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3770 if (CFDictionaryContainsKey(domainStatusDict
, domain
))
3772 CFDictionaryRemoveValue(domainStatusDict
, domain
);
3773 if (!m
->ShutdownTime
) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, mDNSNULL
, domainStatusDict
);
3781 mDNS_snprintf(buffer
, sizeof(buffer
), "%#a", &m
->Router
);
3782 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3784 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
3787 CFDictionarySetValue(dict
, CFSTR("RouterAddress"), tmp
);
3793 mDNSu32 port
= mDNSVal16(llq
->ExternalPort
);
3795 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
3797 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
3800 CFDictionarySetValue(dict
, CFSTR("LLQExternalPort"), num
);
3806 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &llq
->Result
);
3808 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
3811 CFDictionarySetValue(dict
, CFSTR("LLQNPMStatus"), num
);
3819 mDNSu32 port
= mDNSVal16(tun
->ExternalPort
);
3821 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
3823 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
3826 CFDictionarySetValue(dict
, CFSTR("AutoTunnelExternalPort"), num
);
3830 mDNS_snprintf(buffer
, sizeof(buffer
), "%.4a", &tun
->ExternalAddress
);
3831 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3833 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
3836 CFDictionarySetValue(dict
, CFSTR("ExternalAddress"), tmp
);
3842 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tun
->Result
);
3844 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
3847 CFDictionarySetValue(dict
, CFSTR("AutoTunnelNPMStatus"), num
);
3854 mDNSu32 code
= m
->LastNATMapResultCode
;
3856 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &code
);
3858 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
3861 CFDictionarySetValue(dict
, CFSTR("LastNATMapResultCode"), num
);
3866 mDNS_snprintf(buffer
, sizeof(buffer
), "Success");
3867 llqStatus
= UpdateLLQStatus(llqBuffer
, sizeof(llqBuffer
), info
);
3868 status
= UpdateRRStatus(buffer
, sizeof(buffer
), info
);
3870 // If we have a bad signature error updating a RR, it overrides any error as it needs to be
3871 // reported so that it can be fixed automatically (or the user needs to be notified)
3872 if (status
!= mStatus_NoError
)
3874 LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status
, buffer
);
3876 else if (m
->Router
.type
== mDNSAddrType_None
)
3878 status
= mStatus_NoRouter
;
3879 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - none");
3881 else if (m
->Router
.type
== mDNSAddrType_IPv4
&& mDNSIPv4AddressIsZero(m
->Router
.ip
.v4
))
3883 status
= mStatus_NoRouter
;
3884 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - v4 zero");
3886 else if (mDNSIPv6AddressIsZero(info
->AutoTunnelInnerAddress
))
3888 status
= mStatus_ServiceNotRunning
;
3889 mDNS_snprintf(buffer
, sizeof(buffer
), "No inner address");
3891 else if (!llq
&& !tun
)
3893 status
= mStatus_NotInitializedErr
;
3894 mDNS_snprintf(buffer
, sizeof(buffer
), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
3896 else if (llqStatus
== mStatus_NoSuchRecord
)
3899 mDNS_snprintf(buffer
, sizeof(buffer
), "%s", llqBuffer
);
3901 else if ((llq
&& llq
->Result
== mStatus_DoubleNAT
) || (tun
&& tun
->Result
== mStatus_DoubleNAT
))
3903 status
= mStatus_DoubleNAT
;
3904 mDNS_snprintf(buffer
, sizeof(buffer
), "Double NAT: Router is reporting a private address");
3906 else if ((llq
&& llq
->Result
== mStatus_NATPortMappingDisabled
) ||
3907 (tun
&& tun
->Result
== mStatus_NATPortMappingDisabled
) ||
3908 (m
->LastNATMapResultCode
== NATErr_Refused
&& ((llq
&& !llq
->Result
&& mDNSIPPortIsZero(llq
->ExternalPort
)) || (tun
&& !tun
->Result
&& mDNSIPPortIsZero(tun
->ExternalPort
)))))
3910 status
= mStatus_NATPortMappingDisabled
;
3911 mDNS_snprintf(buffer
, sizeof(buffer
), "PCP/NAT-PMP is disabled on the router");
3913 else if ((llq
&& llq
->Result
) || (tun
&& tun
->Result
))
3915 status
= mStatus_NATTraversal
;
3916 mDNS_snprintf(buffer
, sizeof(buffer
), "Error obtaining NAT port mapping from router");
3918 else if ((llq
&& mDNSIPPortIsZero(llq
->ExternalPort
)) || (tun
&& mDNSIPPortIsZero(tun
->ExternalPort
)))
3920 status
= mStatus_NATTraversal
;
3921 mDNS_snprintf(buffer
, sizeof(buffer
), "Unable to obtain NAT port mapping from router");
3926 mDNS_snprintf(buffer
, sizeof(buffer
), "%s", llqBuffer
);
3927 LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status
, buffer
);
3930 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
);
3932 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
3935 CFDictionarySetValue(dict
, CFSTR("StatusCode"), num
);
3939 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3941 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
3944 CFDictionarySetValue(dict
, CFSTR("StatusMessage"), tmp
);
3948 if (!CFDictionaryContainsKey(domainStatusDict
, domain
) ||
3949 !CFEqual(dict
, (CFMutableDictionaryRef
)CFDictionaryGetValue(domainStatusDict
, domain
)))
3951 CFDictionarySetValue(domainStatusDict
, domain
, dict
);
3952 if (!m
->ShutdownTime
)
3954 LogInfo("UpdateAutoTunnelDomainStatus: %s status %d", status
? "failure" : "success", status
);
3955 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, mDNSNULL
, domainStatusDict
);
3962 debugf("UpdateAutoTunnelDomainStatus: %s", buffer
);
3963 #endif // def NO_SECURITYFRAMEWORK
3966 // MUST be called with lock held
3967 mDNSexport
void UpdateAutoTunnelDomainStatuses(const mDNS
*const m
)
3969 #ifdef NO_SECURITYFRAMEWORK
3973 DomainAuthInfo
* info
;
3974 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
3975 if (info
->AutoTunnel
&& !info
->deltime
)
3976 UpdateAutoTunnelDomainStatus(info
);
3977 #endif // def NO_SECURITYFRAMEWORK
3980 mDNSlocal
void UpdateAnonymousRacoonConfig(mDNS
*m
) // Determine whether we need racoon to accept incoming connections
3982 DomainAuthInfo
*info
;
3984 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
3985 if (info
->AutoTunnel
&& !info
->deltime
&& (!mDNSIPPortIsZero(m
->AutoTunnelNAT
.ExternalPort
) || !mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
)))
3988 if (info
!= AnonymousRacoonConfig
)
3990 AnonymousRacoonConfig
= info
;
3991 LogInfo("UpdateAnonymousRacoonConfig need not be done in mDNSResponder");
3995 mDNSlocal
void AutoTunnelRecordCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
3997 // Caller must hold the lock
3998 mDNSlocal mDNSBool
DeregisterAutoTunnelRecord(mDNS
*m
, DomainAuthInfo
*info
, AuthRecord
* record
)
4002 LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info
->domain
.c
, record
->namestorage
.c
);
4004 if (record
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
4006 mStatus err
= mDNS_Deregister_internal(m
, record
, mDNS_Dereg_normal
);
4009 record
->resrec
.RecordType
= kDNSRecordTypeUnregistered
;
4010 LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err
, info
->domain
.c
, record
->namestorage
.c
);
4013 else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
4015 else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record
->resrec
.RecordType
);
4020 // Caller must hold the lock
4021 mDNSlocal
void DeregisterAutoTunnelHostRecord(mDNS
*m
, DomainAuthInfo
*info
)
4023 if (!DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnelHostRecord
))
4025 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
4026 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4030 // Caller must hold the lock
4031 mDNSlocal
void UpdateAutoTunnelHostRecord(mDNS
*m
, DomainAuthInfo
*info
)
4034 mDNSBool NATProblem
= mDNSIPPortIsZero(m
->AutoTunnelNAT
.ExternalPort
) || m
->AutoTunnelNAT
.Result
;
4038 if (!info
->AutoTunnelServiceStarted
|| info
->deltime
|| m
->ShutdownTime
|| mDNSIPv6AddressIsZero(info
->AutoTunnelInnerAddress
) || (m
->SleepState
!= SleepState_Awake
&& NATProblem
))
4040 LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
4041 info
->domain
.c
, info
->AutoTunnelServiceStarted
, info
->deltime
, &info
->AutoTunnelInnerAddress
, m
->SleepState
);
4042 DeregisterAutoTunnelHostRecord(m
, info
);
4044 else if (info
->AutoTunnelHostRecord
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4046 mDNS_SetupResourceRecord(&info
->AutoTunnelHostRecord
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
,
4047 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
4048 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
4049 AppendDomainLabel(&info
->AutoTunnelHostRecord
.namestorage
, &m
->hostlabel
);
4050 AppendDomainName (&info
->AutoTunnelHostRecord
.namestorage
, &info
->domain
);
4051 info
->AutoTunnelHostRecord
.resrec
.rdata
->u
.ipv6
= info
->AutoTunnelInnerAddress
;
4052 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4054 err
= mDNS_Register_internal(m
, &info
->AutoTunnelHostRecord
);
4055 if (err
) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
4058 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
4059 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4060 LogInfo("UpdateAutoTunnelHostRecord registering %##s", info
->AutoTunnelHostRecord
.namestorage
.c
);
4063 else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info
->AutoTunnelHostRecord
.resrec
.RecordType
);
4066 // Caller must hold the lock
4067 mDNSlocal
void DeregisterAutoTunnelServiceRecords(mDNS
*m
, DomainAuthInfo
*info
)
4069 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info
->domain
.c
);
4071 DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnelTarget
);
4072 DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnelService
);
4073 UpdateAutoTunnelHostRecord(m
, info
);
4076 // Caller must hold the lock
4077 mDNSlocal
void UpdateAutoTunnelServiceRecords(mDNS
*m
, DomainAuthInfo
*info
)
4081 if (!info
->AutoTunnelServiceStarted
|| info
->deltime
|| m
->ShutdownTime
|| mDNSIPPortIsZero(m
->AutoTunnelNAT
.ExternalPort
) || m
->AutoTunnelNAT
.Result
)
4083 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
);
4084 DeregisterAutoTunnelServiceRecords(m
, info
);
4088 if (info
->AutoTunnelTarget
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4090 // 1. Set up our address record for the external tunnel address
4091 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
4092 mDNS_SetupResourceRecord(&info
->AutoTunnelTarget
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, kHostNameTTL
,
4093 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
4094 AssignDomainName (&info
->AutoTunnelTarget
.namestorage
, (const domainname
*) "\x0B" "_autotunnel");
4095 AppendDomainLabel(&info
->AutoTunnelTarget
.namestorage
, &m
->hostlabel
);
4096 AppendDomainName (&info
->AutoTunnelTarget
.namestorage
, &info
->domain
);
4097 info
->AutoTunnelTarget
.resrec
.rdata
->u
.ipv4
= m
->AutoTunnelNAT
.ExternalAddress
;
4098 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4100 mStatus err
= mDNS_Register_internal(m
, &info
->AutoTunnelTarget
);
4101 if (err
) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err
, info
->AutoTunnelTarget
.namestorage
.c
);
4102 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info
->AutoTunnelTarget
.namestorage
.c
);
4104 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info
->AutoTunnelTarget
.resrec
.RecordType
);
4106 if (info
->AutoTunnelService
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4108 // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
4109 mDNS_SetupResourceRecord(&info
->AutoTunnelService
, mDNSNULL
, mDNSInterface_Any
, kDNSType_SRV
, kHostNameTTL
,
4110 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
4111 AssignDomainName (&info
->AutoTunnelService
.namestorage
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
4112 AppendDomainLabel(&info
->AutoTunnelService
.namestorage
, &m
->hostlabel
);
4113 AppendDomainName (&info
->AutoTunnelService
.namestorage
, &info
->domain
);
4114 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.priority
= 0;
4115 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.weight
= 0;
4116 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.port
= m
->AutoTunnelNAT
.ExternalPort
;
4117 AssignDomainName(&info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.target
, &info
->AutoTunnelTarget
.namestorage
);
4118 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4120 mStatus err
= mDNS_Register_internal(m
, &info
->AutoTunnelService
);
4121 if (err
) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
4122 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info
->AutoTunnelService
.namestorage
.c
);
4124 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info
->AutoTunnelService
.resrec
.RecordType
);
4126 UpdateAutoTunnelHostRecord(m
, info
);
4128 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
4129 info
->AutoTunnelTarget
.namestorage
.c
, &m
->AdvertisedV4
.ip
.v4
, mDNSVal16(m
->AutoTunnelNAT
.IntPort
),
4130 info
->AutoTunnelHostRecord
.namestorage
.c
, &info
->AutoTunnelInnerAddress
);
4135 // Caller must hold the lock
4136 mDNSlocal
void DeregisterAutoTunnelDeviceInfoRecord(mDNS
*m
, DomainAuthInfo
*info
)
4138 DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnelDeviceInfo
);
4141 // Caller must hold the lock
4142 mDNSlocal
void UpdateAutoTunnelDeviceInfoRecord(mDNS
*m
, DomainAuthInfo
*info
)
4146 if (!info
->AutoTunnelServiceStarted
|| info
->deltime
|| m
->ShutdownTime
)
4147 DeregisterAutoTunnelDeviceInfoRecord(m
, info
);
4148 else if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4150 mDNS_SetupResourceRecord(&info
->AutoTunnelDeviceInfo
, mDNSNULL
, mDNSInterface_Any
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
4151 ConstructServiceName(&info
->AutoTunnelDeviceInfo
.namestorage
, &m
->nicelabel
, &DeviceInfoName
, &info
->domain
);
4153 info
->AutoTunnelDeviceInfo
.resrec
.rdlength
= initializeDeviceInfoTXT(m
, info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
);
4154 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4156 mStatus err
= mDNS_Register_internal(m
, &info
->AutoTunnelDeviceInfo
);
4157 if (err
) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
4158 else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info
->AutoTunnelDeviceInfo
.namestorage
.c
);
4161 LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info
->AutoTunnelDeviceInfo
.resrec
.RecordType
);
4164 // Caller must hold the lock
4165 mDNSlocal
void DeregisterAutoTunnel6Record(mDNS
*m
, DomainAuthInfo
*info
)
4167 LogInfo("DeregisterAutoTunnel6Record %##s", info
->domain
.c
);
4169 DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnel6Record
);
4170 UpdateAutoTunnelHostRecord(m
, info
);
4171 UpdateAutoTunnelDomainStatus(info
);
4174 // Caller must hold the lock
4175 mDNSlocal
void UpdateAutoTunnel6Record(mDNS
*m
, DomainAuthInfo
*info
)
4179 if (!info
->AutoTunnelServiceStarted
|| info
->deltime
|| m
->ShutdownTime
|| mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
) || m
->SleepState
!= SleepState_Awake
)
4180 DeregisterAutoTunnel6Record(m
, info
);
4181 else if (info
->AutoTunnel6Record
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4183 mDNS_SetupResourceRecord(&info
->AutoTunnel6Record
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
,
4184 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
4185 AssignDomainName (&info
->AutoTunnel6Record
.namestorage
, (const domainname
*) "\x0C" "_autotunnel6");
4186 AppendDomainLabel(&info
->AutoTunnel6Record
.namestorage
, &m
->hostlabel
);
4187 AppendDomainName (&info
->AutoTunnel6Record
.namestorage
, &info
->domain
);
4188 info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
= m
->AutoTunnelRelayAddr
;
4189 info
->AutoTunnel6Record
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4191 mStatus err
= mDNS_Register_internal(m
, &info
->AutoTunnel6Record
);
4192 if (err
) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err
, info
->AutoTunnel6Record
.namestorage
.c
);
4193 else LogInfo("UpdateAutoTunnel6Record registering %##s", info
->AutoTunnel6Record
.namestorage
.c
);
4195 UpdateAutoTunnelHostRecord(m
, info
);
4197 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
4198 info
->AutoTunnel6Record
.namestorage
.c
, &m
->AutoTunnelRelayAddr
,
4199 info
->AutoTunnelHostRecord
.namestorage
.c
, &info
->AutoTunnelInnerAddress
);
4202 else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info
->AutoTunnel6Record
.resrec
.RecordType
);
4205 mDNSlocal
void AutoTunnelRecordCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
4207 DomainAuthInfo
*info
= (DomainAuthInfo
*)rr
->RecordContext
;
4208 if (result
== mStatus_MemFree
)
4210 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m
, rr
));
4214 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
4215 if (rr
== &info
->AutoTunnelHostRecord
)
4217 rr
->namestorage
.c
[0] = 0;
4218 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4219 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m
->NextSRVUpdate
- m
->timenow
, m
->timenow
);
4221 if (m
->ShutdownTime
)
4223 LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
4227 if (rr
== &info
->AutoTunnelHostRecord
)
4229 LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
4230 UpdateAutoTunnelHostRecord(m
,info
);
4232 else if (rr
== &info
->AutoTunnelDeviceInfo
)
4234 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
4235 UpdateAutoTunnelDeviceInfoRecord(m
,info
);
4237 else if (rr
== &info
->AutoTunnelService
|| rr
== &info
->AutoTunnelTarget
)
4239 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
4240 UpdateAutoTunnelServiceRecords(m
,info
);
4242 else if (rr
== &info
->AutoTunnel6Record
)
4244 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
4245 UpdateAutoTunnel6Record(m
,info
);
4252 mDNSlocal
void AutoTunnelNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
4254 DomainAuthInfo
*info
;
4256 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
4257 n
->Result
, &n
->ExternalAddress
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->ExternalPort
));
4261 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4262 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m
->NextSRVUpdate
- m
->timenow
, m
->timenow
);
4264 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
4265 if (info
->AutoTunnel
)
4266 UpdateAutoTunnelServiceRecords(m
, info
);
4268 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
4270 UpdateAutoTunnelDomainStatuses(m
);
4275 mDNSlocal
void AutoTunnelHostNameChanged(mDNS
*m
, DomainAuthInfo
*info
)
4277 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m
->hostlabel
.c
, info
->domain
.c
);
4280 // We forcibly deregister the records that are based on the hostname.
4281 // When deregistration of each completes, the MemFree callback will make the
4282 // appropriate Update* call to use the new name to reregister.
4283 DeregisterAutoTunnelHostRecord(m
, info
);
4284 DeregisterAutoTunnelDeviceInfoRecord(m
, info
);
4285 DeregisterAutoTunnelServiceRecords(m
, info
);
4286 DeregisterAutoTunnel6Record(m
, info
);
4287 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4291 // Must be called with the lock held
4292 mDNSexport
void StartServerTunnel(DomainAuthInfo
*const info
)
4294 mDNS
*const m
= &mDNSStorage
;
4295 if (info
->deltime
) return;
4297 if (info
->AutoTunnelServiceStarted
)
4299 // On wake from sleep, this function will be called when determining SRV targets,
4300 // and needs to re-register the host record for the target to be set correctly
4301 UpdateAutoTunnelHostRecord(m
, info
);
4305 info
->AutoTunnelServiceStarted
= mDNStrue
;
4307 // Now that we have a service in this domain, we need to try to register the
4308 // AutoTunnel records, because the relay connection & NAT-T may have already been
4309 // started for another domain. If the relay connection is not up or the NAT-T has not
4310 // yet succeeded, the Update* functions are smart enough to not register the records.
4311 // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
4312 // decide whether to register the AutoTunnel records in the calls below.
4313 UpdateAutoTunnelServiceRecords(m
, info
);
4314 UpdateAutoTunnel6Record(m
, info
);
4315 UpdateAutoTunnelDeviceInfoRecord(m
, info
);
4316 UpdateAutoTunnelHostRecord(m
, info
);
4318 // If the global AutoTunnel NAT-T is not yet started, start it.
4319 if (!m
->AutoTunnelNAT
.clientContext
)
4321 m
->AutoTunnelNAT
.clientCallback
= AutoTunnelNATCallback
;
4322 m
->AutoTunnelNAT
.clientContext
= (void*)1; // Means AutoTunnelNAT Traversal is active;
4323 m
->AutoTunnelNAT
.Protocol
= NATOp_MapUDP
;
4324 m
->AutoTunnelNAT
.IntPort
= IPSECPort
;
4325 m
->AutoTunnelNAT
.RequestedPort
= IPSECPort
;
4326 m
->AutoTunnelNAT
.NATLease
= 0;
4327 mStatus err
= mDNS_StartNATOperation_internal(m
, &m
->AutoTunnelNAT
);
4328 if (err
) LogMsg("StartServerTunnel: error %d starting NAT mapping", err
);
4332 mDNSlocal mStatus
AutoTunnelSetKeys(ClientTunnel
*tun
, mDNSBool AddNew
)
4334 mDNSv6Addr loc_outer6
;
4335 mDNSv6Addr rmt_outer6
;
4337 // When we are tunneling over IPv6 Relay address, the port number is zero
4338 if (mDNSIPPortIsZero(tun
->rmt_outer_port
))
4340 loc_outer6
= tun
->loc_outer6
;
4341 rmt_outer6
= tun
->rmt_outer6
;
4345 loc_outer6
= zerov6Addr
;
4346 loc_outer6
.b
[0] = tun
->loc_outer
.b
[0];
4347 loc_outer6
.b
[1] = tun
->loc_outer
.b
[1];
4348 loc_outer6
.b
[2] = tun
->loc_outer
.b
[2];
4349 loc_outer6
.b
[3] = tun
->loc_outer
.b
[3];
4351 rmt_outer6
= zerov6Addr
;
4352 rmt_outer6
.b
[0] = tun
->rmt_outer
.b
[0];
4353 rmt_outer6
.b
[1] = tun
->rmt_outer
.b
[1];
4354 rmt_outer6
.b
[2] = tun
->rmt_outer
.b
[2];
4355 rmt_outer6
.b
[3] = tun
->rmt_outer
.b
[3];
4358 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)));
4361 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
4362 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
4364 mDNSlocal
void ReissueBlockedQuestionWithType(domainname
*d
, mDNSBool success
, mDNSu16 qtype
)
4366 mDNS
*const m
= &mDNSStorage
;
4367 DNSQuestion
*q
= m
->Questions
;
4370 if (q
->NoAnswer
== NoAnswer_Suspended
&& q
->qtype
== qtype
&& q
->AuthInfo
&& q
->AuthInfo
->AutoTunnel
&& SameDomainName(&q
->qname
, d
))
4372 LogInfo("Restart %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4373 mDNSQuestionCallback
*tmp
= q
->QuestionCallback
;
4374 q
->QuestionCallback
= AutoTunnelCallback
; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
4375 mDNS_StopQuery(m
, q
);
4376 mDNS_StartQuery(m
, q
);
4377 q
->QuestionCallback
= tmp
; // Restore QuestionCallback back to the real value
4378 if (!success
) q
->NoAnswer
= NoAnswer_Fail
;
4379 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
4380 // In general we have to assume that the question list might have changed in arbitrary ways.
4381 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
4382 // already in use. The safest solution is just to go back to the start of the list and start again.
4383 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
4384 // just one suspended question, so it's really a 2n algorithm.
4392 mDNSlocal
void ReissueBlockedQuestions(domainname
*d
, mDNSBool success
)
4394 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
4395 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
4396 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
4397 // 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.
4398 // 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.
4399 ReissueBlockedQuestionWithType(d
, success
, kDNSType_AAAA
);
4400 ReissueBlockedQuestionWithType(d
, mDNStrue
, kDNSType_A
);
4403 mDNSlocal
void UnlinkAndReissueBlockedQuestions(ClientTunnel
*tun
, mDNSBool success
)
4405 mDNS
*const m
= &mDNSStorage
;
4406 ClientTunnel
**p
= &m
->TunnelClients
;
4407 while (*p
!= tun
&& *p
) p
= &(*p
)->next
;
4408 if (*p
) *p
= tun
->next
;
4409 ReissueBlockedQuestions(&tun
->dstname
, success
);
4410 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun
);
4411 freeL("ClientTunnel", tun
);
4414 mDNSlocal mDNSBool
TunnelClientDeleteMatching(ClientTunnel
*tun
, mDNSBool v6Tunnel
)
4416 mDNS
*const m
= &mDNSStorage
;
4418 mDNSBool needSetKeys
= mDNStrue
;
4423 // Is this a tunnel to the same host that we are trying to setup now?
4424 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
4427 ClientTunnel
*old
= *p
;
4430 if (!mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue; }
4431 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4432 if (old
->q
.ThisQInterval
>= 0)
4434 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4435 mDNS_StopQuery(m
, &old
->q
);
4437 else if (!mDNSSameIPv6Address((*p
)->rmt_inner
, tun
->rmt_inner
) ||
4438 !mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
4439 !mDNSSameIPv6Address(old
->loc_outer6
, tun
->loc_outer6
) ||
4440 !mDNSSameIPv6Address(old
->rmt_outer6
, tun
->rmt_outer6
))
4442 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4443 // the other parameters of the tunnel are different
4444 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4445 AutoTunnelSetKeys(old
, mDNSfalse
);
4449 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4450 // as "tun" and "old" are identical
4451 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
,
4453 needSetKeys
= mDNSfalse
;
4458 if (mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue; }
4459 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4460 if (old
->q
.ThisQInterval
>= 0)
4462 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4463 mDNS_StopQuery(m
, &old
->q
);
4465 else if (!mDNSSameIPv6Address((*p
)->rmt_inner
, tun
->rmt_inner
) ||
4466 !mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
4467 !mDNSSameIPv4Address(old
->loc_outer
, tun
->loc_outer
) ||
4468 !mDNSSameIPv4Address(old
->rmt_outer
, tun
->rmt_outer
) ||
4469 !mDNSSameIPPort(old
->rmt_outer_port
, tun
->rmt_outer_port
))
4471 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4472 // the other parameters of the tunnel are different
4473 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4474 AutoTunnelSetKeys(old
, mDNSfalse
);
4478 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4479 // as "tun" and "old" are identical
4480 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
,
4482 needSetKeys
= mDNSfalse
;
4487 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old
);
4488 freeL("ClientTunnel", old
);
4494 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
4495 // tunnel will be deleted
4496 mDNSlocal
void TunnelClientDeleteAny(ClientTunnel
*tun
, mDNSBool v6Tunnel
)
4503 // If there is more than one client tunnel to the same host, delete all of them.
4504 // We do this by just checking against the EUI64 rather than the full address
4505 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
4508 ClientTunnel
*old
= *p
;
4511 if (!mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue;}
4512 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4516 if (mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue;}
4517 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4519 if (old
->q
.ThisQInterval
>= 0)
4521 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4522 mDNS_StopQuery(&mDNSStorage
, &old
->q
);
4526 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4527 AutoTunnelSetKeys(old
, mDNSfalse
);
4530 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old
);
4531 freeL("ClientTunnel", old
);
4536 mDNSlocal
void TunnelClientFinish(DNSQuestion
*question
, const ResourceRecord
*const answer
)
4538 mDNS
*const m
= &mDNSStorage
;
4539 mDNSBool needSetKeys
= mDNStrue
;
4540 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
4541 mDNSBool v6Tunnel
= mDNSfalse
;
4542 DomainAuthInfo
*info
;
4544 // If the port is zero, then we have a relay address of the peer
4545 if (mDNSIPPortIsZero(tun
->rmt_outer_port
))
4546 v6Tunnel
= mDNStrue
;
4550 LogInfo("TunnelClientFinish: Relay address %.16a", &answer
->rdata
->u
.ipv6
);
4551 tun
->rmt_outer6
= answer
->rdata
->u
.ipv6
;
4552 tun
->loc_outer6
= m
->AutoTunnelRelayAddr
;
4556 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer
->rdata
->u
.ipv4
);
4557 tun
->rmt_outer
= answer
->rdata
->u
.ipv4
;
4558 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
4559 tmpDst
.ip
.v4
= tun
->rmt_outer
;
4560 mDNSAddr tmpSrc
= zeroAddr
;
4561 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
4562 if (tmpSrc
.type
== mDNSAddrType_IPv4
) tun
->loc_outer
= tmpSrc
.ip
.v4
;
4563 else tun
->loc_outer
= m
->AdvertisedV4
.ip
.v4
;
4566 question
->ThisQInterval
= -1; // So we know this tunnel setup has completed
4568 info
= GetAuthInfoForName(m
, &tun
->dstname
);
4571 LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun
->dstname
.c
);
4572 ReissueBlockedQuestions(&tun
->dstname
, mDNSfalse
);
4576 tun
->loc_inner
= info
->AutoTunnelInnerAddress
;
4578 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
4579 // look for existing tunnels to see whether they have the same information for our peer.
4580 // If not, delete them and need to create a new tunnel. If they are same, just use the
4581 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
4582 TunnelClientDeleteAny(tun
, !v6Tunnel
);
4583 needSetKeys
= TunnelClientDeleteMatching(tun
, v6Tunnel
);
4585 if (needSetKeys
) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel
? "IPv6" : "IPv4"), tun
->dstname
.c
, &tun
->rmt_inner
);
4586 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel
? "IPv6" : "IPv4"), tun
->dstname
.c
, &tun
->rmt_inner
);
4588 mStatus result
= needSetKeys
? AutoTunnelSetKeys(tun
, mDNStrue
) : mStatus_NoError
;
4589 LogInfo("TunnelClientFinish: Tunnel setup result %d", result
);
4590 // Kick off any questions that were held pending this tunnel setup
4591 ReissueBlockedQuestions(&tun
->dstname
, (result
== mStatus_NoError
) ? mDNStrue
: mDNSfalse
);
4594 mDNSexport
void AutoTunnelCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
4596 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
4597 DomainAuthInfo
*info
;
4599 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun
, AddRecord
, answer
->rdlength
, question
->qtype
);
4601 if (!AddRecord
) return;
4602 mDNS_StopQuery(m
, question
);
4604 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
4605 // The code below will look for _autotunnel._udp SRV record followed by A record
4606 if (tun
->tc_state
!= TC_STATE_AAAA_PEER_RELAY
&& !answer
->rdlength
)
4608 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
4609 UnlinkAndReissueBlockedQuestions(tun
, mDNSfalse
);
4613 switch (tun
->tc_state
)
4615 case TC_STATE_AAAA_PEER
:
4616 if (question
->qtype
!= kDNSType_AAAA
)
4618 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question
->qtype
);
4620 info
= GetAuthInfoForName(m
, &tun
->dstname
);
4623 LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun
->dstname
.c
);
4624 UnlinkAndReissueBlockedQuestions(tun
, mDNStrue
);
4627 if (mDNSSameIPv6Address(answer
->rdata
->u
.ipv6
, info
->AutoTunnelInnerAddress
))
4629 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer
->rdata
->u
.ipv6
);
4630 UnlinkAndReissueBlockedQuestions(tun
, mDNStrue
);
4633 if (info
&& mDNSSameIPv6NetworkPart(answer
->rdata
->u
.ipv6
, info
->AutoTunnelInnerAddress
))
4635 LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer
->rdata
->u
.ipv6
);
4636 UnlinkAndReissueBlockedQuestions(tun
, mDNStrue
);
4639 tun
->rmt_inner
= answer
->rdata
->u
.ipv6
;
4640 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun
->rmt_inner
);
4641 if (!mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
))
4643 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
4644 tun
->tc_state
= TC_STATE_AAAA_PEER_RELAY
;
4645 question
->qtype
= kDNSType_AAAA
;
4646 AssignDomainName(&question
->qname
, (const domainname
*) "\x0C" "_autotunnel6");
4650 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
4651 tun
->tc_state
= TC_STATE_SRV_PEER
;
4652 question
->qtype
= kDNSType_SRV
;
4653 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
4655 AppendDomainName(&question
->qname
, &tun
->dstname
);
4656 mDNS_StartQuery(m
, &tun
->q
);
4658 case TC_STATE_AAAA_PEER_RELAY
:
4659 if (question
->qtype
!= kDNSType_AAAA
)
4661 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question
->qtype
);
4663 // If it failed, look for the SRV record.
4664 if (!answer
->rdlength
)
4666 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
4667 tun
->tc_state
= TC_STATE_SRV_PEER
;
4668 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
4669 AppendDomainName(&question
->qname
, &tun
->dstname
);
4670 question
->qtype
= kDNSType_SRV
;
4671 mDNS_StartQuery(m
, &tun
->q
);
4674 TunnelClientFinish(question
, answer
);
4676 case TC_STATE_SRV_PEER
:
4677 if (question
->qtype
!= kDNSType_SRV
)
4679 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question
->qtype
);
4681 LogInfo("AutoTunnelCallback: SRV target name %##s", answer
->rdata
->u
.srv
.target
.c
);
4682 tun
->tc_state
= TC_STATE_ADDR_PEER
;
4683 AssignDomainName(&tun
->q
.qname
, &answer
->rdata
->u
.srv
.target
);
4684 tun
->rmt_outer_port
= answer
->rdata
->u
.srv
.port
;
4685 question
->qtype
= kDNSType_A
;
4686 mDNS_StartQuery(m
, &tun
->q
);
4688 case TC_STATE_ADDR_PEER
:
4689 if (question
->qtype
!= kDNSType_A
)
4691 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question
->qtype
);
4693 TunnelClientFinish(question
, answer
);
4696 LogMsg("AutoTunnelCallback: Unknown question %p", question
);
4700 // Must be called with the lock held
4701 mDNSexport
void AddNewClientTunnel(DNSQuestion
*const q
)
4703 mDNS
*const m
= &mDNSStorage
;
4704 ClientTunnel
*p
= mallocL("ClientTunnel", sizeof(ClientTunnel
));
4706 AssignDomainName(&p
->dstname
, &q
->qname
);
4707 p
->MarkedForDeletion
= mDNSfalse
;
4708 p
->loc_inner
= zerov6Addr
;
4709 p
->loc_outer
= zerov4Addr
;
4710 p
->loc_outer6
= zerov6Addr
;
4711 p
->rmt_inner
= zerov6Addr
;
4712 p
->rmt_outer
= zerov4Addr
;
4713 p
->rmt_outer6
= zerov6Addr
;
4714 p
->rmt_outer_port
= zeroIPPort
;
4715 p
->tc_state
= TC_STATE_AAAA_PEER
;
4716 p
->next
= m
->TunnelClients
;
4717 m
->TunnelClients
= p
; // We intentionally build list in reverse order
4719 p
->q
.InterfaceID
= mDNSInterface_Any
;
4721 p
->q
.Target
= zeroAddr
;
4722 AssignDomainName(&p
->q
.qname
, &q
->qname
);
4723 p
->q
.qtype
= kDNSType_AAAA
;
4724 p
->q
.qclass
= kDNSClass_IN
;
4725 p
->q
.LongLived
= mDNSfalse
;
4726 p
->q
.ExpectUnique
= mDNStrue
;
4727 p
->q
.ForceMCast
= mDNSfalse
;
4728 p
->q
.ReturnIntermed
= mDNStrue
;
4729 p
->q
.SuppressUnusable
= mDNSfalse
;
4730 p
->q
.SearchListIndex
= 0;
4731 p
->q
.AppendSearchDomains
= 0;
4732 p
->q
.RetryWithSearchDomains
= mDNSfalse
;
4733 p
->q
.TimeoutQuestion
= 0;
4734 p
->q
.WakeOnResolve
= 0;
4735 p
->q
.UseBackgroundTrafficClass
= mDNSfalse
;
4736 p
->q
.ValidationRequired
= 0;
4737 p
->q
.ValidatingResponse
= 0;
4738 p
->q
.ProxyQuestion
= 0;
4739 p
->q
.qnameOrig
= mDNSNULL
;
4740 p
->q
.AnonInfo
= mDNSNULL
;
4741 p
->q
.pid
= mDNSPlatformGetPID();
4743 p
->q
.QuestionCallback
= AutoTunnelCallback
;
4744 p
->q
.QuestionContext
= p
;
4746 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p
, &q
->qname
.c
, DNSTypeName(q
->qtype
), q
->LongLived
? " LongLived" : "");
4747 mDNS_StartQuery_internal(m
, &p
->q
);
4750 #endif // APPLE_OSX_mDNSResponder
4752 #if COMPILER_LIKES_PRAGMA_MARK
4754 #pragma mark - Power State & Configuration Change Management
4757 mDNSlocal mStatus
ReorderInterfaceList()
4759 // Disable Reorder lists till <rdar://problem/30071012> is fixed to prevent spurious name conflicts
4760 return (mStatus_NoError
);
4762 mDNS
*const m
= &mDNSStorage
;
4763 nwi_state_t state
= nwi_state_copy();
4765 if (state
== mDNSNULL
)
4767 LogMsg("NWI State is NULL!");
4768 return (mStatus_Invalid
);
4771 // Get the count of interfaces
4772 mDNSu32 count
= nwi_state_get_interface_names(state
, mDNSNULL
, 0);
4775 LogMsg("Unable to get the ordered list of interface names");
4776 nwi_state_release(state
);
4777 return (mStatus_Invalid
);
4780 // Get the ordered interface list
4782 const char *names
[count
];
4783 count
= nwi_state_get_interface_names(state
, names
, count
);
4785 NetworkInterfaceInfo
*newList
= mDNSNULL
;
4786 for (i
= count
-1; i
>= 0; i
--)
4787 { // Build a new ordered interface list
4788 NetworkInterfaceInfo
**ptr
= &m
->HostInterfaces
;
4789 while (*ptr
!= mDNSNULL
)
4791 if (strcmp((*ptr
)->ifname
, names
[i
]) == 0)
4793 NetworkInterfaceInfo
*node
= *ptr
;
4794 *ptr
= (*ptr
)->next
;
4795 node
->next
= newList
;
4799 ptr
= &((*ptr
)->next
);
4803 // Get to the end of the list
4804 NetworkInterfaceInfo
*newListEnd
= newList
;
4805 while (newListEnd
!= mDNSNULL
&& newListEnd
->next
!= mDNSNULL
)
4806 newListEnd
= newListEnd
->next
;
4808 // Add any remaing interfaces to the end of the sorted list
4809 if (newListEnd
!= mDNSNULL
)
4810 newListEnd
->next
= m
->HostInterfaces
;
4812 // If we have a valid new list, point to that now
4813 if (newList
!= mDNSNULL
)
4814 m
->HostInterfaces
= newList
;
4816 nwi_state_release(state
);
4817 return (mStatus_NoError
);
4820 mDNSlocal mStatus
UpdateInterfaceList(mDNSs32 utc
)
4822 mDNS
*const m
= &mDNSStorage
;
4823 mDNSBool foundav4
= mDNSfalse
;
4824 mDNSBool foundav6
= mDNSfalse
;
4825 struct ifaddrs
*ifa
= myGetIfAddrs(0);
4826 struct ifaddrs
*v4Loopback
= NULL
;
4827 struct ifaddrs
*v6Loopback
= NULL
;
4828 char defaultname
[64];
4829 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
4830 if (InfoSocket
< 3 && errno
!= EAFNOSUPPORT
)
4831 LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
4833 if (m
->SleepState
== SleepState_Sleeping
) ifa
= NULL
;
4837 #if LIST_ALL_INTERFACES
4840 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
4841 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
4842 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4843 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
4844 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
4845 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4846 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
4847 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
4848 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4851 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X ifa_addr is NOT set",
4852 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
);
4854 if (!(ifa
->ifa_flags
& IFF_UP
))
4855 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
4856 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
,
4857 ifa
->ifa_addr
? ifa
->ifa_addr
->sa_family
: 0);
4858 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
4859 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
4860 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
,
4861 ifa
->ifa_addr
? ifa
->ifa_addr
->sa_family
: 0);
4862 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
4863 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
4864 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
,
4865 ifa
->ifa_addr
? ifa
->ifa_addr
->sa_family
: 0);
4866 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
4867 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
4868 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
,
4869 ifa
->ifa_addr
? ifa
->ifa_addr
->sa_family
: 0);
4872 if (ifa
->ifa_addr
&& ifa
->ifa_addr
->sa_family
== AF_LINK
)
4874 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
4875 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(m
->PrimaryMAC
) && mDNSSameEthAddress(&m
->PrimaryMAC
, &zeroEthAddr
))
4876 mDNSPlatformMemCopy(m
->PrimaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6);
4879 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
&& !isCoprocessorInterface(InfoSocket
, ifa
->ifa_name
))
4880 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
4882 if (!ifa
->ifa_netmask
)
4885 SetupAddr(&ip
, ifa
->ifa_addr
);
4886 LogMsg("UpdateInterfaceList: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
4887 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
4889 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
4890 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4891 else if (ifa
->ifa_netmask
->sa_family
!= ifa
->ifa_addr
->sa_family
&& ifa
->ifa_netmask
->sa_family
!= 0)
4894 SetupAddr(&ip
, ifa
->ifa_addr
);
4895 LogMsg("UpdateInterfaceList: ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
4896 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
4898 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
4899 else if ((int)if_nametoindex(ifa
->ifa_name
) <= 0)
4901 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
));
4905 // Make sure ifa_netmask->sa_family is set correctly
4906 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4907 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
;
4908 int ifru_flags6
= 0;
4910 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
4911 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
4913 struct in6_ifreq ifr6
;
4914 mDNSPlatformMemZero((char *)&ifr6
, sizeof(ifr6
));
4915 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
4916 ifr6
.ifr_addr
= *sin6
;
4917 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
4918 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
4919 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
4922 if (!(ifru_flags6
& (IN6_IFF_TENTATIVE
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
4924 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
4926 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
4928 else if (sin6
->sin6_addr
.s6_addr
[0] != 0xFD)
4933 NetworkInterfaceInfoOSX
*i
= AddInterfaceToList(ifa
, utc
);
4934 if (i
&& MulticastInterface(i
) && i
->ifinfo
.Advertise
)
4936 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
4937 foundav4
= mDNStrue
;
4939 foundav6
= mDNStrue
;
4945 ifa
= ifa
->ifa_next
;
4948 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
4949 if (!foundav4
&& v4Loopback
) AddInterfaceToList(v4Loopback
, utc
);
4950 if (!foundav6
&& v6Loopback
) AddInterfaceToList(v6Loopback
, utc
);
4952 if (InfoSocket
>= 0)
4955 mDNS_snprintf(defaultname
, sizeof(defaultname
), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen
, HINFO_HWstring
,
4956 m
->PrimaryMAC
.b
[0], m
->PrimaryMAC
.b
[1], m
->PrimaryMAC
.b
[2], m
->PrimaryMAC
.b
[3], m
->PrimaryMAC
.b
[4], m
->PrimaryMAC
.b
[5]);
4958 // Set up the nice label
4959 domainlabel nicelabel
;
4961 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
4962 if (nicelabel
.c
[0] == 0)
4964 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname
);
4965 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
4968 // Set up the RFC 1034-compliant label
4969 domainlabel hostlabel
;
4971 GetUserSpecifiedLocalHostName(&hostlabel
);
4972 if (hostlabel
.c
[0] == 0)
4974 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname
);
4975 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
4978 mDNSBool namechange
= mDNSfalse
;
4980 // We use a case-sensitive comparison here because even though changing the capitalization
4981 // of the name alone is not significant to DNS, it's still a change from the user's point of view
4982 if (SameDomainLabelCS(m
->p
->usernicelabel
.c
, nicelabel
.c
))
4983 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
4986 if (m
->p
->usernicelabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
4987 LogMsg("User updated Computer Name from “%#s” to “%#s”", m
->p
->usernicelabel
.c
, nicelabel
.c
);
4988 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
4989 namechange
= mDNStrue
;
4992 if (SameDomainLabelCS(m
->p
->userhostlabel
.c
, hostlabel
.c
))
4993 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
4996 if (m
->p
->userhostlabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
4997 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m
->p
->userhostlabel
.c
, hostlabel
.c
);
4998 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
5000 namechange
= mDNStrue
;
5003 if (namechange
) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
5005 #if APPLE_OSX_mDNSResponder
5006 DomainAuthInfo
*info
;
5007 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
5008 if (info
->AutoTunnel
) AutoTunnelHostNameChanged(m
, info
);
5009 #endif // APPLE_OSX_mDNSResponder
5012 return(mStatus_NoError
);
5015 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
5016 // Returns -1 if all the one-bits are not contiguous
5017 mDNSlocal
int CountMaskBits(mDNSAddr
*mask
)
5019 int i
= 0, bits
= 0;
5020 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
5023 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
5024 while (b
& 0x80) { bits
++; b
<<= 1; }
5027 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
5031 // Returns count of non-link local V4 addresses registered (why? -- SC)
5032 mDNSlocal
int SetupActiveInterfaces(mDNSs32 utc
)
5034 mDNS
*const m
= &mDNSStorage
;
5035 NetworkInterfaceInfoOSX
*i
;
5038 // Recalculate SuppressProbes time based on the current set of active interfaces.
5039 m
->SuppressProbes
= 0;
5040 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
5043 NetworkInterfaceInfo
*const n
= &i
->ifinfo
;
5044 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_UNSPEC
);
5045 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifinfo
.ifname
);
5047 if (i
->Registered
&& i
->Registered
!= primary
) // Sanity check
5049 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i
->Registered
, primary
);
5050 i
->Registered
= mDNSNULL
;
5055 InterfaceActivationSpeed activationSpeed
;
5057 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5058 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5059 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it.
5060 i
->Registered
= primary
;
5062 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
5063 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
5064 // 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.
5065 i
->Occulting
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->LastSeen
> 0 && utc
- i
->LastSeen
< 60);
5067 // The "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
5068 // every time a new interface is created. We think it is a duplicate and hence consider it
5069 // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
5070 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
5071 // logs a warning message to system.log noting frequent interface transitions.
5072 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
5073 if ((strncmp(i
->ifinfo
.ifname
, "p2p", 3) == 0) || i
->ifinfo
.DirectLink
)
5075 activationSpeed
= FastActivation
;
5076 LogInfo("SetupActiveInterfaces: %s DirectLink interface registering", i
->ifinfo
.ifname
);
5078 else if (i
->Flashing
&& i
->Occulting
)
5080 activationSpeed
= SlowActivation
;
5084 activationSpeed
= NormalActivation
;
5087 mDNS_RegisterInterface(m
, n
, activationSpeed
);
5089 if (!mDNSAddressIsLinkLocal(&n
->ip
)) count
++;
5090 LogInfo("SetupActiveInterfaces: Registered %7s(%u) BSSID %.6a Struct addr %p, primary %p, %#a/%d%s%s%s",
5091 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
, primary
, &n
->ip
, CountMaskBits(&n
->mask
),
5092 i
->Flashing
? " (Flashing)" : "",
5093 i
->Occulting
? " (Occulting)" : "",
5094 n
->InterfaceActive
? " (Primary)" : "");
5098 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
);
5099 #if TARGET_OS_EMBEDDED
5100 // We join the Bonjour multicast group on Apple embedded platforms ONLY when a client request is active,
5101 // so we leave the multicast group here to clear any residual group membership.
5102 if (i
->sa_family
== AF_INET
)
5105 primary
->ifa_v4addr
.s_addr
= n
->ip
.ip
.v4
.NotAnInteger
;
5106 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
5107 imr
.imr_interface
= primary
->ifa_v4addr
;
5109 if (SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_INET
) == i
)
5111 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IP_DROP_MEMBERSHIP for %.4a on %.4a", i
->ifinfo
.ifname
, i
->scope_id
, &imr
.imr_multiaddr
, &imr
.imr_interface
);
5112 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, &imr
, sizeof(imr
));
5113 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
5114 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err
, errno
, strerror(errno
));
5117 if (i
->sa_family
== AF_INET6
)
5119 struct ipv6_mreq i6mr
;
5120 i6mr
.ipv6mr_interface
= primary
->scope_id
;
5121 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroup_v6
.ip
.v6
;
5123 if (SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_INET6
) == i
)
5125 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IPV6_LEAVE_GROUP for %.16a on %u", i
->ifinfo
.ifname
, i
->scope_id
, &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5126 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
5127 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
5128 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5131 #endif // TARGET_OS_EMBEDDED
5135 if (i
->sa_family
== AF_INET
)
5138 primary
->ifa_v4addr
.s_addr
= n
->ip
.ip
.v4
.NotAnInteger
;
5139 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
5140 imr
.imr_interface
= primary
->ifa_v4addr
;
5142 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
5143 // before trying to join the group, to clear out stale kernel state which may be lingering.
5144 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
5145 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
5146 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
5147 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
5148 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
5149 // because by the time we get the configuration change notification, the interface is already gone,
5150 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
5151 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
5152 if (SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_INET
) == i
)
5154 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
);
5155 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, &imr
, sizeof(imr
));
5156 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
5157 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err
, errno
, strerror(errno
));
5160 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i
->ifinfo
.ifname
, i
->scope_id
, &imr
.imr_multiaddr
, &imr
.imr_interface
);
5161 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
5162 // Joining same group twice can give "Address already in use" error -- no need to report that
5163 if (err
< 0 && (errno
!= EADDRINUSE
))
5164 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err
, errno
, strerror(errno
), &imr
.imr_multiaddr
, &imr
.imr_interface
);
5166 if (i
->sa_family
== AF_INET6
)
5168 struct ipv6_mreq i6mr
;
5169 i6mr
.ipv6mr_interface
= primary
->scope_id
;
5170 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroup_v6
.ip
.v6
;
5172 if (SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_INET6
) == i
)
5174 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
);
5175 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
5176 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
5177 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5180 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i
->ifinfo
.ifname
, i
->scope_id
, &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5181 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
5182 // Joining same group twice can give "Address already in use" error -- no need to report that
5183 if (err
< 0 && (errno
!= EADDRINUSE
))
5184 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5193 mDNSlocal
void MarkAllInterfacesInactive(mDNSs32 utc
)
5195 NetworkInterfaceInfoOSX
*i
;
5196 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
5198 if (i
->Exists
) i
->LastSeen
= utc
;
5199 i
->Exists
= mDNSfalse
;
5203 // Returns count of non-link local V4 addresses deregistered (why? -- SC)
5204 mDNSlocal
int ClearInactiveInterfaces(mDNSs32 utc
)
5206 mDNS
*const m
= &mDNSStorage
;
5208 // If an interface is going away, then deregister this from the mDNSCore.
5209 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
5210 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
5211 // it refers to has gone away we'll crash.
5212 NetworkInterfaceInfoOSX
*i
;
5214 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
5216 // If this interface is no longer active, or its InterfaceID is changing, deregister it
5217 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(i
->ifinfo
.ifname
, AF_UNSPEC
);
5219 if (i
->Exists
== 0 || i
->Exists
== MulticastStateChanged
|| i
->Registered
!= primary
)
5221 InterfaceActivationSpeed activationSpeed
;
5223 i
->Flashing
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->AppearanceTime
< 60);
5224 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5225 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
, primary
,
5226 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
),
5227 i
->Flashing
? " (Flashing)" : "",
5228 i
->Occulting
? " (Occulting)" : "",
5229 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
5231 // "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
5232 // every time it creates a new interface. We think it is a duplicate and hence consider it
5233 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
5234 // stale data returned to the application even after the interface is removed. The application
5235 // then starts to send data but the new interface is not yet created.
5236 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
5237 if ((strncmp(i
->ifinfo
.ifname
, "p2p", 3) == 0) || i
->ifinfo
.DirectLink
)
5239 activationSpeed
= FastActivation
;
5240 LogInfo("ClearInactiveInterfaces: %s DirectLink interface deregistering", i
->ifinfo
.ifname
);
5242 else if (i
->Flashing
&& i
->Occulting
)
5244 activationSpeed
= SlowActivation
;
5248 activationSpeed
= NormalActivation
;
5250 mDNS_DeregisterInterface(m
, &i
->ifinfo
, activationSpeed
);
5252 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
5253 i
->Registered
= mDNSNULL
;
5254 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5255 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5256 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
5258 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
5259 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
5264 // Now that everything that's going to deregister has done so, we can clean up and free the memory
5265 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
5269 // If no longer active, delete interface from list and free memory
5272 if (i
->LastSeen
== utc
) i
->LastSeen
= utc
- 1;
5273 const mDNSBool
delete = (i
->isAWDL
|| (NumCacheRecordsForInterfaceID(m
, i
->ifinfo
.InterfaceID
) == 0)) && (utc
- i
->LastSeen
>= 60);
5274 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
5275 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
,
5276 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), utc
- i
->LastSeen
,
5277 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
5278 #if APPLE_OSX_mDNSResponder
5279 if (i
->BPF_fd
>= 0) CloseBPF(i
);
5280 #endif // APPLE_OSX_mDNSResponder
5284 freeL("NetworkInterfaceInfoOSX", i
);
5285 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
5293 mDNSlocal
void AppendDNameListElem(DNameListElem
***List
, mDNSu32 uid
, domainname
*name
)
5295 DNameListElem
*dnle
= (DNameListElem
*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem
));
5296 if (!dnle
) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
5299 dnle
->next
= mDNSNULL
;
5301 AssignDomainName(&dnle
->name
, name
);
5303 *List
= &dnle
->next
;
5307 mDNSlocal
int compare_dns_configs(const void *aa
, const void *bb
)
5309 dns_resolver_t
*a
= *(dns_resolver_t
**)aa
;
5310 dns_resolver_t
*b
= *(dns_resolver_t
**)bb
;
5312 return (a
->search_order
< b
->search_order
) ? -1 : (a
->search_order
== b
->search_order
) ? 0 : 1;
5315 mDNSlocal
void UpdateSearchDomainHash(MD5_CTX
*sdc
, char *domain
, mDNSInterfaceID InterfaceID
)
5317 mDNS
*const m
= &mDNSStorage
;
5319 mDNSu32 scopeid
= 0;
5325 // Hash the search domain name followed by the InterfaceID.
5326 // As we have scoped search domains, we also included InterfaceID. If either of them change,
5327 // we will detect it. Even if the order of them change, we will detect it.
5329 // Note: We have to handle a few of these tricky cases.
5331 // 1) Current: com, apple.com Changing to: comapple.com
5332 // 2) Current: a.com,b.com Changing to a.comb.com
5333 // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
5334 // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
5336 // There are more variants of the above. The key thing is if we include the null in each case
5337 // at the end of name and the InterfaceID, it will prevent a new name (which can't include
5338 // NULL as part of the name) to be mistakenly thought of as a old name.
5340 scopeid
= mDNSPlatformInterfaceIndexfromInterfaceID(m
, InterfaceID
, mDNStrue
);
5341 // mDNS_snprintf always null terminates
5342 if (mDNS_snprintf(ifid_buf
, sizeof(ifid_buf
), "%u", scopeid
) >= sizeof(ifid_buf
))
5343 LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid
);
5345 LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf
, ifid_buf
);
5346 MD5_Update(sdc
, buf
, strlen(buf
) + 1);
5347 MD5_Update(sdc
, ifid_buf
, strlen(ifid_buf
) + 1);
5350 mDNSlocal
void FinalizeSearchDomainHash(MD5_CTX
*sdc
)
5352 mDNS
*const m
= &mDNSStorage
;
5353 mDNSu8 md5_hash
[MD5_LEN
];
5355 MD5_Final(md5_hash
, sdc
);
5357 if (memcmp(md5_hash
, m
->SearchDomainsHash
, MD5_LEN
))
5359 // If the hash is different, either the search domains have changed or
5360 // the ordering between them has changed. Restart the questions that
5361 // would be affected by this.
5362 LogInfo("FinalizeSearchDomains: The hash is different");
5363 memcpy(m
->SearchDomainsHash
, md5_hash
, MD5_LEN
);
5364 RetrySearchDomainQuestions(m
);
5366 else { LogInfo("FinalizeSearchDomains: The hash is same"); }
5369 mDNSexport
const char *DNSScopeToString(mDNSu32 scope
)
5375 case kScopeInterfaceID
:
5376 return "InterfaceScoped";
5377 case kScopeServiceID
:
5378 return "ServiceScoped";
5384 mDNSlocal
void ConfigSearchDomains(dns_resolver_t
*resolver
, mDNSInterfaceID interfaceId
, mDNSu32 scope
, MD5_CTX
*sdc
, uint64_t generation
)
5386 const char *scopeString
= DNSScopeToString(scope
);
5390 if (scope
== kScopeNone
)
5391 interfaceId
= mDNSInterface_Any
;
5393 if (scope
== kScopeNone
|| scope
== kScopeInterfaceID
)
5395 for (j
= 0; j
< resolver
->n_search
; j
++)
5397 if (MakeDomainNameFromDNSNameString(&d
, resolver
->search
[j
]) != NULL
)
5399 static char interface_buf
[32];
5400 mDNS_snprintf(interface_buf
, sizeof(interface_buf
), "for interface %s", InterfaceNameForID(&mDNSStorage
, interfaceId
));
5401 LogInfo("ConfigSearchDomains: (%s) configuring search domain %s %s (generation= %llu)", scopeString
,
5402 resolver
->search
[j
], (interfaceId
== mDNSInterface_Any
) ? "" : interface_buf
, generation
);
5403 UpdateSearchDomainHash(sdc
, resolver
->search
[j
], interfaceId
);
5404 mDNS_AddSearchDomain_CString(resolver
->search
[j
], interfaceId
);
5408 LogInfo("ConfigSearchDomains: An invalid search domain was detected for %s domain %s n_nameserver %d, (generation= %llu)",
5409 DNSScopeToString(scope
), resolver
->domain
, resolver
->n_nameserver
, generation
);
5415 LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString
, InterfaceNameForID(&mDNSStorage
, interfaceId
));
5419 mDNSlocal mDNSInterfaceID
ConfigParseInterfaceID(mDNSu32 ifindex
)
5421 NetworkInterfaceInfoOSX
*ni
;
5422 mDNSInterfaceID interface
;
5424 for (ni
= mDNSStorage
.p
->InterfaceList
; ni
; ni
= ni
->next
)
5426 if (ni
->ifinfo
.InterfaceID
&& ni
->scope_id
== ifindex
)
5431 interface
= ni
->ifinfo
.InterfaceID
;
5435 // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
5436 // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
5437 // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
5438 // As the caller is going to ack the configuration always, we have to add all the DNS servers
5439 // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
5441 LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex
);
5443 // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
5444 interface
= (mDNSInterfaceID
)(unsigned long)ifindex
;
5449 mDNSlocal
void ConfigNonUnicastResolver(dns_resolver_t
*r
)
5451 char *opt
= r
->options
;
5454 if (opt
&& !strncmp(opt
, "mdns", strlen(opt
)))
5456 if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
))
5458 LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r
->domain
);
5461 mDNS_AddMcastResolver(&mDNSStorage
, &d
, mDNSInterface_Any
, r
->timeout
);
5465 mDNSlocal
void ConfigDNSServers(dns_resolver_t
*r
, mDNSInterfaceID interface
, mDNSu32 scope
, mDNSu16 resGroupID
)
5470 mDNSBool cellIntf
= mDNSfalse
;
5471 mDNSBool reqA
, reqAAAA
;
5472 NetworkInterfaceInfoOSX
*info
;
5473 mDNSBool isExpensive
;
5476 if (!r
->domain
|| !*r
->domain
)
5480 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
))
5482 LogMsg("ConfigDNSServers: bad domain %s", r
->domain
);
5485 // Parse the resolver specific attributes that affects all the DNS servers.
5486 if (scope
== kScopeServiceID
)
5488 serviceID
= r
->service_identifier
;
5491 #if TARGET_OS_IPHONE
5492 cellIntf
= (r
->reach_flags
& kSCNetworkReachabilityFlagsIsWWAN
) ? mDNStrue
: mDNSfalse
;
5494 reqA
= (r
->flags
& DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
? mDNStrue
: mDNSfalse
);
5495 reqAAAA
= (r
->flags
& DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
? mDNStrue
: mDNSfalse
);
5496 info
= IfindexToInterfaceInfoOSX(interface
);
5497 isExpensive
= (info
&& info
->isExpensive
) ? mDNStrue
: mDNSfalse
;
5498 isCLAT46
= (info
&& info
->isCLAT46
) ? mDNStrue
: mDNSfalse
;
5500 for (n
= 0; n
< r
->n_nameserver
; n
++)
5505 if (r
->nameserver
[n
]->sa_family
!= AF_INET
&& r
->nameserver
[n
]->sa_family
!= AF_INET6
)
5508 if (SetupAddr(&saddr
, r
->nameserver
[n
]))
5510 LogMsg("ConfigDNSServers: Bad address");
5514 // The timeout value is for all the DNS servers in a given resolver, hence we pass
5515 // the timeout value only for the first DNSServer. If we don't have a value in the
5516 // resolver, then use the core's default value
5518 // Note: this assumes that when the core picks a list of DNSServers for a question,
5519 // it takes the sum of all the timeout values for all DNS servers. By doing this, it
5520 // tries all the DNS servers in a specified timeout
5521 s
= mDNS_AddDNSServer(&mDNSStorage
, &d
, interface
, serviceID
, &saddr
, r
->port
? mDNSOpaque16fromIntVal(r
->port
) : UnicastDNSPort
, scope
,
5522 (n
== 0 ? (r
->timeout
? r
->timeout
: DEFAULT_UDNS_TIMEOUT
) : 0), cellIntf
, isExpensive
, isCLAT46
,
5523 resGroupID
, reqA
, reqAAAA
, mDNStrue
);
5526 LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope
), &s
->addr
, mDNSVal16(s
->port
), d
.c
);
5531 // ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
5532 // Service scope resolvers. This is indicated by the scope argument.
5534 // "resolver" has entries that should only be used for unscoped questions.
5536 // "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
5537 // interface index (q->InterfaceID)
5539 // "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
5540 // a service identifier (q->ServiceID)
5542 mDNSlocal
void ConfigResolvers(dns_config_t
*config
, mDNSu32 scope
, mDNSBool setsearch
, mDNSBool setservers
, MD5_CTX
*sdc
, mDNSu16 resGroupID
)
5545 dns_resolver_t
**resolver
;
5547 const char *scopeString
= DNSScopeToString(scope
);
5548 mDNSInterfaceID interface
;
5553 resolver
= config
->resolver
;
5554 nresolvers
= config
->n_resolver
;
5556 case kScopeInterfaceID
:
5557 resolver
= config
->scoped_resolver
;
5558 nresolvers
= config
->n_scoped_resolver
;
5560 case kScopeServiceID
:
5561 resolver
= config
->service_specific_resolver
;
5562 nresolvers
= config
->n_service_specific_resolver
;
5567 qsort(resolver
, nresolvers
, sizeof(dns_resolver_t
*), compare_dns_configs
);
5569 for (i
= 0; i
< nresolvers
; i
++)
5571 dns_resolver_t
*r
= resolver
[i
];
5573 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString
, i
, r
->domain
, r
->n_nameserver
);
5575 interface
= mDNSInterface_Any
;
5577 // Parse the interface index
5578 if (r
->if_index
!= 0)
5580 interface
= ConfigParseInterfaceID(r
->if_index
);
5585 ConfigSearchDomains(resolver
[i
], interface
, scope
, sdc
, config
->generation
);
5587 // Parse other scoped resolvers for search lists
5592 if (r
->port
== 5353 || r
->n_nameserver
== 0)
5594 ConfigNonUnicastResolver(r
);
5598 // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the
5599 // scoped resolver are not used by other non-scoped or scoped resolvers.
5600 if (scope
!= kScopeNone
)
5603 ConfigDNSServers(r
, interface
, scope
, resGroupID
);
5608 #if APPLE_OSX_mDNSResponder
5609 mDNSlocal mDNSBool
QuestionValidForDNSTrigger(DNSQuestion
*q
)
5611 if (QuerySuppressed(q
))
5613 debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
5616 if (mDNSOpaque16IsZero(q
->TargetQID
))
5618 debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
5621 // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
5623 if (q
->LOAddressAnswers
)
5625 debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
5632 // This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
5633 // We set our state appropriately so that if we start receiving answers, trigger the
5634 // upper layer to retry DNS questions.
5635 #if APPLE_OSX_mDNSResponder
5636 mDNSexport
void mDNSPlatformUpdateDNSStatus(DNSQuestion
*q
)
5638 mDNS
*const m
= &mDNSStorage
;
5639 if (!QuestionValidForDNSTrigger(q
))
5642 // Ignore applications that start and stop queries for no reason before we ever talk
5643 // to any DNS server.
5644 if (!q
->triedAllServersOnce
)
5646 LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q
->qname
.c
, DNSTypeName(q
->qtype
));
5649 if (q
->qtype
== kDNSType_A
)
5650 m
->p
->v4answers
= 0;
5651 if (q
->qtype
== kDNSType_AAAA
)
5652 m
->p
->v6answers
= 0;
5653 if (!m
->p
->v4answers
|| !m
->p
->v6answers
)
5655 LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, question %##s (%s)", m
->p
->v4answers
, m
->p
->v6answers
, q
->qname
.c
,
5656 DNSTypeName(q
->qtype
));
5661 mDNSlocal
void AckConfigd(dns_config_t
*config
)
5663 mDNS_CheckLock(&mDNSStorage
);
5665 // Acking the configuration triggers configd to reissue the reachability queries
5666 mDNSStorage
.p
->DNSTrigger
= NonZeroTime(mDNSStorage
.timenow
);
5667 _dns_configuration_ack(config
, "com.apple.mDNSResponder");
5670 // If v4q is non-NULL, it means we have received some answers for "A" type questions
5671 // If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
5672 #if APPLE_OSX_mDNSResponder
5673 mDNSexport
void mDNSPlatformTriggerDNSRetry(DNSQuestion
*v4q
, DNSQuestion
*v6q
)
5675 mDNS
*const m
= &mDNSStorage
;
5676 mDNSBool trigger
= mDNSfalse
;
5679 // Don't send triggers too often.
5680 // If we have started delivering answers to questions, we should send a trigger
5681 // if the time permits. If we are delivering answers, we should set the state
5682 // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know
5683 // whether the answers that are being delivered currently is for configd or some
5684 // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
5685 // then we won't deliver the trigger later when it is okay to send one as the
5686 // "answers" are already set to 1. Hence, don't affect the state of v4answers and
5687 // v6answers if we are not delivering triggers.
5689 timenow
= m
->timenow
;
5690 if (m
->p
->DNSTrigger
&& (timenow
- m
->p
->DNSTrigger
) < DNS_TRIGGER_INTERVAL
)
5692 if (!m
->p
->v4answers
|| !m
->p
->v6answers
)
5694 debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
5695 (timenow
- m
->p
->DNSTrigger
), m
->p
->v4answers
, m
->p
->v6answers
);
5701 if (v4q
!= NULL
&& QuestionValidForDNSTrigger(v4q
))
5703 int old
= m
->p
->v4answers
;
5705 m
->p
->v4answers
= 1;
5707 // If there are IPv4 answers now and previously we did not have
5708 // any answers, trigger a DNS change so that reachability
5709 // can retry the queries again.
5712 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow
- m
->p
->DNSTrigger
),
5713 v4q
->qname
.c
, DNSTypeName(v4q
->qtype
));
5717 if (v6q
!= NULL
&& QuestionValidForDNSTrigger(v6q
))
5719 int old
= m
->p
->v6answers
;
5721 m
->p
->v6answers
= 1;
5722 // If there are IPv6 answers now and previously we did not have
5723 // any answers, trigger a DNS change so that reachability
5724 // can retry the queries again.
5727 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow
- m
->p
->DNSTrigger
),
5728 v6q
->qname
.c
, DNSTypeName(v6q
->qtype
));
5734 dns_config_t
*config
= dns_configuration_copy();
5740 dns_configuration_free(config
);
5744 LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
5749 mDNSlocal
void SetupActiveDirectoryDomain(dns_config_t
*config
)
5751 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
5752 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
5753 if (config
->n_resolver
&& config
->resolver
[0]->domain
&& config
->resolver
[0]->n_nameserver
&&
5754 config
->resolver
[0]->nameserver
[0])
5756 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain
, config
->resolver
[0]->domain
);
5760 ActiveDirectoryPrimaryDomain
.c
[0] = 0;
5763 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
5764 ActiveDirectoryPrimaryDomainLabelCount
= CountLabels(&ActiveDirectoryPrimaryDomain
);
5765 if (config
->n_resolver
&& config
->resolver
[0]->n_nameserver
&&
5766 SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain
, ActiveDirectoryPrimaryDomainLabelCount
- 1), &localdomain
))
5768 SetupAddr(&ActiveDirectoryPrimaryDomainServer
, config
->resolver
[0]->nameserver
[0]);
5772 AssignDomainName(&ActiveDirectoryPrimaryDomain
, (const domainname
*)"");
5773 ActiveDirectoryPrimaryDomainLabelCount
= 0;
5774 ActiveDirectoryPrimaryDomainServer
= zeroAddr
;
5779 mDNSlocal
void SetupDDNSDomains(domainname
*const fqdn
, DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
)
5782 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NULL
5785 CFDictionaryRef ddnsdict
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_DynamicDNS
);
5790 CFArrayRef fqdnArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("HostNames"));
5791 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
5793 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
5794 CFDictionaryRef fqdnDict
= CFArrayGetValueAtIndex(fqdnArray
, 0);
5795 if (fqdnDict
&& DictionaryIsEnabled(fqdnDict
))
5797 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
5800 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5801 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
5802 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
5804 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
5811 CFArrayRef regArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("RegistrationDomains"));
5812 if (regArray
&& CFArrayGetCount(regArray
) > 0)
5814 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
5815 if (regDict
&& DictionaryIsEnabled(regDict
))
5817 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
5820 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5821 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
5822 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
5825 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf
);
5826 AppendDNameListElem(&RegDomains
, 0, &d
);
5834 CFArrayRef browseArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("BrowseDomains"));
5837 for (i
= 0; i
< CFArrayGetCount(browseArray
); i
++)
5839 CFDictionaryRef browseDict
= CFArrayGetValueAtIndex(browseArray
, i
);
5840 if (browseDict
&& DictionaryIsEnabled(browseDict
))
5842 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
5845 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5846 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
5847 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf
[0] ? buf
: "(unknown)");
5850 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf
);
5851 AppendDNameListElem(&BrowseDomains
, 0, &d
);
5858 CFRelease(ddnsdict
);
5860 #if MDNSRESPONDER_BTMM_SUPPORT
5863 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_BackToMyMac
);
5866 CFIndex size
= CFDictionaryGetCount(btmm
);
5867 const void *key
[size
];
5868 const void *val
[size
];
5869 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
5870 for (i
= 0; i
< size
; i
++)
5872 LogInfo("BackToMyMac %d", i
);
5873 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5874 LogMsg("Can't read BackToMyMac %d key %s", i
, buf
);
5877 mDNSu32 uid
= atoi(buf
);
5878 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5879 LogMsg("Can't read BackToMyMac %d val %s", i
, buf
);
5880 else if (MakeDomainNameFromDNSNameString(&d
, buf
) && d
.c
[0])
5882 LogInfo("BackToMyMac %d %d %##s", i
, uid
, d
.c
);
5883 AppendDNameListElem(&RegDomains
, uid
, &d
);
5893 // Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
5894 mDNSexport mDNSBool
mDNSPlatformSetDNSConfig(mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
,
5895 DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
, mDNSBool ackConfig
)
5897 mDNS
*const m
= &mDNSStorage
;
5898 MD5_CTX sdc
; // search domain context
5899 static mDNSu16 resolverGroupID
= 0;
5901 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
5902 if (fqdn
) fqdn
->c
[0] = 0;
5903 if (RegDomains
) *RegDomains
= NULL
;
5904 if (BrowseDomains
) *BrowseDomains
= NULL
;
5906 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
5907 setservers
? " setservers" : "",
5908 setsearch
? " setsearch" : "",
5909 fqdn
? " fqdn" : "",
5910 RegDomains
? " RegDomains" : "",
5911 BrowseDomains
? " BrowseDomains" : "");
5913 if (setsearch
) MD5_Init(&sdc
);
5915 // Add the inferred address-based configuration discovery domains
5916 // (should really be in core code I think, not platform-specific)
5919 struct ifaddrs
*ifa
= mDNSNULL
;
5920 struct sockaddr_in saddr
;
5921 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
5922 saddr
.sin_len
= sizeof(saddr
);
5923 saddr
.sin_family
= AF_INET
;
5925 saddr
.sin_addr
.s_addr
= *(in_addr_t
*)&m
->Router
.ip
.v4
;
5927 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
5928 if (!AddrRequiresPPPConnection((struct sockaddr
*)&saddr
)) ifa
= myGetIfAddrs(1);
5935 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
5937 !(ifa
->ifa_flags
& IFF_LOOPBACK
) &&
5938 !SetupAddr(&a
, ifa
->ifa_addr
) &&
5939 !mDNSv4AddressIsLinkLocal(&a
.ip
.v4
) )
5941 // 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
5942 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5943 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
; // Make sure ifa_netmask->sa_family is set correctly
5944 SetupAddr(&n
, ifa
->ifa_netmask
);
5945 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
5946 mDNS_snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d.in-addr.arpa.", a
.ip
.v4
.b
[3] & n
.ip
.v4
.b
[3],
5947 a
.ip
.v4
.b
[2] & n
.ip
.v4
.b
[2],
5948 a
.ip
.v4
.b
[1] & n
.ip
.v4
.b
[1],
5949 a
.ip
.v4
.b
[0] & n
.ip
.v4
.b
[0]);
5950 UpdateSearchDomainHash(&sdc
, buf
, NULL
);
5951 mDNS_AddSearchDomain_CString(buf
, mDNSNULL
);
5953 ifa
= ifa
->ifa_next
;
5957 #ifndef MDNS_NO_DNSINFO
5958 if (setservers
|| setsearch
)
5960 dns_config_t
*config
= dns_configuration_copy();
5963 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
5964 // Apparently this is expected behaviour -- "not a bug".
5965 // Accordingly, we suppress syslog messages for the first three minutes after boot.
5966 // If we are still getting failures after three minutes, then we log them.
5967 if ((mDNSu32
)mDNSPlatformRawTime() > (mDNSu32
)(mDNSPlatformOneSecond
* 180))
5968 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
5972 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config
->n_resolver
, config
->generation
, m
->p
->LastConfigGeneration
);
5974 // For every network change, mDNSPlatformSetDNSConfig is called twice. First,
5975 // to update the search domain list (in which case, the setsearch bool is set);
5976 // and second, to update the DNS server list (in which case, the setservers bool
5977 // is set). The code assumes only one of these flags, setsearch or setserver,
5978 // will be set when mDNSPlatformSetDNSConfig is called to handle a network change.
5979 // The mDNSPlatformSetDNSConfig function also assumes that ackCfg will be set
5980 // when setservers is set.
5982 // The search domains update occurs on every network change to avoid sync issues
5983 // that may occur if a network change happens during the processing
5984 // of a network change. The dns servers update occurs when the DNS config
5985 // changes. The dns servers stay in sync by saving the config's generation number
5986 // on every update; and only updating when the generation number changes.
5988 // If this is a DNS server update and the configuration hasn't changed, then skip update
5989 if (setservers
&& m
->p
->LastConfigGeneration
== config
->generation
)
5991 LogInfo("mDNSPlatformSetDNSConfig(setservers): generation number %llu same, not processing", config
->generation
);
5992 dns_configuration_free(config
);
5993 SetupDDNSDomains(fqdn
, RegDomains
, BrowseDomains
);
5996 #if APPLE_OSX_mDNSResponder
5997 SetupActiveDirectoryDomain(config
);
6000 // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry
6001 // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need
6002 // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between
6003 // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the
6004 // same resolverGroupID.
6006 // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally.
6007 ConfigResolvers(config
, kScopeNone
, setsearch
, setservers
, &sdc
, ++resolverGroupID
);
6008 resolverGroupID
+= config
->n_resolver
;
6010 ConfigResolvers(config
, kScopeInterfaceID
, setsearch
, setservers
, &sdc
, resolverGroupID
);
6011 resolverGroupID
+= config
->n_scoped_resolver
;
6013 ConfigResolvers(config
, kScopeServiceID
, setsearch
, setservers
, &sdc
, resolverGroupID
);
6015 // Acking provides a hint to other processes that the current DNS configuration has completed
6016 // its update. When configd receives the ack, it publishes a notification.
6017 // Applications monitoring the notification then know when to re-issue their DNS queries
6018 // after a network change occurs.
6021 // Note: We have to set the generation number here when we are acking.
6022 // For every DNS configuration change, we do the following:
6024 // 1) Copy dns configuration, handle search domains change
6025 // 2) Copy dns configuration, handle dns server change
6027 // If we update the generation number at step (1), we won't process the
6028 // DNS servers the second time because generation number would be the same.
6029 // As we ack only when we process dns servers, we set the generation number
6031 m
->p
->LastConfigGeneration
= config
->generation
;
6032 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers
, setsearch
);
6035 dns_configuration_free(config
);
6036 if (setsearch
) FinalizeSearchDomainHash(&sdc
);
6039 #endif // MDNS_NO_DNSINFO
6040 SetupDDNSDomains(fqdn
, RegDomains
, BrowseDomains
);
6045 mDNSexport mStatus
mDNSPlatformGetPrimaryInterface(mDNSAddr
*v4
, mDNSAddr
*v6
, mDNSAddr
*r
)
6049 CFDictionaryRef dict
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_IPv4
);
6052 r
->type
= mDNSAddrType_IPv4
;
6053 r
->ip
.v4
= zerov4Addr
;
6054 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
6057 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
6058 LogMsg("Could not convert router to CString");
6061 struct sockaddr_in saddr
;
6062 saddr
.sin_len
= sizeof(saddr
);
6063 saddr
.sin_family
= AF_INET
;
6065 inet_aton(buf
, &saddr
.sin_addr
);
6066 *(in_addr_t
*)&r
->ip
.v4
= saddr
.sin_addr
.s_addr
;
6069 string
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
6072 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
6073 struct ifaddrs
*ifa
= myGetIfAddrs(1);
6074 *v4
= *v6
= zeroAddr
;
6076 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
6078 LogMsg("Could not convert router to CString");
6081 // find primary interface in list
6082 while (ifa
&& (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
) || !HavePrimaryGlobalv6
))
6086 LogMsg("Skip interface, %s, since ifa_addr is not set.", (ifa
->ifa_name
) ? ifa
->ifa_name
: "name not found");
6087 ifa
= ifa
->ifa_next
;
6090 mDNSAddr tmp6
= zeroAddr
;
6091 if (!strcmp(buf
, ifa
->ifa_name
))
6093 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
6095 if (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
))
6096 SetupAddr(v4
, ifa
->ifa_addr
);
6098 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
6100 SetupAddr(&tmp6
, ifa
->ifa_addr
);
6101 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
6103 HavePrimaryGlobalv6
= mDNStrue
;
6110 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
6111 if (!HavePrimaryGlobalv6
&& ifa
->ifa_addr
->sa_family
== AF_INET6
&& !v6
->ip
.v6
.b
[0])
6113 SetupAddr(&tmp6
, ifa
->ifa_addr
);
6114 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1)
6118 ifa
= ifa
->ifa_next
;
6120 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
6121 // V4 to communicate w/ our DNS server
6127 return mStatus_NoError
;
6130 mDNSexport
void mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
6132 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status
, dname
->c
);
6133 char uname
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
6134 ConvertDomainNameToCString(dname
, uname
);
6140 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
6144 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
6145 // That single entity is a CFDictionary with name "HostNames".
6146 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
6147 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
6148 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
6149 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
6150 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
6152 const CFStringRef StateKeys
[1] = { CFSTR("HostNames") };
6153 const CFStringRef HostKeys
[1] = { CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
) };
6154 const CFStringRef StatusKeys
[1] = { CFSTR("Status") };
6155 if (!HostKeys
[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname
);
6158 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
6159 if (!StatusVals
[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status
);
6162 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
6165 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
6168 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
6171 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig
, mDNSNULL
, StateDict
);
6172 CFRelease(StateDict
);
6174 CFRelease(StateVals
[0]);
6176 CFRelease(HostVals
[0]);
6178 CFRelease(StatusVals
[0]);
6180 CFRelease(HostKeys
[0]);
6184 #if MDNSRESPONDER_BTMM_SUPPORT
6187 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
6188 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
6190 mDNSlocal mDNSBool
IsBTMMDomain(domainname
*d
)
6192 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:IsBTMMDomain"), NULL
, NULL
);
6195 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6198 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BackToMyMac
);
6201 CFIndex size
= CFDictionaryGetCount(btmm
);
6202 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
6203 const void *key
[size
];
6204 const void *val
[size
];
6207 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
6208 for (i
= 0; i
< size
; i
++)
6210 LogInfo("BackToMyMac %d", i
);
6211 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
6212 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i
, buf
);
6215 mDNSu32 uid
= atoi(buf
);
6216 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
6217 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i
, buf
);
6218 else if (MakeDomainNameFromDNSNameString(&dom
, buf
) && dom
.c
[0])
6220 if (SameDomainName(&dom
, d
))
6222 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d
->c
, uid
);
6233 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d
->c
);
6237 // Appends data to the buffer
6238 mDNSlocal
int AddOneItem(char *buf
, int bufsz
, char *data
, int *currlen
)
6242 len
= strlcpy(buf
+ *currlen
, data
, bufsz
- *currlen
);
6243 if (len
>= (bufsz
- *currlen
))
6245 // if we have exceeded the space in buf, it has already been NULL terminated
6246 // and we have nothing more to do. Set currlen to the last byte so that the caller
6247 // knows to do the right thing
6248 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen
, len
);
6249 *currlen
= bufsz
- 1;
6252 else { (*currlen
) += len
; }
6254 buf
[*currlen
] = ',';
6255 if (*currlen
>= bufsz
)
6257 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen
);
6258 *currlen
= bufsz
- 1;
6262 // if we have filled up the buffer exactly, then there is no more work to do
6263 if (*currlen
== bufsz
- 1) { buf
[*currlen
] = 0; return -1; }
6268 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
6269 // BTMM domains, then bring down the connection to the relay.
6270 mDNSlocal
void UpdateBTMMRelayConnection(mDNS
*const m
)
6272 DomainAuthInfo
*BTMMDomain
= mDNSNULL
;
6273 DomainAuthInfo
*FoundInList
;
6274 static mDNSBool AWACSDConnected
= mDNSfalse
;
6275 char AllUsers
[1024]; // maximum size of mach message
6276 char AllPass
[1024]; // maximum size of mach message
6277 char username
[MAX_DOMAIN_LABEL
+ 1];
6281 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
6282 // we may not be able to send the dns queries over the relay connection which may be needed
6283 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
6284 // need to make sure that we send the disconnect before attempting the next connect as the
6285 // awacs connections are redirected based on usernames.
6287 // For now we send a disconnect immediately. When we start sending dns queries over the relay
6288 // connection, we will need to fix this.
6290 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
6291 if (!FoundInList
->deltime
&& FoundInList
->AutoTunnel
&& IsBTMMDomain(&FoundInList
->domain
))
6293 // We need the passwd from the first domain.
6294 BTMMDomain
= FoundInList
;
6295 ConvertDomainLabelToCString_unescaped((domainlabel
*)BTMMDomain
->domain
.c
, username
);
6296 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username
, BTMMDomain
->domain
.c
);
6297 if (AddOneItem(AllUsers
, sizeof(AllUsers
), username
, &currulen
) == -1) break;
6298 if (AddOneItem(AllPass
, sizeof(AllPass
), BTMMDomain
->b64keydata
, &currplen
) == -1) break;
6303 // In the normal case (where we neither exceed the buffer size nor write bytes that
6304 // fit exactly into the buffer), currulen/currplen should be a different size than
6305 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
6307 if (currulen
!= (int)(sizeof(AllUsers
) - 1)) AllUsers
[currulen
- 1] = 0;
6308 if (currplen
!= (int)(sizeof(AllPass
) - 1)) AllPass
[currplen
- 1] = 0;
6310 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers
);
6311 AWACS_Connect(AllUsers
, AllPass
, "hello.connectivity.me.com");
6312 AWACSDConnected
= mDNStrue
;
6316 // Disconnect only if we connected previously
6317 if (AWACSDConnected
)
6319 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
6321 AWACSDConnected
= mDNSfalse
;
6323 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
6327 mDNSlocal
void UpdateBTMMRelayConnection(mDNS
*const m
)
6330 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
6332 #endif // ! NO_AWACS
6334 mDNSlocal
void ProcessConndConfigChanges(void);
6336 #endif // MDNSRESPONDER_BTMM_SUPPORT
6338 // MUST be called holding the lock
6339 mDNSlocal
void SetDomainSecrets_internal(mDNS
*m
)
6341 #ifdef NO_SECURITYFRAMEWORK
6343 LogMsg("Note: SetDomainSecrets: no keychain support");
6345 mDNSBool haveAutoTunnels
= mDNSfalse
;
6347 LogInfo("SetDomainSecrets");
6349 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
6350 // In the case where the user simultaneously removes their DDNS host name and the key
6351 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
6352 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
6353 // address records behind that we no longer have permission to delete.
6354 DomainAuthInfo
*ptr
;
6355 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
6356 ptr
->deltime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
*10);
6358 #if APPLE_OSX_mDNSResponder
6360 // Mark all TunnelClients for deletion
6361 ClientTunnel
*client
;
6362 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
6364 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client
->dstname
.c
);
6365 client
->MarkedForDeletion
= mDNStrue
;
6368 #endif // APPLE_OSX_mDNSResponder
6370 // String Array used to write list of private domains to Dynamic Store
6371 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6372 if (!sa
) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
6374 CFDataRef data
= NULL
;
6375 const int itemsPerEntry
= 4; // domain name, key name, key value, Name value
6376 CFArrayRef secrets
= NULL
;
6377 int err
= mDNSKeychainGetSecrets(&secrets
);
6378 if (err
|| !secrets
)
6379 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err
, secrets
);
6382 CFIndex ArrayCount
= CFArrayGetCount(secrets
);
6383 // Iterate through the secrets
6384 for (i
= 0; i
< ArrayCount
; ++i
)
6386 mDNSBool AutoTunnel
;
6388 CFArrayRef entry
= CFArrayGetValueAtIndex(secrets
, i
);
6389 if (CFArrayGetTypeID() != CFGetTypeID(entry
) || itemsPerEntry
!= CFArrayGetCount(entry
))
6390 { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i
, itemsPerEntry
); continue; }
6391 for (j
= 0; j
< CFArrayGetCount(entry
); ++j
)
6392 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry
, j
)))
6393 { LogMsg("SetDomainSecrets: malformed entry item %d", j
); continue; }
6395 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
6397 // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
6398 // Get DNS domain this key is for (kmDNSKcWhere)
6399 char stringbuf
[MAX_ESCAPED_DOMAIN_NAME
+ sizeof(btmmprefix
)];
6400 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcWhere
);
6401 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
6402 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data
)); continue; }
6403 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
6404 stringbuf
[CFDataGetLength(data
)] = '\0';
6406 AutoTunnel
= mDNSfalse
;
6408 if (!strncmp(stringbuf
, dnsprefix
, strlen(dnsprefix
)))
6409 offset
= strlen(dnsprefix
);
6410 #if MDNSRESPONDER_BTMM_SUPPORT
6411 else if (!strncmp(stringbuf
, btmmprefix
, strlen(btmmprefix
)))
6413 AutoTunnel
= mDNStrue
;
6414 offset
= strlen(btmmprefix
);
6418 if (!MakeDomainNameFromDNSNameString(&domain
, stringbuf
+ offset
)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf
); continue; }
6420 // Get key name (kmDNSKcAccount)
6421 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcAccount
);
6422 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
6423 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data
)); continue; }
6424 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)stringbuf
);
6425 stringbuf
[CFDataGetLength(data
)] = '\0';
6428 if (!MakeDomainNameFromDNSNameString(&keyname
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf
); continue; }
6430 // Get key data (kmDNSKcKey)
6431 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcKey
);
6432 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
6434 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data
));
6437 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
6438 stringbuf
[CFDataGetLength(data
)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
6440 // Get the Name of the keychain entry (kmDNSKcName) host or host:port
6441 // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
6442 char hostbuf
[MAX_ESCAPED_DOMAIN_NAME
+ 6]; // Max legal domainname as C-string, including terminating NUL
6443 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcName
);
6444 if (CFDataGetLength(data
) >= (int)sizeof(hostbuf
))
6446 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data
));
6449 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)hostbuf
);
6450 hostbuf
[CFDataGetLength(data
)] = '\0';
6452 domainname hostname
;
6455 hptr
= strchr(hostbuf
, ':');
6457 port
.NotAnInteger
= 0;
6464 while(hptr
&& *hptr
!= 0)
6466 if (*hptr
< '0' || *hptr
> '9')
6467 { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr
, val
); val
= 0; break;}
6468 val
= val
* 10 + *hptr
- '0';
6473 port
.NotAnInteger
= p
[0] << 8 | p
[1];
6475 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
6476 hptr
= strchr(hostbuf
, '@');
6481 if (!MakeDomainNameFromDNSNameString(&hostname
, hptr
)) { LogMsg("SetDomainSecrets: bad host name %s", hptr
); continue; }
6483 DomainAuthInfo
*FoundInList
;
6484 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
6485 if (SameDomainName(&FoundInList
->domain
, &domain
)) break;
6487 #if APPLE_OSX_mDNSResponder
6490 // If any client tunnel destination is in this domain, set deletion flag to false
6491 ClientTunnel
*client
;
6492 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
6493 if (FoundInList
== GetAuthInfoForName_internal(m
, &client
->dstname
))
6495 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client
->dstname
.c
);
6496 client
->MarkedForDeletion
= mDNSfalse
;
6500 #endif // APPLE_OSX_mDNSResponder
6502 // Uncomment the line below to view the keys as they're read out of the system keychain
6503 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
6504 //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]));
6505 LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain
.c
, &keyname
.c
, hostname
.c
, (port
.b
[0] << 8 | port
.b
[1]));
6507 // If didn't find desired domain in the list, make a new entry
6509 if (FoundInList
&& FoundInList
->AutoTunnel
&& haveAutoTunnels
== mDNSfalse
) haveAutoTunnels
= mDNStrue
;
6512 ptr
= (DomainAuthInfo
*)mallocL("DomainAuthInfo", sizeof(*ptr
));
6513 if (!ptr
) { LogMsg("SetDomainSecrets: No memory"); continue; }
6516 //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
6518 // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
6519 if (mDNS_SetSecretForDomain(m
, ptr
, &domain
, &keyname
, stringbuf
, &hostname
, &port
, AutoTunnel
) == mStatus_BadParamErr
)
6521 if (!FoundInList
) mDNSPlatformMemFree(ptr
); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
6525 ConvertDomainNameToCString(&domain
, stringbuf
);
6526 CFStringRef cfs
= CFStringCreateWithCString(NULL
, stringbuf
, kCFStringEncodingUTF8
);
6527 if (cfs
) { CFArrayAppendValue(sa
, cfs
); CFRelease(cfs
); }
6532 if (!privateDnsArray
|| !CFEqual(privateDnsArray
, sa
))
6534 if (privateDnsArray
)
6535 CFRelease(privateDnsArray
);
6537 privateDnsArray
= sa
;
6538 CFRetain(privateDnsArray
);
6539 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, mDNSNULL
, privateDnsArray
);
6543 #if APPLE_OSX_mDNSResponder
6545 // clean up ClientTunnels
6546 ClientTunnel
**pp
= &m
->TunnelClients
;
6549 if ((*pp
)->MarkedForDeletion
)
6551 ClientTunnel
*cur
= *pp
;
6552 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur
, cur
->dstname
.c
);
6553 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
6554 AutoTunnelSetKeys(cur
, mDNSfalse
);
6556 freeL("ClientTunnel", cur
);
6562 mDNSBool needAutoTunnelNAT
= mDNSfalse
;
6563 DomainAuthInfo
*info
;
6564 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
6566 if (info
->AutoTunnel
)
6568 UpdateAutoTunnelDeviceInfoRecord(m
, info
);
6569 UpdateAutoTunnelHostRecord(m
, info
);
6570 UpdateAutoTunnelServiceRecords(m
, info
);
6571 UpdateAutoTunnel6Record(m
, info
);
6574 if (info
->AutoTunnelServiceStarted
) info
->AutoTunnelServiceStarted
= mDNSfalse
;
6576 else if (info
->AutoTunnelServiceStarted
)
6577 needAutoTunnelNAT
= true;
6579 UpdateAutoTunnelDomainStatus(info
);
6583 // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
6584 if (!needAutoTunnelNAT
&& m
->AutoTunnelNAT
.clientContext
)
6586 // stop the NAT operation, reset port, cleanup state
6587 mDNS_StopNATOperation_internal(m
, &m
->AutoTunnelNAT
);
6588 m
->AutoTunnelNAT
.ExternalAddress
= zerov4Addr
;
6589 m
->AutoTunnelNAT
.NewAddress
= zerov4Addr
;
6590 m
->AutoTunnelNAT
.ExternalPort
= zeroIPPort
;
6591 m
->AutoTunnelNAT
.RequestedPort
= zeroIPPort
;
6592 m
->AutoTunnelNAT
.Lifetime
= 0;
6593 m
->AutoTunnelNAT
.Result
= mStatus_NoError
;
6594 m
->AutoTunnelNAT
.clientContext
= mDNSNULL
;
6597 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
6598 #if MDNSRESPONDER_BTMM_SUPPORT
6599 ProcessConndConfigChanges(); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
6602 #endif // APPLE_OSX_mDNSResponder
6604 CheckSuppressUnusableQuestions(m
);
6606 #endif /* NO_SECURITYFRAMEWORK */
6609 mDNSexport
void SetDomainSecrets(mDNS
*m
)
6612 // Don't get secrets for BTMM if running in debug mode
6613 if (!IsDebugSocketInUse())
6615 SetDomainSecrets_internal(m
);
6618 mDNSlocal
void SetLocalDomains(void)
6620 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6621 if (!sa
) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
6623 CFArrayAppendValue(sa
, CFSTR("local"));
6624 CFArrayAppendValue(sa
, CFSTR("254.169.in-addr.arpa"));
6625 CFArrayAppendValue(sa
, CFSTR("8.e.f.ip6.arpa"));
6626 CFArrayAppendValue(sa
, CFSTR("9.e.f.ip6.arpa"));
6627 CFArrayAppendValue(sa
, CFSTR("a.e.f.ip6.arpa"));
6628 CFArrayAppendValue(sa
, CFSTR("b.e.f.ip6.arpa"));
6630 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig
, mDNSNULL
, sa
);
6634 mDNSlocal
void GetCurrentPMSetting(const CFStringRef name
, mDNSs32
*val
)
6637 CFDictionaryRef dict
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_PowerSettings
);
6640 LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
6644 CFNumberRef number
= CFDictionaryGetValue(dict
, name
);
6645 if (!number
|| CFGetTypeID(number
) != CFNumberGetTypeID() || !CFNumberGetValue(number
, kCFNumberSInt32Type
, val
))
6652 #if APPLE_OSX_mDNSResponder
6654 static CFMutableDictionaryRef spsStatusDict
= NULL
;
6655 static const CFStringRef kMetricRef
= CFSTR("Metric");
6657 mDNSlocal
void SPSStatusPutNumber(CFMutableDictionaryRef dict
, const mDNSu8
* const ptr
, CFStringRef key
)
6659 mDNSu8 tmp
= (ptr
[0] - '0') * 10 + ptr
[1] - '0';
6660 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt8Type
, &tmp
);
6662 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
6665 CFDictionarySetValue(dict
, key
, num
);
6670 mDNSlocal CFMutableDictionaryRef
SPSCreateDict(const mDNSu8
* const ptr
)
6672 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
6673 if (!dict
) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict
; }
6676 buffer
[mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", ptr
) - 1] = 0;
6677 CFStringRef spsname
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
6678 if (!spsname
) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict
); return NULL
; }
6679 CFDictionarySetValue(dict
, CFSTR("FullName"), spsname
);
6682 if (ptr
[0] >= 2) SPSStatusPutNumber(dict
, ptr
+ 1, CFSTR("Type"));
6683 if (ptr
[0] >= 5) SPSStatusPutNumber(dict
, ptr
+ 4, CFSTR("Portability"));
6684 if (ptr
[0] >= 8) SPSStatusPutNumber(dict
, ptr
+ 7, CFSTR("MarginalPower"));
6685 if (ptr
[0] >= 11) SPSStatusPutNumber(dict
, ptr
+10, CFSTR("TotalPower"));
6687 mDNSu32 tmp
= SPSMetric(ptr
);
6688 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tmp
);
6690 LogMsg("SPSCreateDict: Could not create CFNumber");
6693 CFDictionarySetValue(dict
, kMetricRef
, num
);
6699 memcpy(buffer
, ptr
+ 13, ptr
[0] - 12);
6700 buffer
[ptr
[0] - 12] = 0;
6701 spsname
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
6702 if (!spsname
) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict
); return NULL
; }
6705 CFDictionarySetValue(dict
, CFSTR("PrettyName"), spsname
);
6713 mDNSlocal CFComparisonResult
CompareSPSEntries(const void *val1
, const void *val2
, void *context
)
6716 return CFNumberCompare((CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val1
, kMetricRef
),
6717 (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val2
, kMetricRef
),
6721 mDNSlocal
void UpdateSPSStatus(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
6723 NetworkInterfaceInfo
* info
= (NetworkInterfaceInfo
*)question
->QuestionContext
;
6724 debugf("UpdateSPSStatus: %s %##s %s %s", info
->ifname
, question
->qname
.c
, AddRecord
? "Add" : "Rmv", answer
? RRDisplayString(m
, answer
) : "<null>");
6727 mDNS_UpdateAllowSleep(m
);
6730 if (answer
&& SPSMetric(answer
->rdata
->u
.name
.c
) > 999999) return; // Ignore instances with invalid names
6734 spsStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
6735 if (!spsStatusDict
) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
6738 CFStringRef ifname
= CFStringCreateWithCString(NULL
, info
->ifname
, kCFStringEncodingUTF8
);
6739 if (!ifname
) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
6741 CFMutableArrayRef array
= NULL
;
6743 if (!CFDictionaryGetValueIfPresent(spsStatusDict
, ifname
, (const void**) &array
))
6745 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6746 if (!array
) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname
); return; }
6747 CFDictionarySetValue(spsStatusDict
, ifname
, array
);
6748 CFRelease(array
); // let go of our reference, now that the dict has one
6751 if (!array
) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info
->ifname
); CFRelease(ifname
); return; }
6753 if (!answer
) // special call that means the question has been stopped (because the interface is going away)
6754 CFArrayRemoveAllValues(array
);
6757 CFMutableDictionaryRef dict
= SPSCreateDict(answer
->rdata
->u
.name
.c
);
6758 if (!dict
) { CFRelease(ifname
); return; }
6762 if (!CFArrayContainsValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), dict
))
6765 for (i
=0; i
<CFArrayGetCount(array
); i
++)
6766 if (CompareSPSEntries(CFArrayGetValueAtIndex(array
, i
), dict
, NULL
) != kCFCompareLessThan
)
6768 CFArrayInsertValueAtIndex(array
, i
, dict
);
6770 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info
->ifname
, answer
->rdata
->u
.name
.c
);
6774 CFIndex i
= CFArrayGetFirstIndexOfValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), dict
);
6775 if (i
!= -1) CFArrayRemoveValueAtIndex(array
, i
);
6776 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info
->ifname
, answer
->rdata
->u
.name
.c
);
6782 if (!m
->ShutdownTime
) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState
, info
->ifname
, array
);
6787 mDNSlocal mDNSs32
GetSystemSleepTimerSetting(void)
6790 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL
, NULL
);
6792 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6795 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_PowerSettings
);
6798 CFNumberRef number
= CFDictionaryGetValue(dict
, CFSTR("System Sleep Timer"));
6799 if (number
) CFNumberGetValue(number
, kCFNumberSInt32Type
, &val
);
6807 mDNSlocal
void SetSPS(mDNS
*const m
)
6810 // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
6811 mDNSu8 sps
= (OfferSleepProxyService
&& GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware
: 0;
6813 // For devices that are not running NAT, but are set to never sleep, we may choose to act
6814 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
6815 //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
6817 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
6819 // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
6820 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
6821 // We rate such a device as metric 70 ("Incidentally Available Hardware")
6822 if (SPMetricMarginalPower
<= 60 && !sps
) sps
= mDNSSleepProxyMetric_IncidentalHardware
;
6824 // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
6825 // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
6826 if (sps
&& OfferSleepProxyService
&& OfferSleepProxyService
< 100) sps
= OfferSleepProxyService
;
6828 #ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI
6829 // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active.
6832 NetworkInterfaceInfo
*intf
= mDNSNULL
;
6833 mDNSEthAddr bssid
= zeroEthAddr
;
6834 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
6836 if (intf
->InterfaceID
== AWDLInterfaceID
) continue;
6837 bssid
= GetBSSID(intf
->ifname
);
6838 if (!mDNSSameEthAddress(&bssid
, &zeroEthAddr
))
6840 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
6846 #endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI
6848 mDNSCoreBeSleepProxyServer(m
, sps
, SPMetricPortability
, SPMetricMarginalPower
, SPMetricTotalPower
, SPMetricFeatures
);
6851 // The definitions below should eventually come from some externally-supplied header file.
6852 // However, since these definitions can't really be changed without breaking binary compatibility,
6853 // they should never change, so in practice it should not be a big problem to have them defined here.
6856 { // commands from the daemon to the driver
6857 cmd_mDNSOffloadRR
= 21, // give the mdns update buffer to the driver
6860 typedef union { void *ptr
; mDNSOpaque64 sixtyfourbits
; } FatPtr
;
6863 { // cmd_mDNSOffloadRR structure
6864 uint32_t command
; // set to OffloadRR
6865 uint32_t rrBufferSize
; // number of bytes of RR records
6866 uint32_t numUDPPorts
; // number of SRV UDP ports
6867 uint32_t numTCPPorts
; // number of SRV TCP ports
6868 uint32_t numRRRecords
; // number of RR records
6869 uint32_t compression
; // rrRecords - compression is base for compressed strings
6870 FatPtr rrRecords
; // address of array of pointers to the rr records
6871 FatPtr udpPorts
; // address of udp port list (SRV)
6872 FatPtr tcpPorts
; // address of tcp port list (SRV)
6875 #include <IOKit/IOKitLib.h>
6876 #include <dns_util.h>
6878 mDNSlocal mDNSu16
GetPortArray(int trans
, mDNSIPPort
*portarray
, mDNSBool TCPKAOnly
, mDNSBool supportsTCPKA
)
6880 mDNS
*const m
= &mDNSStorage
;
6881 const domainlabel
*const tp
= (trans
== mDNSTransport_UDP
) ? (const domainlabel
*)"\x4_udp" : (const domainlabel
*)"\x4_tcp";
6885 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6887 mDNSBool isKeepAliveRecord
= mDNS_KeepaliveRecord(&rr
->resrec
);
6888 // Skip over all other records if we are registering TCP KeepAlive records only
6889 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
6890 // supportsTCPKA is set to true if both policy and interface allow TCP Keepalive
6891 if ((TCPKAOnly
&& !isKeepAliveRecord
) || (isKeepAliveRecord
&& !supportsTCPKA
)) {
6895 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainLabel(ThirdLabel(rr
->resrec
.name
)->c
, tp
->c
))
6902 for (i
= 0; i
< count
; i
++)
6903 if (mDNSSameIPPort(portarray
[i
], rr
->resrec
.rdata
->u
.srv
.port
))
6906 // Add it into the port list only if it not already present in the list
6908 portarray
[count
++] = rr
->resrec
.rdata
->u
.srv
.port
;
6913 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
6914 if (trans
== mDNSTransport_UDP
&& m
->AutoTunnelNAT
.clientContext
)
6916 LogSPS("GetPortArray Back to My Mac at %d", count
);
6917 if (portarray
) portarray
[count
] = IPSECPort
;
6923 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6924 mDNSlocal mDNSBool
SupportsTCPKeepAlive()
6926 IOReturn ret
= kIOReturnSuccess
;
6927 CFTypeRef obj
= NULL
;
6928 mDNSBool supports
= mDNSfalse
;
6930 ret
= IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj
);
6931 if ((kIOReturnSuccess
== ret
) && (obj
!= NULL
))
6933 supports
= (obj
== kCFBooleanTrue
)? mDNStrue
: mDNSfalse
;
6936 LogSPS("%s: The hardware %s TCP Keep Alive", __func__
, (supports
? "supports" : "does not support"));
6940 mDNSlocal mDNSBool
OnBattery(void)
6942 CFTypeRef powerInfo
= IOPSCopyPowerSourcesInfo();
6943 CFTypeRef powerSrc
= IOPSGetProvidingPowerSourceType(powerInfo
);
6944 mDNSBool result
= mDNSfalse
;
6946 if (powerInfo
!= NULL
)
6948 result
= CFEqual(CFSTR(kIOPSBatteryPowerValue
), powerSrc
);
6949 CFRelease(powerInfo
);
6951 LogSPS("%s: The system is on %s", __func__
, (result
)? "Battery" : "AC Power");
6955 #endif // !TARGET_OS_EMBEDDED
6957 #define TfrRecordToNIC(RR) \
6958 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
6960 mDNSlocal mDNSu32
CountProxyRecords(uint32_t *const numbytes
, NetworkInterfaceInfo
*const intf
, mDNSBool TCPKAOnly
, mDNSBool supportsTCPKA
)
6962 mDNS
*const m
= &mDNSStorage
;
6968 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6970 if (!(rr
->AuthFlags
& AuthFlagsWakeOnly
) && rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
6972 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
6973 mDNSBool isKeepAliveRecord
= mDNS_KeepaliveRecord(&rr
->resrec
);
6974 // Skip over all other records if we are registering TCP KeepAlive records only
6975 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
6976 if ((TCPKAOnly
&& !isKeepAliveRecord
) || (isKeepAliveRecord
&& !supportsTCPKA
))
6979 // Update the record before calculating the number of bytes required
6980 // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
6981 // attempt to update the record again.
6982 if (isKeepAliveRecord
&& (UpdateKeepaliveRData(m
, rr
, intf
, mDNSfalse
, mDNSNULL
) != mStatus_NoError
))
6983 LogSPS("CountProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m
, rr
));
6985 // Offload only Valid Keepalive records
6986 if (isKeepAliveRecord
&& !mDNSValidKeepAliveRecord(rr
))
6989 (void) TCPKAOnly
; // unused
6990 (void) supportsTCPKA
; // unused
6991 (void) intf
; // unused
6992 #endif // APPLE_OSX_mDNSResponder
6993 if (TfrRecordToNIC(rr
))
6995 *numbytes
+= DomainNameLength(rr
->resrec
.name
) + 10 + rr
->resrec
.rdestimate
;
6996 LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
6997 count
, DomainNameLength(rr
->resrec
.name
) + 10 + rr
->resrec
.rdestimate
, *numbytes
, ARDisplayString(m
,rr
));
7005 mDNSlocal
void GetProxyRecords(DNSMessage
*const msg
, uint32_t *const numbytes
, FatPtr
*const records
, mDNSBool TCPKAOnly
, mDNSBool supportsTCPKA
)
7007 mDNS
*const m
= &mDNSStorage
;
7008 mDNSu8
*p
= msg
->data
;
7009 const mDNSu8
*const limit
= p
+ *numbytes
;
7010 InitializeDNSMessage(&msg
->h
, zeroID
, zeroID
);
7015 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
7017 if (!(rr
->AuthFlags
& AuthFlagsWakeOnly
) && rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
7019 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7020 mDNSBool isKeepAliveRecord
= mDNS_KeepaliveRecord(&rr
->resrec
);
7022 // Skip over all other records if we are registering TCP KeepAlive records only
7023 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
7024 // supportsTCPKA is set to true if both policy and interface allow TCP Keepalive
7025 if ((TCPKAOnly
&& !isKeepAliveRecord
) || (isKeepAliveRecord
&& !supportsTCPKA
))
7028 // Offload only Valid Keepalive records
7029 if (isKeepAliveRecord
&& !mDNSValidKeepAliveRecord(rr
))
7032 (void) TCPKAOnly
; // unused
7033 (void) supportsTCPKA
; // unused
7034 #endif // APPLE_OSX_mDNSResponder
7036 if (TfrRecordToNIC(rr
))
7038 records
[count
].sixtyfourbits
= zeroOpaque64
;
7039 records
[count
].ptr
= p
;
7040 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
7041 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the 'unique' bit so PutResourceRecord will set it
7042 p
= PutResourceRecordTTLWithLimit(msg
, p
, &msg
->h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
, limit
);
7043 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear 'unique' bit back to normal state
7044 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
7045 count
, records
[count
].ptr
, p
, p
- (mDNSu8
*)records
[count
].ptr
, p
- msg
->data
, ARDisplayString(m
,rr
));
7050 *numbytes
= p
- msg
->data
;
7053 mDNSexport mDNSBool
SupportsInNICProxy(NetworkInterfaceInfo
*const intf
)
7055 if(!UseInternalSleepProxy
)
7057 LogMsg("SupportsInNICProxy: Internal Sleep Proxy is disabled");
7060 return CheckInterfaceSupport(intf
, mDNS_IOREG_KEY
);
7063 mDNSexport mStatus
ActivateLocalProxy(NetworkInterfaceInfo
*const intf
, mDNSBool
*keepaliveOnly
) // Called with the lock held
7065 mStatus result
= mStatus_UnknownErr
;
7066 mDNSBool TCPKAOnly
= mDNSfalse
;
7067 mDNSBool supportsTCPKA
= mDNSfalse
;
7068 mDNSBool onbattery
= mDNSfalse
;
7069 io_service_t service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOBSDNameMatching(kIOMasterPortDefault
, 0, intf
->ifname
));
7071 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7072 onbattery
= OnBattery();
7073 // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
7074 supportsTCPKA
= (InterfaceSupportsKeepAlive(intf
) && SupportsTCPKeepAlive());
7076 // Only TCP Keepalive records are to be offloaded if
7077 // - The system is on battery
7078 // - OR wake for network access is not set but powernap is enabled
7079 TCPKAOnly
= supportsTCPKA
&& ((mDNSStorage
.SystemWakeOnLANEnabled
== mDNS_WakeOnBattery
) || onbattery
);
7081 (void) onbattery
; // unused;
7083 if (!service
) { LogMsg("ActivateLocalProxy: No service for interface %s", intf
->ifname
); return(mStatus_UnknownErr
); }
7086 IOObjectGetClass(service
, n1
);
7087 io_object_t parent
= IO_OBJECT_NULL
;
7089 kern_return_t kr
= IORegistryEntryGetParentEntry(service
, kIOServicePlane
, &parent
);
7090 if (kr
!= KERN_SUCCESS
) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf
->ifname
, n1
, kr
);
7093 CFTypeRef ref
= mDNSNULL
;
7098 ref
= IORegistryEntryCreateCFProperty(parent
, CFSTR(mDNS_IOREG_KEY
), kCFAllocatorDefault
, mDNSNULL
);
7101 IOObjectRelease(service
);
7103 kr
= IORegistryEntryGetParentEntry(service
, kIOServicePlane
, &parent
);
7104 if (kr
!= KERN_SUCCESS
)
7106 IOObjectGetClass(service
, n1
);
7107 LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf
->ifname
, n1
, kr
);
7108 parent
= IO_OBJECT_NULL
;
7109 result
= mStatus_BadStateErr
;
7115 IOObjectGetClass(parent
, n2
);
7116 LogSPS("ActivateLocalProxy: Found %s Interface %s parent %s", mDNS_IOREG_KEY
, intf
->ifname
, n2
);
7123 IOObjectGetClass(parent
, n2
);
7124 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf
->ifname
, n1
, n2
);
7125 ref
= IORegistryEntryCreateCFProperty(parent
, CFSTR(mDNS_IOREG_KEY
), kCFAllocatorDefault
, mDNSNULL
);
7128 if (!ref
|| parent
== IO_OBJECT_NULL
) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", intf
->ifname
, n1
, n2
);
7131 if (CFGetTypeID(ref
) != CFStringGetTypeID() || !CFEqual(ref
, CFSTR(mDNS_IOREG_VALUE
)))
7132 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
7133 intf
->ifname
, n1
, n2
, CFStringGetCStringPtr(ref
, mDNSNULL
), mDNS_IOREG_VALUE
);
7134 else if (!UseInternalSleepProxy
)
7135 LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf
->ifname
);
7138 io_connect_t conObj
;
7139 kr
= IOServiceOpen(parent
, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE
, &conObj
);
7140 if (kr
!= KERN_SUCCESS
) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf
->ifname
, n1
, n2
, kr
);
7144 mDNSPlatformMemZero(&cmd
, sizeof(cmd
)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
7145 cmd
.command
= cmd_mDNSOffloadRR
;
7146 cmd
.numUDPPorts
= GetPortArray(mDNSTransport_UDP
, mDNSNULL
, TCPKAOnly
, supportsTCPKA
);
7147 cmd
.numTCPPorts
= GetPortArray(mDNSTransport_TCP
, mDNSNULL
, TCPKAOnly
, supportsTCPKA
);
7148 cmd
.numRRRecords
= CountProxyRecords(&cmd
.rrBufferSize
, intf
, TCPKAOnly
, supportsTCPKA
);
7149 cmd
.compression
= sizeof(DNSMessageHeader
);
7151 DNSMessage
*msg
= (DNSMessage
*)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader
) + cmd
.rrBufferSize
);
7152 cmd
.rrRecords
.ptr
= cmd
.numRRRecords
? mallocL("mDNSOffloadCmd rrRecords", cmd
.numRRRecords
* sizeof(FatPtr
)) : NULL
;
7153 cmd
.udpPorts
.ptr
= cmd
.numUDPPorts
? mallocL("mDNSOffloadCmd udpPorts" , cmd
.numUDPPorts
* sizeof(mDNSIPPort
)) : NULL
;
7154 cmd
.tcpPorts
.ptr
= cmd
.numTCPPorts
? mallocL("mDNSOffloadCmd tcpPorts" , cmd
.numTCPPorts
* sizeof(mDNSIPPort
)) : NULL
;
7156 LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
7157 msg
, cmd
.rrBufferSize
,
7158 cmd
.rrRecords
.ptr
, cmd
.numRRRecords
,
7159 cmd
.udpPorts
.ptr
, cmd
.numUDPPorts
,
7160 cmd
.tcpPorts
.ptr
, cmd
.numTCPPorts
);
7162 if (msg
&& cmd
.rrRecords
.ptr
) GetProxyRecords(msg
, &cmd
.rrBufferSize
, cmd
.rrRecords
.ptr
, TCPKAOnly
, supportsTCPKA
);
7163 if (cmd
.udpPorts
.ptr
) cmd
.numUDPPorts
= GetPortArray(mDNSTransport_UDP
, cmd
.udpPorts
.ptr
, TCPKAOnly
, supportsTCPKA
);
7164 if (cmd
.tcpPorts
.ptr
) cmd
.numTCPPorts
= GetPortArray(mDNSTransport_TCP
, cmd
.tcpPorts
.ptr
, TCPKAOnly
, supportsTCPKA
);
7167 size_t outputDataSize
= sizeof(outputData
);
7168 kr
= IOConnectCallStructMethod(conObj
, 0, &cmd
, sizeof(cmd
), outputData
, &outputDataSize
);
7169 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf
->ifname
, n1
, n2
, kr
);
7170 if (kr
== KERN_SUCCESS
) result
= mStatus_NoError
;
7172 if (cmd
.tcpPorts
.ptr
) freeL("mDNSOffloadCmd udpPorts", cmd
.tcpPorts
.ptr
);
7173 if (cmd
.udpPorts
.ptr
) freeL("mDNSOffloadCmd tcpPorts", cmd
.udpPorts
.ptr
);
7174 if (cmd
.rrRecords
.ptr
) freeL("mDNSOffloadCmd rrRecords", cmd
.rrRecords
.ptr
);
7175 if (msg
) freeL("mDNSOffloadCmd msg", msg
);
7176 IOServiceClose(conObj
);
7181 if (parent
!= IO_OBJECT_NULL
) IOObjectRelease(parent
);
7183 if (service
!= IO_OBJECT_NULL
) IOObjectRelease(service
);
7184 *keepaliveOnly
= TCPKAOnly
;
7188 #endif // APPLE_OSX_mDNSResponder
7190 mDNSlocal mDNSu8
SystemWakeForNetworkAccess(void)
7193 mDNSu8 ret
= (mDNSu8
)mDNS_NoWake
;
7196 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7200 if (DisableSleepProxyClient
)
7202 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7206 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val
);
7208 ret
= (mDNSu8
)(val
!= 0) ? mDNS_WakeOnAC
: mDNS_NoWake
;
7210 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7211 // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
7212 // Further policy decisions on whether to offload the records is handled during sleep processing.
7213 if ((ret
== mDNS_NoWake
) && SupportsTCPKeepAlive())
7214 ret
= (mDNSu8
)mDNS_WakeOnBattery
;
7215 #endif // APPLE_OSX_mDNSResponder
7217 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret
);
7221 mDNSlocal mDNSBool
SystemSleepOnlyIfWakeOnLAN(void)
7224 // PrioritizeNetworkReachabilityOverSleep has been deprecated.
7225 // GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
7226 // Statically set the PrioritizeNetworkReachabilityOverSleep value to 1 for AppleTV
7229 return val
!= 0 ? mDNStrue
: mDNSfalse
;
7233 #if APPLE_OSX_mDNSResponder
7234 // When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
7235 // gets deregistered, so that older peers are forced to connect over direct UDP instead of
7238 // When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
7239 // service records are deregistered, so they do not appear in peers' Finder sidebars.
7240 // We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
7241 // depend on their associated SRV record and therefore will be deregistered together in a
7242 // single update with the SRV record.
7244 // Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
7245 // its presence shouldn't delay sleep.
7247 // Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
7248 // relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
7250 // Also note that returning false here will not delay sleep past the maximum of 10 seconds.
7251 mDNSexport mDNSBool
RecordReadyForSleep(AuthRecord
*rr
)
7253 mDNS
*const m
= &mDNSStorage
;
7254 if (!AuthRecord_uDNS(rr
)) return mDNStrue
;
7256 if ((rr
->resrec
.rrtype
== kDNSType_AAAA
) && SameDomainLabel(rr
->namestorage
.c
, (const mDNSu8
*)"\x0c_autotunnel6"))
7258 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m
, rr
));
7262 if ((mDNSIPPortIsZero(m
->AutoTunnelNAT
.ExternalPort
) || m
->AutoTunnelNAT
.Result
))
7264 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& rr
->state
!= regState_NoTarget
&& rr
->zone
7265 && !SameDomainLabel(rr
->namestorage
.c
, (const mDNSu8
*)"\x0b_autotunnel"))
7267 DomainAuthInfo
*info
= GetAuthInfoForName_internal(m
, rr
->zone
);
7268 if (info
&& info
->AutoTunnel
)
7270 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m
, rr
));
7279 // Caller must hold the lock
7280 mDNSexport
void RemoveAutoTunnel6Record(mDNS
*const m
)
7282 DomainAuthInfo
*info
;
7283 // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
7284 // deregister the record, and the MemFree callback won't re-register.
7285 m
->AutoTunnelRelayAddr
= zerov6Addr
;
7286 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
7287 if (info
->AutoTunnel
)
7288 UpdateAutoTunnel6Record(m
, info
);
7290 #endif /* APPLE_OSX_mDNSResponder */
7292 #if MDNSRESPONDER_BTMM_SUPPORT
7293 mDNSlocal mDNSBool
IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr
, char *ifname
)
7295 struct ifaddrs
*ifa
;
7296 struct ifaddrs
*ifaddrs
;
7299 if (if_nametoindex(ifname
) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname
); return mDNSfalse
;}
7301 if (getifaddrs(&ifaddrs
) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse
;}
7303 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
7305 if (strncmp(ifa
->ifa_name
, ifname
, IFNAMSIZ
) != 0)
7307 if ((ifa
->ifa_flags
& IFF_UP
) == 0 || !ifa
->ifa_addr
|| ifa
->ifa_addr
->sa_family
!= AF_INET6
)
7309 if (SetupAddr(&addr
, ifa
->ifa_addr
) != mStatus_NoError
)
7311 LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
7314 if (mDNSSameIPv6Address(ipv6Addr
, *(mDNSv6Addr
*)&addr
.ip
.v6
))
7316 LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr
);
7320 freeifaddrs(ifaddrs
);
7324 mDNSlocal mDNSv6Addr
IPv6AddressFromString(char* buf
)
7327 struct addrinfo hints
;
7328 struct addrinfo
*res0
;
7330 memset(&hints
, 0, sizeof(hints
));
7331 hints
.ai_family
= AF_INET6
;
7332 hints
.ai_flags
= AI_NUMERICHOST
;
7334 int err
= getaddrinfo(buf
, NULL
, &hints
, &res0
);
7338 retVal
= *(mDNSv6Addr
*)&((struct sockaddr_in6
*)res0
->ai_addr
)->sin6_addr
;
7345 mDNSlocal CFDictionaryRef
CopyConnectivityBackToMyMacDict()
7347 CFDictionaryRef connd
= NULL
;
7348 CFDictionaryRef BTMMDict
= NULL
;
7350 connd
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_BTMMConnectivity
);
7353 LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
7357 BTMMDict
= CFDictionaryGetValue(connd
, CFSTR("BackToMyMac"));
7360 LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
7364 // Non-dictionary is treated as non-existent dictionary
7365 if (CFGetTypeID(BTMMDict
) != CFDictionaryGetTypeID())
7368 LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
7375 if (connd
) CFRelease(connd
);
7380 #define MAX_IPV6_TEXTUAL 40
7382 mDNSlocal mDNSv6Addr
ParseBackToMyMacAddr(CFDictionaryRef BTMMDict
, CFStringRef ifKey
, CFStringRef addrKey
)
7384 mDNSv6Addr retVal
= zerov6Addr
;
7385 CFTypeRef string
= NULL
;
7386 char ifname
[IFNAMSIZ
];
7387 char address
[MAX_IPV6_TEXTUAL
];
7392 if (!CFDictionaryGetValueIfPresent(BTMMDict
, ifKey
, &string
))
7394 LogInfo("ParseBackToMyMacAddr: interface key does not exist");
7398 if (!CFStringGetCString(string
, ifname
, IFNAMSIZ
, kCFStringEncodingUTF8
))
7400 LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
7404 if (!CFDictionaryGetValueIfPresent(BTMMDict
, addrKey
, &string
))
7406 LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
7410 if (!CFStringGetCString(string
, address
, sizeof(address
), kCFStringEncodingUTF8
))
7412 LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
7416 retVal
= IPv6AddressFromString(address
);
7417 LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname
, address
, &retVal
);
7419 if (mDNSIPv6AddressIsZero(retVal
))
7422 if (!IPv6AddressIsOnInterface(retVal
, ifname
))
7424 LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal
, ifname
);
7431 mDNSlocal CFDictionaryRef
GetBackToMyMacZones(CFDictionaryRef BTMMDict
)
7433 CFTypeRef zones
= NULL
;
7438 if (!CFDictionaryGetValueIfPresent(BTMMDict
, CFSTR("Zones"), &zones
))
7440 LogInfo("CopyBTMMZones: Zones key does not exist");
7447 mDNSlocal mDNSv6Addr
ParseBackToMyMacZone(CFDictionaryRef zones
, DomainAuthInfo
* info
)
7449 mDNSv6Addr addr
= zerov6Addr
;
7450 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
7451 CFStringRef domain
= NULL
;
7452 CFTypeRef theZone
= NULL
;
7457 ConvertDomainNameToCString(&info
->domain
, buffer
);
7458 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
7462 if (CFDictionaryGetValueIfPresent(zones
, domain
, &theZone
))
7463 addr
= ParseBackToMyMacAddr(theZone
, CFSTR("Interface"), CFSTR("Address"));
7470 mDNSlocal
void SetupBackToMyMacInnerAddresses(CFDictionaryRef BTMMDict
)
7472 mDNS
*const m
= &mDNSStorage
;
7473 DomainAuthInfo
* info
;
7474 CFDictionaryRef zones
= GetBackToMyMacZones(BTMMDict
);
7477 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
7479 if (!info
->AutoTunnel
)
7482 newAddr
= ParseBackToMyMacZone(zones
, info
);
7484 if (mDNSSameIPv6Address(newAddr
, info
->AutoTunnelInnerAddress
))
7487 info
->AutoTunnelInnerAddress
= newAddr
;
7488 DeregisterAutoTunnelHostRecord(m
, info
);
7489 UpdateAutoTunnelHostRecord(m
, info
);
7490 UpdateAutoTunnelDomainStatus(info
);
7494 // MUST be called holding the lock
7495 mDNSlocal
void ProcessConndConfigChanges(void)
7497 mDNS
*const m
= &mDNSStorage
;
7498 CFDictionaryRef dict
= CopyConnectivityBackToMyMacDict();
7500 LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
7501 mDNSv6Addr relayAddr
= ParseBackToMyMacAddr(dict
, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
7503 LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr
);
7505 SetupBackToMyMacInnerAddresses(dict
);
7507 if (dict
) CFRelease(dict
);
7509 if (!mDNSSameIPv6Address(relayAddr
, m
->AutoTunnelRelayAddr
))
7511 m
->AutoTunnelRelayAddr
= relayAddr
;
7513 DomainAuthInfo
* info
;
7514 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
7515 if (info
->AutoTunnel
)
7517 DeregisterAutoTunnel6Record(m
, info
);
7518 UpdateAutoTunnel6Record(m
, info
);
7519 UpdateAutoTunnelDomainStatus(info
);
7522 // Determine whether we need racoon to accept incoming connections
7523 UpdateAnonymousRacoonConfig(m
);
7526 // If awacsd crashes or exits for some reason, restart it
7527 UpdateBTMMRelayConnection(m
);
7529 #endif // MDNSRESPONDER_BTMM_SUPPORT
7531 mDNSlocal mDNSBool
IsAppleNetwork(mDNS
*const m
)
7534 // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
7535 for (s
= m
->DNSServers
; s
; s
= s
->next
)
7537 if (s
->addr
.ip
.v4
.b
[0] == 17)
7539 LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s
->domain
.c
, &s
->addr
);
7546 // Called with KQueueLock & mDNS lock
7547 // SetNetworkChanged is allowed to shorten (but not extend) the pause while we wait for configuration changes to settle
7548 mDNSlocal
void SetNetworkChanged(mDNSs32 delay
)
7550 mDNS
*const m
= &mDNSStorage
;
7552 if (!m
->NetworkChanged
|| m
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) > 0)
7554 m
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
7555 LogInfo("SetNetworkChanged: Scheduling in %d ticks", delay
);
7558 LogInfo("SetNetworkChanged: *NOT* increasing delay from %d to %d", m
->NetworkChanged
- m
->timenow
, delay
);
7561 // Called with KQueueLock & mDNS lock
7562 mDNSlocal
void SetKeyChainTimer(mDNSs32 delay
)
7564 mDNS
*const m
= &mDNSStorage
;
7565 // If it's not set or it needs to happen sooner than when it's currently set
7566 if (!m
->p
->KeyChainTimer
|| m
->p
->KeyChainTimer
- NonZeroTime(m
->timenow
+ delay
) > 0)
7568 m
->p
->KeyChainTimer
= NonZeroTime(m
->timenow
+ delay
);
7569 LogInfo("SetKeyChainTimer: %d", delay
);
7573 mDNSexport
void mDNSMacOSXNetworkChanged(void)
7575 mDNS
*const m
= &mDNSStorage
;
7576 LogInfo("*** Network Configuration Change *** %d ticks late%s",
7577 m
->NetworkChanged
? mDNS_TimeNow(m
) - m
->NetworkChanged
: 0,
7578 m
->NetworkChanged
? "" : " (no scheduled configuration change)");
7579 m
->NetworkChanged
= 0; // If we received a network change event and deferred processing, we're now dealing with it
7581 // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring
7582 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
7585 mDNSBool tentative
= mDNSfalse
;
7586 struct ifaddrs
*ifa
= myGetIfAddrs(1);
7589 if (ifa
->ifa_addr
&& ifa
->ifa_addr
->sa_family
== AF_INET6
)
7591 struct in6_ifreq ifr6
;
7592 mDNSPlatformMemZero((char *)&ifr6
, sizeof(ifr6
));
7593 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
7594 ifr6
.ifr_addr
= *(struct sockaddr_in6
*)ifa
->ifa_addr
;
7595 // We need to check for IN6_IFF_TENTATIVE here, not IN6_IFF_NOTREADY, because
7596 // IN6_IFF_NOTREADY includes both IN6_IFF_TENTATIVE and IN6_IFF_DUPLICATED addresses.
7597 // We can expect that an IN6_IFF_TENTATIVE address will shortly become ready,
7598 // but an IN6_IFF_DUPLICATED address may not.
7599 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
7601 if (ifr6
.ifr_ifru
.ifru_flags6
& IN6_IFF_TENTATIVE
)
7603 LogInfo("*** Network Configuration Change *** IPv6 address %.16a TENTATIVE, will retry", &ifr6
.ifr_addr
.sin6_addr
);
7604 tentative
= mDNStrue
;
7605 // no need to check other interfaces if we already found out that one interface is TENTATIVE
7610 ifa
= ifa
->ifa_next
;
7616 SetNetworkChanged(mDNSPlatformOneSecond
/ 2);
7620 LogInfo("*** Network Configuration Change *** No IPv6 address TENTATIVE, will continue");
7623 mDNSs32 utc
= mDNSPlatformUTC();
7624 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
7625 m
->SystemSleepOnlyIfWakeOnLAN
= SystemSleepOnlyIfWakeOnLAN();
7626 MarkAllInterfacesInactive(utc
);
7627 UpdateInterfaceList(utc
);
7628 ClearInactiveInterfaces(utc
);
7629 SetupActiveInterfaces(utc
);
7630 ReorderInterfaceList();
7632 #if APPLE_OSX_mDNSResponder
7633 #if !TARGET_OS_EMBEDDED
7634 #if MDNSRESPONDER_BTMM_SUPPORT
7636 ProcessConndConfigChanges();
7640 // Scan to find client tunnels whose questions have completed,
7641 // but whose local inner/outer addresses have changed since the tunnel was set up
7643 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
7644 if (p
->q
.ThisQInterval
< 0)
7646 DomainAuthInfo
* info
= GetAuthInfoForName(m
, &p
->dstname
);
7649 LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p
->dstname
.c
);
7650 AutoTunnelSetKeys(p
, mDNSfalse
);
7654 mDNSv6Addr inner
= info
->AutoTunnelInnerAddress
;
7656 if (!mDNSIPPortIsZero(p
->rmt_outer_port
))
7658 mDNSAddr tmpSrc
= zeroAddr
;
7659 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
7660 tmpDst
.ip
.v4
= p
->rmt_outer
;
7661 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
7662 if (!mDNSSameIPv6Address(p
->loc_inner
, inner
) ||
7663 !mDNSSameIPv4Address(p
->loc_outer
, tmpSrc
.ip
.v4
))
7665 AutoTunnelSetKeys(p
, mDNSfalse
);
7666 p
->loc_inner
= inner
;
7667 p
->loc_outer
= tmpSrc
.ip
.v4
;
7668 AutoTunnelSetKeys(p
, mDNStrue
);
7673 if (!mDNSSameIPv6Address(p
->loc_inner
, inner
) ||
7674 !mDNSSameIPv6Address(p
->loc_outer6
, m
->AutoTunnelRelayAddr
))
7676 AutoTunnelSetKeys(p
, mDNSfalse
);
7677 p
->loc_inner
= inner
;
7678 p
->loc_outer6
= m
->AutoTunnelRelayAddr
;
7679 AutoTunnelSetKeys(p
, mDNStrue
);
7684 #endif //!TARGET_OS_EMBEDDED
7688 NetworkInterfaceInfoOSX
*i
;
7689 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
7691 if (!m
->SPSSocket
) // Not being Sleep Proxy Server; close any open BPF fds
7693 if (i
->BPF_fd
>= 0 && CountProxyTargets(i
, mDNSNULL
, mDNSNULL
) == 0)
7696 else // else, we're Sleep Proxy Server; open BPF fds
7698 if (i
->Exists
&& (i
->Registered
== i
) && SPSInterface(i
) && i
->BPF_fd
== -1)
7700 LogMsg("%s mDNSMacOSXNetworkChanged: requesting BPF", i
->ifinfo
.ifname
);
7707 #endif // APPLE_OSX_mDNSResponder
7709 uDNS_SetupDNSConfig(m
);
7710 mDNS_ConfigChanged(m
);
7712 if (IsAppleNetwork(m
) != mDNS_McastTracingEnabled
)
7714 mDNS_McastTracingEnabled
= mDNS_McastTracingEnabled
? mDNSfalse
: mDNStrue
;
7715 LogInfo("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled
? "Enabled" : "Disabled");
7721 // Copy the fourth slash-delimited element from either:
7722 // State:/Network/Interface/<bsdname>/IPv4
7724 // Setup:/Network/Service/<servicename>/Interface
7725 mDNSlocal CFStringRef
CopyNameFromKey(CFStringRef key
)
7728 CFStringRef name
= NULL
;
7730 a
= CFStringCreateArrayBySeparatingStrings(NULL
, key
, CFSTR("/"));
7731 if (a
&& CFArrayGetCount(a
) == 5) name
= CFRetain(CFArrayGetValueAtIndex(a
, 3));
7732 if (a
!= NULL
) CFRelease(a
);
7737 // Whether a key from a network change notification corresponds to
7738 // an IP service that is explicitly configured for IPv4 Link Local
7739 mDNSlocal
int ChangedKeysHaveIPv4LL(CFArrayRef inkeys
)
7741 CFDictionaryRef dict
= NULL
;
7742 CFMutableArrayRef a
;
7743 const void **keys
= NULL
, **vals
= NULL
;
7744 CFStringRef pattern
= NULL
;
7748 jc
= CFArrayGetCount(inkeys
);
7751 a
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
7752 if (a
== NULL
) goto done
;
7754 // Setup:/Network/Service/[^/]+/Interface
7755 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetInterface
);
7756 if (pattern
== NULL
) goto done
;
7757 CFArrayAppendValue(a
, pattern
);
7760 // Setup:/Network/Service/[^/]+/IPv4
7761 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetIPv4
);
7762 if (pattern
== NULL
) goto done
;
7763 CFArrayAppendValue(a
, pattern
);
7766 dict
= SCDynamicStoreCopyMultiple(NULL
, NULL
, a
);
7771 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
7775 ic
= CFDictionaryGetCount(dict
);
7776 vals
= mDNSPlatformMemAllocate(sizeof (void *) * ic
);
7777 keys
= mDNSPlatformMemAllocate(sizeof (void *) * ic
);
7778 CFDictionaryGetKeysAndValues(dict
, keys
, vals
);
7780 // For each key we were given...
7781 for (j
= 0; j
< jc
; j
++)
7783 CFStringRef key
= CFArrayGetValueAtIndex(inkeys
, j
);
7784 CFStringRef ifname
= NULL
;
7788 // It would be nice to use a regex here
7789 if (!CFStringHasPrefix(key
, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key
, kSCEntNetIPv4
)) continue;
7791 if ((ifname
= CopyNameFromKey(key
)) == NULL
) continue;
7792 if (mDNS_LoggingEnabled
)
7794 if (!CFStringGetCString(ifname
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7795 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf
);
7798 // Loop over the interfaces to find matching the ifname, and see if that one has kSCValNetIPv4ConfigMethodLinkLocal
7799 for (i
= 0; i
< ic
; i
++)
7801 CFDictionaryRef ipv4dict
;
7803 CFStringRef serviceid
;
7804 CFStringRef configmethod
;
7806 if (!CFStringHasSuffix(keys
[i
], kSCEntNetInterface
)) continue;
7808 if (CFDictionaryGetTypeID() != CFGetTypeID(vals
[i
])) continue;
7810 if ((name
= CFDictionaryGetValue(vals
[i
], kSCPropNetInterfaceDeviceName
)) == NULL
) continue;
7812 if (!CFEqual(ifname
, name
)) continue;
7814 if ((serviceid
= CopyNameFromKey(keys
[i
])) == NULL
) continue;
7815 if (mDNS_LoggingEnabled
)
7817 if (!CFStringGetCString(serviceid
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7818 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf
);
7821 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceid
, kSCEntNetIPv4
);
7822 CFRelease(serviceid
);
7823 if (pattern
== NULL
) continue;
7825 ipv4dict
= CFDictionaryGetValue(dict
, pattern
);
7827 if (!ipv4dict
|| CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict
)) continue;
7829 configmethod
= CFDictionaryGetValue(ipv4dict
, kSCPropNetIPv4ConfigMethod
);
7830 if (!configmethod
) continue;
7832 if (mDNS_LoggingEnabled
)
7834 if (!CFStringGetCString(configmethod
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7835 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf
);
7838 if (CFEqual(configmethod
, kSCValNetIPv4ConfigMethodLinkLocal
)) { found
++; break; }
7845 if (vals
!= NULL
) mDNSPlatformMemFree(vals
);
7846 if (keys
!= NULL
) mDNSPlatformMemFree(keys
);
7847 if (dict
!= NULL
) CFRelease(dict
);
7852 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
7854 (void)store
; // Parameter not used
7855 mDNS
*const m
= (mDNS
*const)context
;
7859 //mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
7860 const mDNSs32 delay
= (mDNSPlatformOneSecond
+ 39) / 40; // 25 ms delay
7862 const int c
= CFArrayGetCount(changedKeys
); // Count changes
7863 CFRange range
= { 0, c
};
7864 const int c_host
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Hostnames
) != 0);
7865 const int c_comp
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Computername
) != 0);
7866 const int c_udns
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DNS
) != 0);
7867 const int c_ddns
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DynamicDNS
) != 0);
7868 #if MDNSRESPONDER_BTMM_SUPPORT
7869 const int c_btmm
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_BackToMyMac
) != 0);
7871 const int c_btmm
= 0;
7873 const int c_v4ll
= ChangedKeysHaveIPv4LL(changedKeys
);
7876 // Do immediate network changed processing for "p2p*" interfaces and
7877 // for interfaces with the IFEF_DIRECTLINK or IFEF_AWDL flag set or association with a CarPlay
7882 for (int i
= 0; i
< c
; i
++)
7884 CFStringRef key
= CFArrayGetValueAtIndex(changedKeys
, i
);
7886 // Only look at keys with prefix "State:/Network/Interface/"
7887 if (!CFStringHasPrefix(key
, NetworkChangedKey_StateInterfacePrefix
))
7890 // And suffix "IPv6" or "IPv4".
7891 if (!CFStringHasSuffix(key
, kSCEntNetIPv6
) && !CFStringHasSuffix(key
, kSCEntNetIPv4
))
7894 labels
= CFStringCreateArrayBySeparatingStrings(NULL
, key
, CFSTR("/"));
7897 n
= CFArrayGetCount(labels
);
7899 // Interface changes will have keys of the form:
7900 // State:/Network/Interface/<interfaceName>/IPv6
7901 // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
7906 // The 4th label (index = 3) should be the interface name.
7907 if (CFStringGetCString(CFArrayGetValueAtIndex(labels
, 3), buf
, sizeof(buf
), kCFStringEncodingUTF8
)
7908 && (strstr(buf
, "p2p") || (getExtendedFlags(buf
) & (IFEF_DIRECTLINK
| IFEF_AWDL
)) || IsCarPlaySSID(buf
)))
7910 LogInfo("NetworkChanged: interface %s qualifies for reduced change handling delay", buf
);
7920 //if (c && c - c_host - c_comp - c_udns - c_ddns - c_btmm - c_v4ll - c_fast == 0)
7921 // delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
7923 if (mDNS_LoggingEnabled
)
7929 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys
, i
), buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7930 LogInfo("*** Network Configuration Change *** SC key: %s", buf
);
7932 LogInfo("*** Network Configuration Change *** %d change%s %s%s%s%s%s%s%sdelay %d%s",
7934 c_host
? "(Local Hostname) " : "",
7935 c_comp
? "(Computer Name) " : "",
7936 c_udns
? "(DNS) " : "",
7937 c_ddns
? "(DynamicDNS) " : "",
7938 c_btmm
? "(BTMM) " : "",
7939 c_v4ll
? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
7940 c_fast
? "(P2P/IFEF_DIRECTLINK/IFEF_AWDL/IsCarPlaySSID) " : "",
7942 (c_ddns
|| c_btmm
) ? " + SetKeyChainTimer" : "");
7945 SetNetworkChanged(delay
);
7947 // Other software might pick up these changes to register or browse in WAB or BTMM domains,
7948 // so in order for secure updates to be made to the server, make sure to read the keychain and
7949 // setup the DomainAuthInfo before handing the network change.
7950 // If we don't, then we will first try to register services in the clear, then later setup the
7951 // DomainAuthInfo, which is incorrect.
7952 if (c_ddns
|| c_btmm
)
7953 SetKeyChainTimer(delay
);
7955 // Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
7958 KQueueUnlock("NetworkChanged");
7961 #if APPLE_OSX_mDNSResponder
7962 mDNSlocal
void RefreshSPSStatus(const void *key
, const void *value
, void *context
)
7967 CFStringRef ifnameStr
= (CFStringRef
)key
;
7968 CFArrayRef array
= (CFArrayRef
)value
;
7969 if (!CFStringGetCString(ifnameStr
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
7972 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf
, CFArrayGetCount(array
));
7973 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState
, buf
, value
);
7977 mDNSlocal
void DynamicStoreReconnected(SCDynamicStoreRef store
, void *info
)
7979 mDNS
*const m
= (mDNS
*const)info
;
7982 KQueueLock(); // serialize with KQueueLoop()
7984 LogInfo("DynamicStoreReconnected: Reconnected");
7986 // State:/Network/MulticastDNS
7989 // State:/Network/DynamicDNS
7991 mDNSPlatformDynDNSHostNameStatusChanged(&m
->FQDN
, 1);
7993 // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
7994 // as we receive network change notifications and thus not necessary. But we leave it here
7995 // so that if things are done differently in the future, this code still works.
7997 // State:/Network/PrivateDNS
7998 if (privateDnsArray
)
7999 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, mDNSNULL
, privateDnsArray
);
8001 #if APPLE_OSX_mDNSResponder
8002 // State:/Network/BackToMyMac
8003 UpdateAutoTunnelDomainStatuses(m
);
8005 // State:/Network/Interface/en0/SleepProxyServers
8007 CFDictionaryApplyFunction(spsStatusDict
, RefreshSPSStatus
, NULL
);
8009 KQueueUnlock("DynamicStoreReconnected");
8012 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
8015 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
8016 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
8017 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
8018 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
8019 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
8020 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
8022 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
8023 if (!keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
8025 CFArrayAppendValue(keys
, NetworkChangedKey_IPv4
);
8026 CFArrayAppendValue(keys
, NetworkChangedKey_IPv6
);
8027 CFArrayAppendValue(keys
, NetworkChangedKey_Hostnames
);
8028 CFArrayAppendValue(keys
, NetworkChangedKey_Computername
);
8029 CFArrayAppendValue(keys
, NetworkChangedKey_DNS
);
8030 CFArrayAppendValue(keys
, NetworkChangedKey_DynamicDNS
);
8031 CFArrayAppendValue(keys
, NetworkChangedKey_PowerSettings
);
8032 #if MDNSRESPONDER_BTMM_SUPPORT
8033 CFArrayAppendValue(keys
, NetworkChangedKey_BackToMyMac
);
8034 CFArrayAppendValue(keys
, NetworkChangedKey_BTMMConnectivity
);
8036 CFArrayAppendValue(patterns
, pattern1
);
8037 CFArrayAppendValue(patterns
, pattern2
);
8038 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
8039 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
8040 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
8042 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8043 if (!SCDynamicStoreSetDispatchQueue(store
, dispatch_get_main_queue()))
8044 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
8046 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
8047 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
8048 CFRunLoopAddSource(CFRunLoopGetMain(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
8050 SCDynamicStoreSetDisconnectCallBack(store
, DynamicStoreReconnected
);
8051 m
->p
->Store
= store
;
8056 if (store
) CFRelease(store
);
8059 if (patterns
) CFRelease(patterns
);
8060 if (pattern2
) CFRelease(pattern2
);
8061 if (pattern1
) CFRelease(pattern1
);
8062 if (keys
) CFRelease(keys
);
8067 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8069 mDNSlocal
void mDNSSetPacketFilterRules(char * ifname
, const ResourceRecord
*const excludeRecord
)
8071 mDNS
*const m
= &mDNSStorage
;
8073 pfArray_t portArray
;
8074 pfArray_t protocolArray
;
8077 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
8079 if ((rr
->resrec
.rrtype
== kDNSServiceType_SRV
)
8080 && ((rr
->ARType
== AuthRecordAnyIncludeP2P
) || (rr
->ARType
== AuthRecordAnyIncludeAWDLandP2P
)))
8084 if (count
>= PFPortArraySize
)
8086 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize
, ARDisplayString(m
, rr
));
8090 if (excludeRecord
&& IdenticalResourceRecord(&rr
->resrec
, excludeRecord
))
8092 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m
, rr
));
8096 LogMsg("mDNSSetPacketFilterRules: found %s", ARDisplayString(m
, rr
));
8098 portArray
[count
] = rr
->resrec
.rdata
->u
.srv
.port
.NotAnInteger
;
8100 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
8101 p
= rr
->resrec
.name
->c
;
8103 // Skip to App Protocol
8107 // Skip to Transport Protocol
8111 if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_tcp"))
8113 protocolArray
[count
] = IPPROTO_TCP
;
8115 else if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_udp"))
8117 protocolArray
[count
] = IPPROTO_UDP
;
8121 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
8122 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m
, rr
));
8128 mDNSPacketFilterControl(PF_SET_RULES
, ifname
, count
, portArray
, protocolArray
);
8131 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
8132 mDNSexport
void mDNSUpdatePacketFilter(const ResourceRecord
*const excludeRecord
)
8134 mDNS
*const m
= &mDNSStorage
;
8136 NetworkInterfaceInfo
*intf
= GetFirstActiveInterface(m
->HostInterfaces
);
8139 if (strncmp(intf
->ifname
, "p2p", 3) == 0)
8141 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf
->ifname
);
8142 mDNSSetPacketFilterRules(intf
->ifname
, excludeRecord
);
8145 intf
= GetFirstActiveInterface(intf
->next
);
8149 #else // !TARGET_OS_EMBEDDED
8151 // Currently no packet filter setup required on embedded platforms.
8152 mDNSexport
void mDNSUpdatePacketFilter(const ResourceRecord
*const excludeRecord
)
8154 (void) excludeRecord
; // unused
8157 #endif // !TARGET_OS_EMBEDDED
8159 // AWDL should no longer generate KEV_DL_MASTER_ELECTED events, so just log a message if we receive one.
8160 mDNSlocal
void newMasterElected(struct net_event_data
* ptr
)
8162 char ifname
[IFNAMSIZ
];
8163 mDNSu32 interfaceIndex
;
8165 snprintf(ifname
, IFNAMSIZ
, "%s%d", ptr
->if_name
, ptr
->if_unit
);
8166 interfaceIndex
= if_nametoindex(ifname
);
8168 if (!interfaceIndex
)
8170 LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname
);
8174 LogInfo("newMasterElected: KEV_DL_MASTER_ELECTED received on ifname = %s, interfaceIndex = %d", ifname
, interfaceIndex
);
8177 // An ssth array of all zeroes indicates the peer has no services registered.
8178 mDNSlocal mDNSBool
allZeroSSTH(struct opaque_presence_indication
*op
)
8181 int *intp
= (int *) op
->ssth
;
8183 // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
8184 // it's not, print an error message and return false so that
8185 // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
8187 if (MAX_SSTH_SIZE
% sizeof(int))
8189 LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE
);
8193 for (i
= 0; i
< (int)(MAX_SSTH_SIZE
/ sizeof(int)); i
++, intp
++)
8201 // Mark records from this peer for deletion from the cache.
8202 mDNSlocal
void removeCachedPeerRecords(mDNSu32 ifindex
, mDNSAddr
*ap
, bool purgeNow
)
8204 mDNS
*const m
= &mDNSStorage
;
8208 NetworkInterfaceInfoOSX
*infoOSX
;
8209 mDNSInterfaceID InterfaceID
;
8211 // Using mDNSPlatformInterfaceIDfromInterfaceIndex() would lead to recursive
8212 // locking issues, see: <rdar://problem/21332983>
8213 infoOSX
= IfindexToInterfaceInfoOSX((mDNSInterfaceID
)(uintptr_t)ifindex
);
8216 LogInfo("removeCachedPeerRecords: interface %d not yet active", ifindex
);
8219 InterfaceID
= infoOSX
->ifinfo
.InterfaceID
;
8221 FORALL_CACHERECORDS(slot
, cg
, cr
)
8223 if ((InterfaceID
== cr
->resrec
.InterfaceID
) && mDNSSameAddress(ap
, & cr
->sourceAddress
))
8225 LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
8226 DNSTypeName(cr
->resrec
.rrtype
), cr
->resrec
.name
->c
);
8229 mDNS_PurgeCacheResourceRecord(m
, cr
);
8231 mDNS_Reconfirm_internal(m
, cr
, 0); // use default minimum reconfirm time
8236 // Handle KEV_DL_NODE_PRESENCE event.
8237 mDNSlocal
void nodePresence(struct kev_dl_node_presence
* p
)
8239 struct opaque_presence_indication
*op
= (struct opaque_presence_indication
*) p
->node_service_info
;
8241 LogInfo("nodePresence: IPv6 address: %.16a, SUI %d", p
->sin6_node_address
.sin6_addr
.s6_addr
, op
->SUI
);
8243 // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
8244 // all zeroes when a node is present and has no services registered.
8245 if (allZeroSSTH(op
))
8249 peerAddr
.type
= mDNSAddrType_IPv6
;
8250 peerAddr
.ip
.v6
= *(mDNSv6Addr
*)&p
->sin6_node_address
.sin6_addr
;
8252 LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer");
8253 removeCachedPeerRecords(p
->sdl_node_address
.sdl_index
, & peerAddr
, false);
8257 // Handle KEV_DL_NODE_ABSENCE event.
8258 mDNSlocal
void nodeAbsence(struct kev_dl_node_absence
* p
)
8262 peerAddr
.type
= mDNSAddrType_IPv6
;
8263 peerAddr
.ip
.v6
= *(mDNSv6Addr
*)&p
->sin6_node_address
.sin6_addr
;
8265 LogInfo("nodeAbsence: immediately purge cached records from %.16a", p
->sin6_node_address
.sin6_addr
.s6_addr
);
8266 removeCachedPeerRecords(p
->sdl_node_address
.sdl_index
, & peerAddr
, true);
8269 mDNSlocal
void SysEventCallBack(int s1
, short __unused filter
, void *context
, __unused mDNSBool encounteredEOF
)
8271 mDNS
*const m
= (mDNS
*const)context
;
8275 struct { struct kern_event_msg k
; char extra
[256]; } msg
;
8276 int bytes
= recv(s1
, &msg
, sizeof(msg
), 0);
8278 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes
, errno
, strerror(errno
));
8281 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
8282 bytes
, msg
.k
.total_size
,
8283 msg
.k
.vendor_code
, msg
.k
.vendor_code
== KEV_VENDOR_APPLE
? "KEV_VENDOR_APPLE" : "?",
8284 msg
.k
.kev_class
, msg
.k
.kev_class
== KEV_NETWORK_CLASS
? "KEV_NETWORK_CLASS" : "?",
8285 msg
.k
.kev_subclass
, msg
.k
.kev_subclass
== KEV_DL_SUBCLASS
? "KEV_DL_SUBCLASS" : "?",
8286 msg
.k
.id
, msg
.k
.event_code
,
8287 msg
.k
.event_code
== KEV_DL_SIFFLAGS
? "KEV_DL_SIFFLAGS" :
8288 msg
.k
.event_code
== KEV_DL_SIFMETRICS
? "KEV_DL_SIFMETRICS" :
8289 msg
.k
.event_code
== KEV_DL_SIFMTU
? "KEV_DL_SIFMTU" :
8290 msg
.k
.event_code
== KEV_DL_SIFPHYS
? "KEV_DL_SIFPHYS" :
8291 msg
.k
.event_code
== KEV_DL_SIFMEDIA
? "KEV_DL_SIFMEDIA" :
8292 msg
.k
.event_code
== KEV_DL_SIFGENERIC
? "KEV_DL_SIFGENERIC" :
8293 msg
.k
.event_code
== KEV_DL_ADDMULTI
? "KEV_DL_ADDMULTI" :
8294 msg
.k
.event_code
== KEV_DL_DELMULTI
? "KEV_DL_DELMULTI" :
8295 msg
.k
.event_code
== KEV_DL_IF_ATTACHED
? "KEV_DL_IF_ATTACHED" :
8296 msg
.k
.event_code
== KEV_DL_IF_DETACHING
? "KEV_DL_IF_DETACHING" :
8297 msg
.k
.event_code
== KEV_DL_IF_DETACHED
? "KEV_DL_IF_DETACHED" :
8298 msg
.k
.event_code
== KEV_DL_LINK_OFF
? "KEV_DL_LINK_OFF" :
8299 msg
.k
.event_code
== KEV_DL_LINK_ON
? "KEV_DL_LINK_ON" :
8300 msg
.k
.event_code
== KEV_DL_PROTO_ATTACHED
? "KEV_DL_PROTO_ATTACHED" :
8301 msg
.k
.event_code
== KEV_DL_PROTO_DETACHED
? "KEV_DL_PROTO_DETACHED" :
8302 msg
.k
.event_code
== KEV_DL_LINK_ADDRESS_CHANGED
? "KEV_DL_LINK_ADDRESS_CHANGED" :
8303 msg
.k
.event_code
== KEV_DL_WAKEFLAGS_CHANGED
? "KEV_DL_WAKEFLAGS_CHANGED" :
8304 msg
.k
.event_code
== KEV_DL_IF_IDLE_ROUTE_REFCNT
? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
8305 msg
.k
.event_code
== KEV_DL_IFCAP_CHANGED
? "KEV_DL_IFCAP_CHANGED" :
8306 msg
.k
.event_code
== KEV_DL_LINK_QUALITY_METRIC_CHANGED
? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" :
8307 msg
.k
.event_code
== KEV_DL_NODE_PRESENCE
? "KEV_DL_NODE_PRESENCE" :
8308 msg
.k
.event_code
== KEV_DL_NODE_ABSENCE
? "KEV_DL_NODE_ABSENCE" :
8309 msg
.k
.event_code
== KEV_DL_MASTER_ELECTED
? "KEV_DL_MASTER_ELECTED" :
8312 if (msg
.k
.event_code
== KEV_DL_NODE_PRESENCE
)
8313 nodePresence((struct kev_dl_node_presence
*) &msg
.k
.event_data
);
8315 if (msg
.k
.event_code
== KEV_DL_NODE_ABSENCE
)
8316 nodeAbsence((struct kev_dl_node_absence
*) &msg
.k
.event_data
);
8318 if (msg
.k
.event_code
== KEV_DL_MASTER_ELECTED
)
8319 newMasterElected((struct net_event_data
*) &msg
.k
.event_data
);
8321 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
8322 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
8323 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
8324 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
8325 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
8327 if (msg
.k
.event_code
== KEV_DL_WAKEFLAGS_CHANGED
|| msg
.k
.event_code
== KEV_DL_LINK_ON
)
8328 SetNetworkChanged(mDNSPlatformOneSecond
* 2);
8330 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8332 // For p2p interfaces, need to open the advertised service port in the firewall.
8333 if (msg
.k
.event_code
== KEV_DL_IF_ATTACHED
)
8335 struct net_event_data
* p
;
8336 p
= (struct net_event_data
*) &msg
.k
.event_data
;
8338 if (strncmp(p
->if_name
, "p2p", 3) == 0)
8340 char ifname
[IFNAMSIZ
];
8341 snprintf(ifname
, IFNAMSIZ
, "%s%d", p
->if_name
, p
->if_unit
);
8343 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p
->if_family
, p
->if_unit
, p
->if_name
);
8345 mDNSSetPacketFilterRules(ifname
, NULL
);
8349 // For p2p interfaces, need to clear the firewall rules on interface detach
8350 if (msg
.k
.event_code
== KEV_DL_IF_DETACHED
)
8352 struct net_event_data
* p
;
8353 p
= (struct net_event_data
*) &msg
.k
.event_data
;
8355 if (strncmp(p
->if_name
, "p2p", 3) == 0)
8357 pfArray_t portArray
, protocolArray
; // not initialized since count is 0 for PF_CLEAR_RULES
8358 char ifname
[IFNAMSIZ
];
8359 snprintf(ifname
, IFNAMSIZ
, "%s%d", p
->if_name
, p
->if_unit
);
8361 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p
->if_family
, p
->if_unit
, p
->if_name
);
8363 mDNSPacketFilterControl(PF_CLEAR_RULES
, ifname
, 0, portArray
, protocolArray
);
8366 #endif // !TARGET_OS_EMBEDDED
8373 mDNSlocal mStatus
WatchForSysEvents(mDNS
*const m
)
8375 m
->p
->SysEventNotifier
= socket(PF_SYSTEM
, SOCK_RAW
, SYSPROTO_EVENT
);
8376 if (m
->p
->SysEventNotifier
< 0)
8377 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m
->p
->SysEventNotifier
, errno
, strerror(errno
)); return(mStatus_NoMemoryErr
); }
8379 struct kev_request kev_req
= { KEV_VENDOR_APPLE
, KEV_NETWORK_CLASS
, KEV_DL_SUBCLASS
};
8380 int err
= ioctl(m
->p
->SysEventNotifier
, SIOCSKEVFILT
, &kev_req
);
8383 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err
, errno
, strerror(errno
));
8384 close(m
->p
->SysEventNotifier
);
8385 m
->p
->SysEventNotifier
= -1;
8386 return(mStatus_UnknownErr
);
8389 m
->p
->SysEventKQueue
.KQcallback
= SysEventCallBack
;
8390 m
->p
->SysEventKQueue
.KQcontext
= m
;
8391 m
->p
->SysEventKQueue
.KQtask
= "System Event Notifier";
8392 KQueueSet(m
->p
->SysEventNotifier
, EV_ADD
, EVFILT_READ
, &m
->p
->SysEventKQueue
);
8394 return(mStatus_NoError
);
8397 #ifndef NO_SECURITYFRAMEWORK
8398 mDNSlocal OSStatus
KeychainChanged(SecKeychainEvent keychainEvent
, SecKeychainCallbackInfo
*info
, void *context
)
8400 LogInfo("*** Keychain Changed ***");
8401 mDNS
*const m
= (mDNS
*const)context
;
8403 OSStatus err
= SecKeychainCopyDefault(&skc
);
8406 if (info
->keychain
== skc
)
8408 // 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
8409 mDNSBool relevant
= (keychainEvent
== kSecDeleteEvent
);
8412 UInt32 tags
[3] = { kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
};
8413 SecKeychainAttributeInfo attrInfo
= { 3, tags
, NULL
}; // Count, array of tags, array of formats
8414 SecKeychainAttributeList
*a
= NULL
;
8415 err
= SecKeychainItemCopyAttributesAndData(info
->item
, &attrInfo
, NULL
, &a
, NULL
, NULL
);
8418 relevant
= ((a
->attr
[0].length
== 4 && (!strncasecmp(a
->attr
[0].data
, "ddns", 4) || !strncasecmp(a
->attr
[0].data
, "sndd", 4))) ||
8419 (a
->attr
[1].length
>= mDNSPlatformStrLen(dnsprefix
) && (!strncasecmp(a
->attr
[1].data
, dnsprefix
, mDNSPlatformStrLen(dnsprefix
)))));
8420 #if MDNSRESPONDER_BTMM_SUPPORT
8421 if (!relevant
&& (a
->attr
[1].length
>= mDNSPlatformStrLen(btmmprefix
)) && !strncasecmp(a
->attr
[1].data
, btmmprefix
, mDNSPlatformStrLen(btmmprefix
)))
8423 relevant
= mDNStrue
;
8426 SecKeychainItemFreeAttributesAndData(a
, NULL
);
8431 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
8433 keychainEvent
== kSecAddEvent
? "kSecAddEvent" :
8434 keychainEvent
== kSecDeleteEvent
? "kSecDeleteEvent" :
8435 keychainEvent
== kSecUpdateEvent
? "kSecUpdateEvent" : "<Unknown>");
8436 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
8440 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
8441 // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
8442 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
8444 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
8445 // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
8446 // a one second delay is ok, as we'll still converge to correctness, and there's no race
8447 // condition between the RegistrationDomain and the DomainAuthInfo.
8449 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
8450 // the timer here, as it will not get set by NetworkChanged().
8451 SetKeyChainTimer(mDNSPlatformOneSecond
);
8454 KQueueUnlock("KeychainChanged");
8464 mDNSlocal
void PowerOn(mDNS
*const m
)
8466 mDNSCoreMachineSleep(m
, false); // Will set m->SleepState = SleepState_Awake;
8468 if (m
->p
->WakeAtUTC
)
8470 long utc
= mDNSPlatformUTC();
8471 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
8472 if (m
->p
->WakeAtUTC
- utc
> 30)
8474 LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m
->p
->WakeAtUTC
- utc
);
8476 else if (utc
- m
->p
->WakeAtUTC
> 30)
8478 LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc
- m
->p
->WakeAtUTC
);
8480 else if (IsAppleTV())
8482 LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc
- m
->p
->WakeAtUTC
);
8486 LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m
->p
->WakeAtUTC
- utc
);
8487 m
->p
->RequestReSleep
= mDNS_TimeNow(m
) + 20 * mDNSPlatformOneSecond
;
8491 // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
8492 // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
8493 // We will clear this assertion as soon as we think the mainenance activities are done.
8494 mDNSPlatformPreventSleep(DARK_WAKE_TIME
, "mDNSResponder:maintenance");
8498 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
8500 mDNS
*const m
= (mDNS
*const)refcon
;
8502 (void)service
; // Parameter not used
8503 debugf("PowerChanged %X %lX", messageType
, messageArgument
);
8505 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8506 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
8510 case kIOMessageCanSystemPowerOff
: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
8511 case kIOMessageSystemWillPowerOff
: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
8512 mDNSCoreMachineSleep(m
, true);
8513 if (m
->SleepState
== SleepState_Sleeping
) mDNSMacOSXNetworkChanged();
8515 case kIOMessageSystemWillNotPowerOff
: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
8516 case kIOMessageCanSystemSleep
: LogSPS("PowerChanged kIOMessageCanSystemSleep"); break; // E0000270
8517 case kIOMessageSystemWillSleep
: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
8518 mDNSCoreMachineSleep(m
, true);
8520 case kIOMessageSystemWillNotSleep
: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
8521 case kIOMessageSystemHasPoweredOn
: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
8522 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
8525 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m
->SleepState
);
8528 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
8529 // the System Configuration Framework "network changed" event that we expect
8530 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
8532 SetNetworkChanged(mDNSPlatformOneSecond
* 2);
8536 case kIOMessageSystemWillRestart
: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
8537 case kIOMessageSystemWillPowerOn
: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
8539 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
8540 if (m
->SleepState
!= SleepState_Sleeping
)
8542 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m
->SleepState
);
8543 m
->SleepState
= SleepState_Sleeping
;
8544 mDNSMacOSXNetworkChanged();
8548 default: LogSPS("PowerChanged unknown message %X", messageType
); break;
8551 if (messageType
== kIOMessageSystemWillSleep
)
8552 m
->p
->SleepCookie
= (long)messageArgument
;
8553 else if (messageType
== kIOMessageCanSystemSleep
)
8554 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
8556 KQueueUnlock("PowerChanged Sleep/Wake");
8559 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
8560 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
8561 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
8562 mDNSlocal
void SnowLeopardPowerChanged(void *refcon
, IOPMConnection connection
, IOPMConnectionMessageToken token
, IOPMSystemPowerStateCapabilities eventDescriptor
)
8564 mDNS
*const m
= (mDNS
*const)refcon
;
8566 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
8567 connection
, token
, eventDescriptor
,
8568 eventDescriptor
& kIOPMSystemPowerStateCapabilityCPU
? " CPU" : "",
8569 eventDescriptor
& kIOPMSystemPowerStateCapabilityVideo
? " Video" : "",
8570 eventDescriptor
& kIOPMSystemPowerStateCapabilityAudio
? " Audio" : "",
8571 eventDescriptor
& kIOPMSystemPowerStateCapabilityNetwork
? " Network" : "",
8572 eventDescriptor
& kIOPMSystemPowerStateCapabilityDisk
? " Disk" : "");
8574 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8575 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
8577 if (eventDescriptor
& kIOPMSystemPowerStateCapabilityCPU
)
8579 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
8580 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
8581 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
8582 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
8585 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m
->SleepLimit
, m
->SleepState
);
8586 IOPMConnectionAcknowledgeEvent(connection
, m
->p
->SleepCookie
);
8589 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m
->SleepLimit
, m
->SleepState
);
8590 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
8591 if (m
->SleepState
!= SleepState_Awake
)
8594 // If the network notifications have already come before we got the wakeup, we ignored them and
8595 // in case we get no more, we need to trigger one.
8597 SetNetworkChanged(mDNSPlatformOneSecond
* 2);
8600 IOPMConnectionAcknowledgeEvent(connection
, token
);
8604 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
8605 // we should hear nothing more until we're told that the CPU has started executing again.
8606 if (m
->SleepState
) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor
, m
->SleepState
);
8608 //mDNSMacOSXNetworkChanged(m);
8609 mDNSCoreMachineSleep(m
, true);
8610 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
8611 m
->p
->SleepCookie
= token
;
8614 KQueueUnlock("SnowLeopardPowerChanged Sleep/Wake");
8618 #if COMPILER_LIKES_PRAGMA_MARK
8620 #pragma mark - /etc/hosts support
8623 // Implementation Notes
8625 // As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
8626 // 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
8627 // them into a hash table. The implementation need to be able to do the following things efficiently
8629 // 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
8630 // 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
8631 // 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
8632 // need to be able set the RRSet of a resource record to the first one in the list and also update when
8633 // one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
8635 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
8637 // CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
8638 // "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
8639 // of the core layer which does all of the above very efficiently
8641 #define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
8643 mDNSexport
void FreeEtcHosts(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
8648 if (result
== mStatus_MemFree
)
8650 LogInfo("FreeEtcHosts: %s", ARDisplayString(m
, rr
));
8651 freeL("etchosts", rr
);
8655 // Returns true on success and false on failure
8656 mDNSlocal mDNSBool
mDNSMacOSXCreateEtcHostsEntry(const domainname
*domain
, const struct sockaddr
*sa
, const domainname
*cname
, char *ifname
, AuthHash
*auth
)
8661 mDNSInterfaceID InterfaceID
= mDNSInterface_LocalOnly
;
8666 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
8671 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
8675 if (sa
&& sa
->sa_family
!= AF_INET
&& sa
->sa_family
!= AF_INET6
)
8677 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa
->sa_family
);
8684 mDNSu32 ifindex
= if_nametoindex(ifname
);
8687 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain
->c
, ifname
);
8690 InterfaceID
= (mDNSInterfaceID
)(uintptr_t)ifindex
;
8694 rrtype
= (sa
->sa_family
== AF_INET
? kDNSType_A
: kDNSType_AAAA
);
8696 rrtype
= kDNSType_CNAME
;
8698 // Check for duplicates. See whether we parsed an entry before like this ?
8699 namehash
= DomainNameHashValue(domain
);
8700 ag
= AuthGroupForName(auth
, namehash
, domain
);
8706 if (rr
->resrec
.rrtype
== rrtype
)
8708 if (rrtype
== kDNSType_A
)
8711 ip
.NotAnInteger
= ((struct sockaddr_in
*)sa
)->sin_addr
.s_addr
;
8712 if (mDNSSameIPv4Address(rr
->resrec
.rdata
->u
.ipv4
, ip
))
8714 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain
->c
);
8718 else if (rrtype
== kDNSType_AAAA
)
8721 ip6
.l
[0] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[0];
8722 ip6
.l
[1] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[1];
8723 ip6
.l
[2] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[2];
8724 ip6
.l
[3] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[3];
8725 if (mDNSSameIPv6Address(rr
->resrec
.rdata
->u
.ipv6
, ip6
))
8727 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain
->c
);
8731 else if (rrtype
== kDNSType_CNAME
)
8733 if (SameDomainName(&rr
->resrec
.rdata
->u
.name
, cname
))
8735 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname
->c
, domain
->c
);
8743 rr
= mallocL("etchosts", sizeof(*rr
));
8744 if (rr
== NULL
) return mDNSfalse
;
8745 mDNSPlatformMemZero(rr
, sizeof(*rr
));
8746 mDNS_SetupResourceRecord(rr
, NULL
, InterfaceID
, rrtype
, 1, kDNSRecordTypeKnownUnique
, AuthRecordLocalOnly
, FreeEtcHosts
, NULL
);
8747 AssignDomainName(&rr
->namestorage
, domain
);
8751 rr
->resrec
.rdlength
= sa
->sa_family
== AF_INET
? sizeof(mDNSv4Addr
) : sizeof(mDNSv6Addr
);
8752 if (sa
->sa_family
== AF_INET
)
8753 rr
->resrec
.rdata
->u
.ipv4
.NotAnInteger
= ((struct sockaddr_in
*)sa
)->sin_addr
.s_addr
;
8756 rr
->resrec
.rdata
->u
.ipv6
.l
[0] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[0];
8757 rr
->resrec
.rdata
->u
.ipv6
.l
[1] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[1];
8758 rr
->resrec
.rdata
->u
.ipv6
.l
[2] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[2];
8759 rr
->resrec
.rdata
->u
.ipv6
.l
[3] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[3];
8764 rr
->resrec
.rdlength
= DomainNameLength(cname
);
8765 rr
->resrec
.rdata
->u
.name
.c
[0] = 0;
8766 AssignDomainName(&rr
->resrec
.rdata
->u
.name
, cname
);
8768 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
8769 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
8770 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(&mDNSStorage
, rr
));
8771 InsertAuthRecord(&mDNSStorage
, auth
, rr
);
8775 mDNSlocal
int EtcHostsParseOneName(int start
, int length
, char *buffer
, char **name
)
8780 for (i
= start
; i
< length
; i
++)
8782 if (buffer
[i
] == '#')
8784 if (buffer
[i
] != ' ' && buffer
[i
] != ',' && buffer
[i
] != '\t')
8788 // Found the start of a name, find the end and null terminate
8789 for (i
++; i
< length
; i
++)
8791 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t')
8803 mDNSlocal
void mDNSMacOSXParseEtcHostsLine(char *buffer
, ssize_t length
, AuthHash
*auth
)
8807 char *ifname
= NULL
;
8814 //Ignore leading whitespaces and tabs
8815 while (*buffer
== ' ' || *buffer
== '\t')
8821 // Find the end of the address string
8822 for (i
= 0; i
< length
; i
++)
8824 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t' || buffer
[i
] == '%')
8826 if (buffer
[i
] == '%')
8833 // Convert the address string to an address
8834 struct addrinfo hints
;
8835 bzero(&hints
, sizeof(hints
));
8836 hints
.ai_flags
= AI_NUMERICHOST
;
8837 struct addrinfo
*gairesults
= NULL
;
8838 if (getaddrinfo(buffer
, NULL
, &hints
, &gairesults
) != 0)
8840 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
8846 // Parse the interface
8847 ifname
= &buffer
[ifStart
];
8848 for (i
= ifStart
+ 1; i
< length
; i
++)
8850 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t')
8858 i
= EtcHostsParseOneName(i
+ 1, length
, buffer
, &name1
);
8861 // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
8862 if (!MakeDomainNameFromDNSNameString(&name1d
, name1
))
8864 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1
);
8865 freeaddrinfo(gairesults
);
8868 mDNSMacOSXCreateEtcHostsEntry(&name1d
, gairesults
->ai_addr
, mDNSNULL
, ifname
, auth
);
8873 // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
8874 // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
8875 // doing the right thing.
8877 if (!MakeDomainNameFromDNSNameString(&first
, name1
))
8879 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1
);
8880 freeaddrinfo(gairesults
);
8883 mDNSMacOSXCreateEtcHostsEntry(&first
, gairesults
->ai_addr
, mDNSNULL
, ifname
, auth
);
8885 // /etc/hosts alias discussion:
8887 // If the /etc/hosts has an entry like this
8889 // ip_address cname [aliases...]
8890 // 1.2.3.4 sun star bright
8892 // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
8893 // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
8895 // To achieve this, we need to add the entry like this:
8901 // We store the first name we parsed in "first" and add the address (A/AAAA) record.
8902 // Then we parse additional names adding CNAME records till we reach the end.
8907 // Continue to parse additional aliases until we reach end of the line and
8908 // for each "alias" parsed, add a CNAME record where "alias" points to the first "name".
8909 // See also /etc/hosts alias discussion above
8911 i
= EtcHostsParseOneName(i
+ 1, length
, buffer
, &name2
);
8915 if ((aliasIndex
) && (*buffer
== *name2
))
8916 break; // break out of the loop if we wrap around
8918 if (!MakeDomainNameFromDNSNameString(&name2d
, name2
))
8920 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2
);
8921 freeaddrinfo(gairesults
);
8924 // Ignore if it points to itself
8925 if (!SameDomainName(&first
, &name2d
))
8927 if (!mDNSMacOSXCreateEtcHostsEntry(&name2d
, mDNSNULL
, &first
, ifname
, auth
))
8929 freeaddrinfo(gairesults
);
8935 LogInfo("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names first %##s, name2 %##s", first
.c
, name2d
.c
);
8939 else if (!aliasIndex
)
8941 // We have never parsed any aliases. This case happens if there
8942 // is just one name and some extra white spaces at the end.
8943 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first
.c
);
8948 freeaddrinfo(gairesults
);
8951 mDNSlocal
void mDNSMacOSXParseEtcHosts(int fd
, AuthHash
*auth
)
8954 char buf
[ETCHOSTS_BUFSIZE
];
8958 if (fd
== -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
8960 fp
= fopen("/etc/hosts", "r");
8961 if (!fp
) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
8965 good
= (fgets(buf
, ETCHOSTS_BUFSIZE
, fp
) != NULL
);
8968 // skip comment and empty lines
8969 if (buf
[0] == '#' || buf
[0] == '\r' || buf
[0] == '\n')
8973 if (!len
) break; // sanity check
8974 //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
8975 if (buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
8977 buf
[len
- 1] = '\0';
8980 // fgets always null terminates and hence even if we have no
8981 // newline at the end, it is null terminated. The callee
8982 // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
8983 // buf[length] is zero and hence we decrement len to reflect that.
8986 //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
8987 //here we need to check for just \r but taking extra caution.
8988 if (buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
8990 buf
[len
- 1] = '\0';
8994 if (!len
) //Sanity Check: len should never be zero
8996 LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
8999 mDNSMacOSXParseEtcHostsLine(buf
, len
, auth
);
9004 mDNSlocal
void mDNSMacOSXUpdateEtcHosts(mDNS
*const m
);
9006 mDNSlocal
int mDNSMacOSXGetEtcHostsFD(void)
9008 mDNS
*const m
= &mDNSStorage
;
9009 #ifdef __DISPATCH_GROUP__
9010 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9011 static dispatch_queue_t etcq
= 0;
9012 static dispatch_source_t etcsrc
= 0;
9013 static dispatch_source_t hostssrc
= 0;
9015 // First time through? just schedule ourselves on the main queue and we'll do the work later
9018 etcq
= dispatch_get_main_queue();
9021 // Do this work on the queue, not here - solves potential synchronization issues
9022 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
9027 if (hostssrc
) return dispatch_source_get_handle(hostssrc
);
9030 int fd
= open("/etc/hosts", O_RDONLY
);
9032 #ifdef __DISPATCH_GROUP__
9033 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9036 // If the open failed and we're already watching /etc, we're done
9037 if (etcsrc
) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd
; }
9039 // we aren't watching /etc, we should be
9040 fd
= open("/etc", O_RDONLY
);
9041 if (fd
== -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
9042 etcsrc
= dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE
, fd
, DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_WRITE
| DISPATCH_VNODE_RENAME
, etcq
);
9048 dispatch_source_set_event_handler(etcsrc
,
9050 u_int32_t flags
= dispatch_source_get_data(etcsrc
);
9051 LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags
);
9052 if ((flags
& (DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_RENAME
)) != 0)
9054 dispatch_source_cancel(etcsrc
);
9055 dispatch_release(etcsrc
);
9057 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
9060 if ((flags
& DISPATCH_VNODE_WRITE
) != 0 && hostssrc
== NULL
)
9062 mDNSMacOSXUpdateEtcHosts(m
);
9065 dispatch_source_set_cancel_handler(etcsrc
, ^{close(fd
);});
9066 dispatch_resume(etcsrc
);
9068 // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
9069 fd
= open("/etc/hosts", O_RDONLY
| O_EVTONLY
);
9070 if (fd
== -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
9073 // create a dispatch source to watch for changes to hosts file
9074 hostssrc
= dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE
, fd
,
9075 (DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_WRITE
| DISPATCH_VNODE_RENAME
|
9076 DISPATCH_VNODE_ATTRIB
| DISPATCH_VNODE_EXTEND
| DISPATCH_VNODE_LINK
| DISPATCH_VNODE_REVOKE
), etcq
);
9077 if (hostssrc
== NULL
)
9082 dispatch_source_set_event_handler(hostssrc
,
9084 u_int32_t flags
= dispatch_source_get_data(hostssrc
);
9085 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags
);
9086 if ((flags
& (DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_RENAME
)) != 0)
9088 dispatch_source_cancel(hostssrc
);
9089 dispatch_release(hostssrc
);
9091 // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
9092 // the block immediately, we try to open the file and the file may not exist and may
9093 // fail to get a notification in the future. When the file does not exist and
9094 // we start to monitor the directory, on "dispatch_resume" of that source, there
9095 // is no guarantee that the file creation will be notified always because when
9096 // the dispatch_resume returns, the kevent manager may not have registered the
9097 // kevent yet but the file may have been created
9099 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
9102 if ((flags
& DISPATCH_VNODE_WRITE
) != 0)
9104 mDNSMacOSXUpdateEtcHosts(m
);
9107 dispatch_source_set_cancel_handler(hostssrc
, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd
); close(fd
);});
9108 dispatch_resume(hostssrc
);
9110 // Cleanup /etc source, no need to watch it if we already have /etc/hosts
9113 dispatch_source_cancel(etcsrc
);
9114 dispatch_release(etcsrc
);
9118 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
9119 return hostssrc
? (int)dispatch_source_get_handle(hostssrc
) : -1;
9126 // When /etc/hosts is modified, flush all the cache records as there may be local
9127 // authoritative answers now
9128 mDNSlocal
void FlushAllCacheRecords(mDNS
*const m
)
9134 FORALL_CACHERECORDS(slot
, cg
, cr
)
9137 if (cr
->resrec
.InterfaceID
) continue;
9139 // If a resource record can answer A or AAAA, they need to be flushed so that we will
9140 // never used to deliver an ADD or RMV
9141 if (RRTypeAnswersQuestionType(&cr
->resrec
, kDNSType_A
) ||
9142 RRTypeAnswersQuestionType(&cr
->resrec
, kDNSType_AAAA
))
9144 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m
, cr
));
9145 mDNS_PurgeCacheResourceRecord(m
, cr
);
9150 // Add new entries to the core. If justCheck is set, this function does not add, just returns true
9151 mDNSlocal mDNSBool
EtcHostsAddNewEntries(AuthHash
*newhosts
, mDNSBool justCheck
)
9153 mDNS
*const m
= &mDNSStorage
;
9156 AuthRecord
*rr
, *primary
, *rrnext
;
9157 for (slot
= 0; slot
< AUTH_HASH_SLOTS
; slot
++)
9158 for (ag
= newhosts
->rrauth_hash
[slot
]; ag
; ag
= ag
->next
)
9161 for (rr
= ag
->members
; rr
; rr
= rrnext
)
9166 mDNSBool found
= mDNSfalse
;
9167 ag1
= AuthGroupForRecord(&m
->rrauth
, &rr
->resrec
);
9168 if (ag1
&& ag1
->members
)
9170 if (!primary
) primary
= ag1
->members
;
9174 // We are not using InterfaceID in checking for duplicates. This means,
9175 // if there are two addresses for a given name e.g., fe80::1%en0 and
9176 // fe80::1%en1, we only add the first one. It is not clear whether
9177 // this is a common case. To fix this, we also need to modify
9178 // mDNS_Register_internal in how it handles duplicates. If it becomes a
9179 // common case, we will fix it then.
9180 if (IdenticalResourceRecord(&rr1
->resrec
, &rr
->resrec
))
9182 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m
, rr1
));
9193 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m
, rr
));
9196 RemoveAuthRecord(m
, newhosts
, rr
);
9197 // if there is no primary, point to self
9198 rr
->RRSet
= (primary
? primary
: rr
);
9200 LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m
, rr
));
9201 if (mDNS_Register_internal(m
, rr
) != mStatus_NoError
)
9202 LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m
, rr
));
9209 // Delete entries from the core that are no longer needed. If justCheck is set, this function
9210 // does not delete, just returns true
9211 mDNSlocal mDNSBool
EtcHostsDeleteOldEntries(AuthHash
*newhosts
, mDNSBool justCheck
)
9213 mDNS
*const m
= &mDNSStorage
;
9216 AuthRecord
*rr
, *rrnext
;
9217 for (slot
= 0; slot
< AUTH_HASH_SLOTS
; slot
++)
9218 for (ag
= m
->rrauth
.rrauth_hash
[slot
]; ag
; ag
= ag
->next
)
9219 for (rr
= ag
->members
; rr
; rr
= rrnext
)
9221 mDNSBool found
= mDNSfalse
;
9225 if (rr
->RecordCallback
!= FreeEtcHosts
) continue;
9226 ag1
= AuthGroupForRecord(newhosts
, &rr
->resrec
);
9232 if (IdenticalResourceRecord(&rr1
->resrec
, &rr
->resrec
))
9234 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m
, rr
));
9241 // there is no corresponding record in newhosts for the same name. This means
9242 // we should delete this from the core.
9247 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m
, rr
));
9250 // if primary is going away, make sure that the rest of the records
9251 // point to the new primary
9252 if (rr
== ag
->members
)
9254 AuthRecord
*new_primary
= rr
->next
;
9255 AuthRecord
*r
= new_primary
;
9260 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m
, r
));
9261 r
->RRSet
= new_primary
;
9263 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m
, r
), r
->resrec
.name
);
9267 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m
, rr
));
9268 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
9274 mDNSlocal
void UpdateEtcHosts(mDNS
*const m
, void *context
)
9276 AuthHash
*newhosts
= (AuthHash
*)context
;
9280 //Delete old entries from the core if they are not present in the newhosts
9281 EtcHostsDeleteOldEntries(newhosts
, mDNSfalse
);
9282 // Add the new entries to the core if not already present in the core
9283 EtcHostsAddNewEntries(newhosts
, mDNSfalse
);
9286 mDNSlocal
void FreeNewHosts(AuthHash
*newhosts
)
9289 AuthGroup
*ag
, *agnext
;
9290 AuthRecord
*rr
, *rrnext
;
9292 for (slot
= 0; slot
< AUTH_HASH_SLOTS
; slot
++)
9293 for (ag
= newhosts
->rrauth_hash
[slot
]; ag
; ag
= agnext
)
9296 for (rr
= ag
->members
; rr
; rr
= rrnext
)
9299 freeL("etchosts", rr
);
9301 freeL("AuthGroups", ag
);
9305 mDNSlocal
void mDNSMacOSXUpdateEtcHosts(mDNS
*const m
)
9309 // As we will be modifying the core, we can only have one thread running at
9310 // any point in time.
9313 mDNSPlatformMemZero(&newhosts
, sizeof(AuthHash
));
9315 // Get the file desecriptor (will trigger us to start watching for changes)
9316 int fd
= mDNSMacOSXGetEtcHostsFD();
9319 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd
);
9320 mDNSMacOSXParseEtcHosts(fd
, &newhosts
);
9322 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
9324 // Optimization: Detect whether /etc/hosts changed or not.
9326 // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
9327 // newhosts is already registered with core. If we find at least one entry that is not
9328 // registered with core, then it means we have work to do.
9330 // 2. Next, we check to see if any of the entries that are registered with core is not present
9331 // in newhosts. If we find at least one entry that is not present, it means we have work to
9334 // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
9335 // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
9336 // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
9337 // in the future and this code does not have to change.
9339 // Add the new entries to the core if not already present in the core
9340 if (!EtcHostsAddNewEntries(&newhosts
, mDNStrue
))
9342 // No new entries to add, check to see if we need to delete any old entries from the
9343 // core if they are not present in the newhosts
9344 if (!EtcHostsDeleteOldEntries(&newhosts
, mDNStrue
))
9346 LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
9347 FreeNewHosts(&newhosts
);
9349 KQueueUnlock("/etc/hosts changed");
9354 // This will flush the cache, stop and start the query so that the queries
9355 // can look at the /etc/hosts again
9359 // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
9360 // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
9361 // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
9362 // delivers these events in the right order and then calls us back to delete them.
9364 // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
9365 // is a common function that looks at all local auth records and delivers a RMV including
9366 // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
9367 // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
9368 // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
9369 // is called back where we do the Registration of the record. This results in RMV followed by ADD which
9371 mDNSCoreRestartAddressQueries(m
, mDNSfalse
, FlushAllCacheRecords
, UpdateEtcHosts
, &newhosts
);
9372 FreeNewHosts(&newhosts
);
9374 KQueueUnlock("/etc/hosts changed");
9377 #if COMPILER_LIKES_PRAGMA_MARK
9379 #pragma mark - Initialization & Teardown
9382 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
9383 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
9384 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
9385 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
9387 // Major version 13 is 10.9.x
9388 mDNSexport
void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
9390 int major
= 0, minor
= 0;
9391 char letter
= 0, prodname
[256]="<Unknown>", prodvers
[256]="<Unknown>", buildver
[256]="<Unknown>";
9392 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
9395 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
9396 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
9397 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
9399 CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
9401 CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
9402 if (cfbuildver
&& CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
))
9403 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
9409 LogMsg("Note: No Major Build Version number found; assuming 13");
9412 mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, STRINGIFY(mDNSResponderVersion
));
9413 //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
9415 // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
9416 if ((prodname
[0] & 0xDF) == 'M')
9422 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
9423 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
9424 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
9425 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
9428 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
9430 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
9433 struct sockaddr_in s5353
;
9434 s5353
.sin_family
= AF_INET
;
9435 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
9436 s5353
.sin_addr
.s_addr
= 0;
9437 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
9441 if (err
) LogMsg("No unicast UDP responses");
9442 else debugf("Unicast UDP responses okay");
9446 mDNSlocal
void CreatePTRRecord(const domainname
*domain
)
9449 const domainname
*pname
= (domainname
*)"\x9" "localhost";
9451 rr
= mallocL("localhosts", sizeof(*rr
));
9452 if (rr
== NULL
) return;
9453 mDNSPlatformMemZero(rr
, sizeof(*rr
));
9455 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, kHostNameTTL
, kDNSRecordTypeKnownUnique
, AuthRecordLocalOnly
, mDNSNULL
, mDNSNULL
);
9456 AssignDomainName(&rr
->namestorage
, domain
);
9458 rr
->resrec
.rdlength
= DomainNameLength(pname
);
9459 rr
->resrec
.rdata
->u
.name
.c
[0] = 0;
9460 AssignDomainName(&rr
->resrec
.rdata
->u
.name
, pname
);
9462 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
9463 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
9464 mDNS_Register(&mDNSStorage
, rr
);
9467 // Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
9468 // on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
9469 // fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
9470 // a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
9472 // Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
9473 // intentionally to avoid adding to the complexity of code handling /etc/hosts.
9474 mDNSlocal
void SetupLocalHostRecords(void)
9478 MakeDomainNameFromDNSNameString(&name
, "1.0.0.127.in-addr.arpa.");
9479 CreatePTRRecord(&name
);
9481 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.");
9482 CreatePTRRecord(&name
);
9485 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
9486 mDNSlocal
void setSameDomainLabelPointer(void);
9489 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
9490 // 1) query for b._dns-sd._udp.local on LocalOnly interface
9491 // (.local manually generated via explicit callback)
9492 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
9493 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
9494 // 4) result above should generate a callback from question in (1). result added to global list
9495 // 5) global list delivered to client via GetSearchDomainList()
9496 // 6) client calls to enumerate domains now go over LocalOnly interface
9497 // (!!!KRS may add outgoing interface in addition)
9499 #if TARGET_OS_IPHONE
9500 mDNSlocal mDNSBool
IsAppleInternalBuild(void)
9502 return (os_variant_has_internal_diagnostics("com.apple.mDNSResponder") ? mDNStrue
: mDNSfalse
);
9505 mDNSlocal mStatus
RegisterLocalOnlyAddressRecord(const domainname
*const name
, mDNSu16 type
, const void *rdata
, mDNSu16 rdlength
)
9510 if (rdlength
!= 4) return (mStatus_BadParamErr
);
9514 if (rdlength
!= 16) return (mStatus_BadParamErr
);
9518 return (mStatus_BadParamErr
);
9521 AuthRecord
*rr
= mallocL("etchosts", sizeof(*rr
));
9522 if (!rr
) return (mStatus_NoMemoryErr
);
9523 mDNSPlatformMemZero(rr
, sizeof(*rr
));
9525 mDNS_SetupResourceRecord(rr
, NULL
, mDNSInterface_LocalOnly
, type
, 1, kDNSRecordTypeKnownUnique
, AuthRecordLocalOnly
, FreeEtcHosts
, NULL
);
9526 AssignDomainName(&rr
->namestorage
, name
);
9527 mDNSPlatformMemCopy(rr
->resrec
.rdata
->u
.data
, rdata
, rdlength
);
9529 const mStatus err
= mDNS_Register_internal(&mDNSStorage
, rr
);
9532 LogMsg("RegisterLocalOnlyAddressRecord: mDNS_Register error %d registering %s", err
, ARDisplayString(&mDNSStorage
, rr
));
9533 freeL("etchosts", rr
);
9538 mDNSlocal
void RegisterLocalOnlyARecord(const domainname
*const name
, const mDNSv4Addr
*const addr
)
9540 RegisterLocalOnlyAddressRecord(name
, kDNSType_A
, addr
->b
, (mDNSu16
)sizeof(mDNSv4Addr
));
9543 mDNSlocal
void RegisterLocalOnlyAAAARecord(const domainname
*const name
, const mDNSv6Addr
*const addr
)
9545 RegisterLocalOnlyAddressRecord(name
, kDNSType_AAAA
, addr
->b
, (mDNSu16
)sizeof(mDNSv6Addr
));
9549 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
9553 char HINFO_SWstring
[256] = "";
9554 mDNSMacOSXSystemBuildNumber(HINFO_SWstring
);
9556 #if APPLE_OSX_mDNSResponder
9557 setSameDomainLabelPointer();
9560 err
= mDNSHelperInit();
9564 // Store mDNSResponder Platform
9567 m
->mDNS_plat
= platform_OSX
;
9572 m
->mDNS_plat
= platform_Atv
;
9574 m
->mDNS_plat
= platform_iOS
;
9578 m
->mDNS_plat
= platform_NonApple
;
9581 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
9582 // 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.
9584 for (i
=0; i
<100; i
++)
9586 domainlabel testlabel
;
9588 GetUserSpecifiedLocalHostName(&testlabel
);
9589 if (testlabel
.c
[0]) break;
9593 m
->hostlabel
.c
[0] = 0;
9595 int get_model
[2] = { CTL_HW
, HW_MODEL
};
9596 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
9598 // Normal Apple model names are of the form "iPhone2,1", and
9599 // internal code names are strings containing no commas, e.g. "N88AP".
9600 // We used to ignore internal code names, but Apple now uses these internal code names
9601 // even in released shipping products, so we no longer ignore strings containing no commas.
9602 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
9603 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
9604 HINFO_HWstring
= HINFO_HWstring_buffer
;
9606 // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
9607 // For names of the form "N88AP" containg no comma, we use the entire string.
9608 HINFO_HWstring_prefixlen
= strchr(HINFO_HWstring_buffer
, ',') ? strcspn(HINFO_HWstring
, "0123456789") : strlen(HINFO_HWstring
);
9610 if (mDNSPlatformInit_CanReceiveUnicast())
9611 m
->CanReceiveUnicastOn5353
= mDNStrue
;
9613 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
9614 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
9615 if (hlen
+ slen
< 254)
9617 m
->HIHardware
.c
[0] = hlen
;
9618 m
->HISoftware
.c
[0] = slen
;
9619 mDNSPlatformMemCopy(&m
->HIHardware
.c
[1], HINFO_HWstring
, hlen
);
9620 mDNSPlatformMemCopy(&m
->HISoftware
.c
[1], HINFO_SWstring
, slen
);
9623 m
->p
->permanentsockets
.port
= MulticastDNSPort
;
9624 m
->p
->permanentsockets
.m
= m
;
9625 m
->p
->permanentsockets
.sktv4
= -1;
9626 m
->p
->permanentsockets
.kqsv4
.KQcallback
= myKQSocketCallBack
;
9627 m
->p
->permanentsockets
.kqsv4
.KQcontext
= &m
->p
->permanentsockets
;
9628 m
->p
->permanentsockets
.kqsv4
.KQtask
= "IPv4 UDP packet reception";
9629 m
->p
->permanentsockets
.sktv6
= -1;
9630 m
->p
->permanentsockets
.kqsv6
.KQcallback
= myKQSocketCallBack
;
9631 m
->p
->permanentsockets
.kqsv6
.KQcontext
= &m
->p
->permanentsockets
;
9632 m
->p
->permanentsockets
.kqsv6
.KQtask
= "IPv6 UDP packet reception";
9634 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET
, mDNSNULL
);
9635 if (err
) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET) failed error %d errno %d (%s)", err
, errno
, strerror(errno
));
9636 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET6
, mDNSNULL
);
9637 if (err
) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET6) failed error %d errno %d (%s)", err
, errno
, strerror(errno
));
9639 struct sockaddr_in s4
;
9640 socklen_t n4
= sizeof(s4
);
9641 if (getsockname(m
->p
->permanentsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0)
9642 LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
9644 m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
9646 if (m
->p
->permanentsockets
.sktv6
>= 0)
9648 struct sockaddr_in6 s6
;
9649 socklen_t n6
= sizeof(s6
);
9650 if (getsockname(m
->p
->permanentsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
9651 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
9654 m
->p
->InterfaceList
= mDNSNULL
;
9655 m
->p
->userhostlabel
.c
[0] = 0;
9656 m
->p
->usernicelabel
.c
[0] = 0;
9657 m
->p
->prevoldnicelabel
.c
[0] = 0;
9658 m
->p
->prevnewnicelabel
.c
[0] = 0;
9659 m
->p
->prevoldhostlabel
.c
[0] = 0;
9660 m
->p
->prevnewhostlabel
.c
[0] = 0;
9661 m
->p
->NotifyUser
= 0;
9662 m
->p
->KeyChainTimer
= 0;
9663 m
->p
->WakeAtUTC
= 0;
9664 m
->p
->RequestReSleep
= 0;
9665 // Assume that everything is good to begin with. If something is not working,
9666 // we will detect that when we start sending questions.
9667 m
->p
->v4answers
= 1;
9668 m
->p
->v6answers
= 1;
9669 m
->p
->DNSTrigger
= 0;
9670 m
->p
->LastConfigGeneration
= 0;
9672 m
->AutoTunnelRelayAddr
= zerov6Addr
;
9674 NetworkChangedKey_IPv4
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
9675 NetworkChangedKey_IPv6
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
9676 NetworkChangedKey_Hostnames
= SCDynamicStoreKeyCreateHostNames(NULL
);
9677 NetworkChangedKey_Computername
= SCDynamicStoreKeyCreateComputerName(NULL
);
9678 NetworkChangedKey_DNS
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
9679 NetworkChangedKey_StateInterfacePrefix
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, CFSTR(""), NULL
);
9680 if (!NetworkChangedKey_IPv4
|| !NetworkChangedKey_IPv6
|| !NetworkChangedKey_Hostnames
|| !NetworkChangedKey_Computername
|| !NetworkChangedKey_DNS
|| !NetworkChangedKey_StateInterfacePrefix
)
9681 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr
); }
9683 err
= WatchForNetworkChanges(m
);
9684 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err
); return(err
); }
9686 err
= WatchForSysEvents(m
);
9687 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err
); return(err
); }
9689 mDNSs32 utc
= mDNSPlatformUTC();
9690 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
9692 UpdateInterfaceList(utc
);
9693 SetupActiveInterfaces(utc
);
9694 ReorderInterfaceList();
9696 // Explicitly ensure that our Keychain operations utilize the system domain.
9697 #ifndef NO_SECURITYFRAMEWORK
9698 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
9702 SetDomainSecrets(m
);
9706 #ifndef NO_SECURITYFRAMEWORK
9707 err
= SecKeychainAddCallback(KeychainChanged
, kSecAddEventMask
|kSecDeleteEventMask
|kSecUpdateEventMask
, m
);
9708 if (err
) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err
); return(err
); }
9711 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
9712 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
9715 IOReturn iopmerr
= IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU
, &c
);
9716 if (iopmerr
) LogMsg("IOPMConnectionCreate failed %d", iopmerr
);
9719 iopmerr
= IOPMConnectionSetNotification(c
, m
, SnowLeopardPowerChanged
);
9720 if (iopmerr
) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr
);
9723 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9724 IOPMConnectionSetDispatchQueue(c
, dispatch_get_main_queue());
9725 LogInfo("IOPMConnectionSetDispatchQueue is now running");
9727 iopmerr
= IOPMConnectionScheduleWithRunLoop(c
, CFRunLoopGetMain(), kCFRunLoopDefaultMode
);
9728 if (iopmerr
) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr
);
9729 LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
9730 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9733 m
->p
->IOPMConnection
= iopmerr
? mDNSNULL
: c
;
9734 if (iopmerr
) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
9735 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
9737 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &m
->p
->PowerPortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
9738 if (!m
->p
->PowerConnection
) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
9741 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9742 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, dispatch_get_main_queue());
9744 CFRunLoopAddSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
9745 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9749 #if APPLE_OSX_mDNSResponder
9750 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
9751 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
9752 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
9753 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
9754 if (!strncasecmp(HINFO_HWstring
, "Xserve", 6)) { SPMetricPortability
= 25 /* 30kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
9755 else if (!strncasecmp(HINFO_HWstring
, "RackMac", 7)) { SPMetricPortability
= 25 /* 30kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
9756 else if (!strncasecmp(HINFO_HWstring
, "MacPro", 6)) { SPMetricPortability
= 27 /* 20kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
9757 else if (!strncasecmp(HINFO_HWstring
, "PowerMac", 8)) { SPMetricPortability
= 27 /* 20kg */; SPMetricMarginalPower
= 82 /* 160W */; SPMetricTotalPower
= 83 /* 200W */; }
9758 else if (!strncasecmp(HINFO_HWstring
, "iMac", 4)) { SPMetricPortability
= 30 /* 10kg */; SPMetricMarginalPower
= 77 /* 50W */; SPMetricTotalPower
= 78 /* 60W */; }
9759 else if (!strncasecmp(HINFO_HWstring
, "Macmini", 7)) { SPMetricPortability
= 33 /* 5kg */; SPMetricMarginalPower
= 73 /* 20W */; SPMetricTotalPower
= 74 /* 25W */; }
9760 else if (!strncasecmp(HINFO_HWstring
, "TimeCapsule", 11)) { SPMetricPortability
= 34 /* 4kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 70 /* 13W */; }
9761 else if (!strncasecmp(HINFO_HWstring
, "AirPort", 7)) { SPMetricPortability
= 35 /* 3kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 70 /* 12W */; }
9762 else if ( IsAppleTV() ) { SPMetricPortability
= 35 /* 3kg */; SPMetricMarginalPower
= 60 /* 1W */; SPMetricTotalPower
= 63 /* 2W */; }
9763 else if (!strncasecmp(HINFO_HWstring
, "MacBook", 7)) { SPMetricPortability
= 37 /* 2kg */; SPMetricMarginalPower
= 71 /* 13W */; SPMetricTotalPower
= 72 /* 15W */; }
9764 else if (!strncasecmp(HINFO_HWstring
, "PowerBook", 9)) { SPMetricPortability
= 37 /* 2kg */; SPMetricMarginalPower
= 71 /* 13W */; SPMetricTotalPower
= 72 /* 15W */; }
9765 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
9766 HINFO_HWstring_prefixlen
, HINFO_HWstring
, HINFO_HWstring
, SPMetricPortability
, SPMetricMarginalPower
, SPMetricTotalPower
, SPMetricFeatures
);
9767 #endif // APPLE_OSX_mDNSResponder
9769 // Currently this is not defined. SSL code will eventually fix this. If it becomes
9770 // critical, we will define this to workaround the bug in SSL.
9771 #ifdef __SSL_NEEDS_SERIALIZATION__
9772 SSLqueue
= dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL
);
9774 SSLqueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
9776 if (SSLqueue
== mDNSNULL
) LogMsg("dispatch_queue_create: SSL queue NULL");
9778 #if TARGET_OS_IPHONE
9779 // On device OSes (iOS, tvOS, watchOS, etc.), ignore /etc/hosts unless the OS is an internal build. When the /etc/hosts
9780 // file is ignored, LocalOnly auth records will be registered for localhost and broadcasthost addresses contained in the
9781 // standard /etc/hosts file:
9783 // 127.0.0.1 localhost
9784 // 255.255.255.255 broadcasthost
9787 if (!IsAppleInternalBuild())
9789 const domainname
*const localHostName
= (const domainname
*) "\x9" "localhost";
9790 const domainname
*const broadcastHostName
= (const domainname
*) "\xd" "broadcasthost";
9791 const mDNSv4Addr localHostV4
= { { 127, 0, 0, 1 } };
9792 mDNSv6Addr localHostV6
;
9794 // Register localhost 127.0.0.1 A record.
9796 RegisterLocalOnlyARecord(localHostName
, &localHostV4
);
9798 // Register broadcasthost 255.255.255.255 A record.
9800 RegisterLocalOnlyARecord(broadcastHostName
, &onesIPv4Addr
);
9802 // Register localhost ::1 AAAA record.
9804 mDNSPlatformMemZero(&localHostV6
, sizeof(localHostV6
));
9805 localHostV6
.b
[15] = 1;
9806 RegisterLocalOnlyAAAARecord(localHostName
, &localHostV6
);
9811 mDNSMacOSXUpdateEtcHosts(m
);
9813 SetupLocalHostRecords();
9815 return(mStatus_NoError
);
9818 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
9821 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
9824 // Adding interfaces will use this flag, so set it now.
9825 m
->DivertMulticastAdvertisements
= !m
->AdvertiseLocalAddresses
;
9827 #if APPLE_OSX_mDNSResponder
9828 m
->SPSBrowseCallback
= UpdateSPSStatus
;
9829 #endif // APPLE_OSX_mDNSResponder
9831 mStatus result
= mDNSPlatformInit_setup(m
);
9833 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
9834 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
9835 if (result
== mStatus_NoError
)
9837 mDNSCoreInitComplete(m
, mStatus_NoError
);
9838 initializeD2DPlugins(m
);
9840 result
= DNSSECCryptoInit(m
);
9844 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
9846 if (m
->p
->PowerConnection
)
9848 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9849 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, NULL
);
9851 CFRunLoopRemoveSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
9853 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
9854 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
9855 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
9856 IOServiceClose ( m
->p
->PowerConnection
);
9857 IONotificationPortDestroy ( m
->p
->PowerPortRef
);
9858 m
->p
->PowerConnection
= 0;
9863 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9864 if (!SCDynamicStoreSetDispatchQueue(m
->p
->Store
, NULL
))
9865 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
9867 CFRunLoopRemoveSource(CFRunLoopGetMain(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
9868 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
9869 CFRelease(m
->p
->StoreRLS
);
9870 m
->p
->StoreRLS
= NULL
;
9872 CFRelease(m
->p
->Store
);
9878 CFRunLoopRemoveSource(CFRunLoopGetMain(), m
->p
->PMRLS
, kCFRunLoopDefaultMode
);
9879 CFRunLoopSourceInvalidate(m
->p
->PMRLS
);
9880 CFRelease(m
->p
->PMRLS
);
9884 if (m
->p
->SysEventNotifier
>= 0) { close(m
->p
->SysEventNotifier
); m
->p
->SysEventNotifier
= -1; }
9886 terminateD2DPlugins();
9888 mDNSs32 utc
= mDNSPlatformUTC();
9889 MarkAllInterfacesInactive(utc
);
9890 ClearInactiveInterfaces(utc
);
9891 CloseSocketSet(&m
->p
->permanentsockets
);
9893 #if APPLE_OSX_mDNSResponder
9895 while (m
->TunnelClients
)
9897 ClientTunnel
*cur
= m
->TunnelClients
;
9898 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur
, cur
->dstname
.c
);
9899 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
9900 AutoTunnelSetKeys(cur
, mDNSfalse
);
9901 m
->TunnelClients
= cur
->next
;
9902 freeL("ClientTunnel", cur
);
9905 if (AnonymousRacoonConfig
)
9907 AnonymousRacoonConfig
= mDNSNULL
;
9908 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel need not be done in mDNSResponder");
9910 #endif // APPLE_OSX_mDNSResponder
9913 #if COMPILER_LIKES_PRAGMA_MARK
9915 #pragma mark - General Platform Support Layer functions
9918 mDNSexport mDNSu32
mDNSPlatformRandomNumber(void)
9920 return(arc4random());
9923 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
9924 mDNSexport mDNSu32 mDNSPlatformClockDivisor
= 0;
9926 mDNSexport mStatus
mDNSPlatformTimeInit(void)
9928 // Notes: Typical values for mach_timebase_info:
9929 // tbi.numer = 1000 million
9930 // tbi.denom = 33 million
9931 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
9932 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
9933 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
9934 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
9935 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
9937 // Arithmetic notes:
9938 // tbi.denom is at least 1, and not more than 2^32-1.
9939 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
9940 // tbi.denom is at least 1, and not more than 2^32-1.
9941 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
9942 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
9943 // which is unlikely on any current or future Macintosh.
9944 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
9945 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
9946 struct mach_timebase_info tbi
;
9947 kern_return_t result
= mach_timebase_info(&tbi
);
9948 if (result
== KERN_SUCCESS
) mDNSPlatformClockDivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
9952 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
9954 if (mDNSPlatformClockDivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
9956 static uint64_t last_mach_absolute_time
= 0;
9957 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
9958 uint64_t this_mach_absolute_time
= mach_absolute_time();
9959 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
9961 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
9962 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
9963 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
9964 last_mach_absolute_time
= this_mach_absolute_time
;
9965 // Note: This bug happens all the time on 10.3
9966 NotifyOfElusiveBug("mach_absolute_time went backwards!",
9967 "This error occurs from time to time, often on newly released hardware, "
9968 "and usually the exact cause is different in each instance.\r\r"
9969 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
9970 "and assign it to Radar Component “Kernel” Version “X”.");
9972 last_mach_absolute_time
= this_mach_absolute_time
;
9974 return((mDNSs32
)(this_mach_absolute_time
/ mDNSPlatformClockDivisor
));
9977 mDNSexport mDNSs32
mDNSPlatformUTC(void)
9982 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
9983 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
9984 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
9985 mDNSexport
void mDNSPlatformStrCopy( void *dst
, const void *src
) { strcpy((char *)dst
, (const char *)src
); }
9986 mDNSexport mDNSu32
mDNSPlatformStrLCopy( void *dst
, const void *src
, mDNSu32 dstlen
) { return (strlcpy((char *)dst
, (const char *)src
, dstlen
)); }
9987 mDNSexport mDNSu32
mDNSPlatformStrLen ( const void *src
) { return(strlen((const char*)src
)); }
9988 mDNSexport
void mDNSPlatformMemCopy( void *dst
, const void *src
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
9989 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *dst
, const void *src
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
9990 mDNSexport
int mDNSPlatformMemCmp(const void *dst
, const void *src
, mDNSu32 len
) { return(memcmp(dst
, src
, len
)); }
9991 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { memset(dst
, 0, len
); }
9992 mDNSexport
void mDNSPlatformQsort ( void *base
, int nel
, int width
, int (*compar
)(const void *, const void *))
9994 return (qsort(base
, nel
, width
, compar
));
9996 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
9997 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
9999 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }
10001 mDNSexport
void mDNSPlatformSetAllowSleep(mDNSBool allowSleep
, const char *reason
)
10003 mDNS
*const m
= &mDNSStorage
;
10004 if (allowSleep
&& m
->p
->IOPMAssertion
)
10006 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__
);
10007 IOPMAssertionRelease(m
->p
->IOPMAssertion
);
10008 m
->p
->IOPMAssertion
= 0;
10010 else if (!allowSleep
)
10012 #ifdef kIOPMAssertionTypeNoIdleSleep
10013 if (m
->p
->IOPMAssertion
)
10015 IOPMAssertionRelease(m
->p
->IOPMAssertion
);
10016 m
->p
->IOPMAssertion
= 0;
10019 CFStringRef assertionName
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s.%d %s"), getprogname(), getpid(), reason
? reason
: "");
10020 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep
, kIOPMAssertionLevelOn
, assertionName
? assertionName
: CFSTR("mDNSResponder"), &m
->p
->IOPMAssertion
);
10021 if (assertionName
) CFRelease(assertionName
);
10022 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__
);
10027 mDNSexport
void mDNSPlatformPreventSleep(mDNSu32 timeout
, const char *reason
)
10029 mDNS
*const m
= &mDNSStorage
;
10030 if (m
->p
->IOPMAssertion
)
10032 LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout
, reason
);
10035 #ifdef kIOPMAssertionTypeNoIdleSleep
10037 #if TARGET_OS_EMBEDDED
10039 return; // No need for maintenance wakes on non-AppleTV embedded devices.
10042 double timeoutVal
= (double)timeout
;
10043 CFStringRef str
= CFStringCreateWithCString(NULL
, reason
, kCFStringEncodingUTF8
);
10044 CFNumberRef Timeout_num
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &timeoutVal
);
10045 CFMutableDictionaryRef assertionProperties
= CFDictionaryCreateMutable(NULL
, 0,
10046 &kCFTypeDictionaryKeyCallBacks
,
10047 &kCFTypeDictionaryValueCallBacks
);
10049 CFDictionarySetValue(assertionProperties
, kIOPMAssertionTypeKey
, kIOPMAssertPreventUserIdleSystemSleep
);
10051 CFDictionarySetValue(assertionProperties
, kIOPMAssertionTypeKey
, kIOPMAssertMaintenanceActivity
);
10053 CFDictionarySetValue(assertionProperties
, kIOPMAssertionTimeoutKey
, Timeout_num
);
10054 CFDictionarySetValue(assertionProperties
, kIOPMAssertionNameKey
, str
);
10056 IOPMAssertionCreateWithProperties(assertionProperties
, (IOPMAssertionID
*)&m
->p
->IOPMAssertion
);
10058 CFRelease(Timeout_num
);
10059 CFRelease(assertionProperties
);
10060 LogSPS("Got an idle sleep assertion for %d seconds for %s", timeout
, reason
);
10064 mDNSexport
void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID
, char *EthAddr
, char *IPAddr
, int iteration
)
10069 ifindex
= mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage
, InterfaceID
, mDNStrue
);
10072 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex
);
10075 mDNSSendWakeupPacket(ifindex
, EthAddr
, IPAddr
, iteration
);
10078 mDNSexport mDNSBool
mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID
)
10080 NetworkInterfaceInfoOSX
*info
;
10082 if (InterfaceID
== mDNSInterface_P2P
)
10085 // mDNSInterface_BLE not considered a D2D interface for the purpose of this
10086 // routine, since it's not implemented via a D2D plugin.
10087 if (InterfaceID
== mDNSInterface_BLE
)
10090 if ( (InterfaceID
== mDNSInterface_Any
)
10091 || (InterfaceID
== mDNSInterfaceMark
)
10092 || (InterfaceID
== mDNSInterface_LocalOnly
)
10093 || (InterfaceID
== mDNSInterface_Unicast
))
10096 // Compare to cached AWDL interface ID.
10097 if (AWDLInterfaceID
&& (InterfaceID
== AWDLInterfaceID
))
10100 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
10103 // this log message can print when operations are stopped on an interface that has gone away
10104 LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID
);
10108 return (mDNSBool
) info
->D2DInterface
;
10111 // Filter records send over P2P (D2D) type interfaces
10112 // Note that the terms P2P and D2D are used synonymously in the current code and comments.
10113 mDNSexport mDNSBool
mDNSPlatformValidRecordForInterface(const AuthRecord
*rr
, mDNSInterfaceID InterfaceID
)
10115 // For an explicit match to a valid interface ID, return true.
10116 if (rr
->resrec
.InterfaceID
== InterfaceID
)
10119 // Only filtering records for D2D type interfaces, return true for all other interface types.
10120 if (!mDNSPlatformInterfaceIsD2D(InterfaceID
))
10123 // If it's an AWDL interface the record must be explicitly marked to include AWDL.
10124 if (InterfaceID
== AWDLInterfaceID
)
10126 if (rr
->ARType
== AuthRecordAnyIncludeAWDL
|| rr
->ARType
== AuthRecordAnyIncludeAWDLandP2P
)
10132 // Send record if it is explicitly marked to include all other P2P type interfaces.
10133 if (rr
->ARType
== AuthRecordAnyIncludeP2P
|| rr
->ARType
== AuthRecordAnyIncludeAWDLandP2P
)
10136 // Don't send the record over this interface.
10140 // Filter questions send over P2P (D2D) type interfaces.
10141 mDNSexport mDNSBool
mDNSPlatformValidQuestionForInterface(DNSQuestion
*q
, const NetworkInterfaceInfo
*intf
)
10143 // For an explicit match to a valid interface ID, return true.
10144 if (q
->InterfaceID
== intf
->InterfaceID
)
10147 // Only filtering questions for D2D type interfaces
10148 if (!mDNSPlatformInterfaceIsD2D(intf
->InterfaceID
))
10151 // If it's an AWDL interface the question must be explicitly marked to include AWDL.
10152 if (intf
->InterfaceID
== AWDLInterfaceID
)
10154 if (q
->flags
& kDNSServiceFlagsIncludeAWDL
)
10160 // Sent question if it is explicitly marked to include all other P2P type interfaces.
10161 if (q
->flags
& kDNSServiceFlagsIncludeP2P
)
10164 // Don't send the question over this interface.
10168 // Returns true unless record was received over the AWDL interface and
10169 // the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
10170 // with the kDNSServiceFlagsIncludeAWDL flag set.
10171 mDNSexport mDNSBool
mDNSPlatformValidRecordForQuestion(const ResourceRecord
*const rr
, const DNSQuestion
*const q
)
10173 if (!rr
->InterfaceID
|| (rr
->InterfaceID
== q
->InterfaceID
))
10176 if ((rr
->InterfaceID
== AWDLInterfaceID
) && !(q
->flags
& kDNSServiceFlagsIncludeAWDL
))
10182 // formating time to RFC 4034 format
10183 mDNSexport
void mDNSPlatformFormatTime(unsigned long te
, mDNSu8
*buf
, int bufsize
)
10186 time_t t
= (time_t)te
;
10187 // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
10188 // gmtime_r first and then use strftime
10189 gmtime_r(&t
, &tmTime
);
10190 strftime((char *)buf
, bufsize
, "%Y%m%d%H%M%S", &tmTime
);
10193 mDNSexport mDNSs32
mDNSPlatformGetPID()
10198 // Schedule a function asynchronously on the main queue
10199 mDNSexport
void mDNSPlatformDispatchAsync(mDNS
*const m
, void *context
, AsyncDispatchFunc func
)
10201 // KQueueLock/Unlock is used for two purposes
10203 // 1. We can't be running along with the KQueue thread and hence acquiring the lock
10204 // serializes the access to the "core"
10206 // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
10207 // up and calls udsserver_idle which schedules the messages across the uds socket.
10208 // If "func" delivers something to the uds socket from the dispatch thread, it will
10209 // not be delivered immediately if not for the Unlock.
10210 dispatch_async(dispatch_get_main_queue(), ^{
10213 KQueueUnlock("mDNSPlatformDispatchAsync");
10214 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10215 // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
10216 // to handle any message that "func" might deliver.
10217 TriggerEventCompletion();
10222 // definitions for device-info record construction
10223 #define DEVINFO_MODEL "model="
10224 #define DEVINFO_MODEL_LEN sizeof_string(DEVINFO_MODEL)
10226 #define OSX_VER "osxvers="
10227 #define OSX_VER_LEN sizeof_string(OSX_VER)
10228 #define VER_NUM_LEN 2 // 2 digits of version number added to base string
10230 #define MODEL_COLOR "ecolor="
10231 #define MODEL_COLOR_LEN sizeof_string(MODEL_COLOR)
10232 #define MODEL_RGB_VALUE_LEN sizeof_string("255,255,255") // 'r,g,b'
10234 // Bytes available in TXT record for model name after subtracting space for other
10235 // fixed size strings and their length bytes.
10236 #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))
10238 mDNSlocal mDNSu8
getModelIconColors(char *color
)
10240 mDNSPlatformMemZero(color
, MODEL_RGB_VALUE_LEN
+ 1);
10242 #if !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10247 IOReturn rGetDeviceColor
= IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey
,
10248 &red
, &green
, &blue
);
10249 if (kIOReturnSuccess
== rGetDeviceColor
)
10251 // IOKit was able to get enclosure color for the current device.
10252 return snprintf(color
, MODEL_RGB_VALUE_LEN
+ 1, "%d,%d,%d", red
, green
, blue
);
10254 #endif // !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10260 // Initialize device-info TXT record contents and return total length of record data.
10261 mDNSexport mDNSu32
initializeDeviceInfoTXT(mDNS
*m
, mDNSu8
*ptr
)
10263 mDNSu8
*bufferStart
= ptr
;
10264 mDNSu8 len
= m
->HIHardware
.c
[0] < MAX_MODEL_NAME_LEN
? m
->HIHardware
.c
[0] : MAX_MODEL_NAME_LEN
;
10266 *ptr
= DEVINFO_MODEL_LEN
+ len
; // total length of DEVINFO_MODEL string plus the hardware name string
10268 mDNSPlatformMemCopy(ptr
, DEVINFO_MODEL
, DEVINFO_MODEL_LEN
);
10269 ptr
+= DEVINFO_MODEL_LEN
;
10270 mDNSPlatformMemCopy(ptr
, m
->HIHardware
.c
+ 1, len
);
10273 // only include this string for OSX
10276 char ver_num
[VER_NUM_LEN
+ 1]; // version digits + null written by snprintf
10277 *ptr
= OSX_VER_LEN
+ VER_NUM_LEN
; // length byte
10279 mDNSPlatformMemCopy(ptr
, OSX_VER
, OSX_VER_LEN
);
10280 ptr
+= OSX_VER_LEN
;
10281 // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
10282 // WARNING: This code assumes that OSXVers is always exactly two digits
10283 snprintf(ver_num
, VER_NUM_LEN
+ 1, "%d", OSXVers
);
10284 mDNSPlatformMemCopy(ptr
, ver_num
, VER_NUM_LEN
);
10285 ptr
+= VER_NUM_LEN
;
10287 char rgb
[MODEL_RGB_VALUE_LEN
+ 1]; // RGB value + null written by snprintf
10288 len
= getModelIconColors(rgb
);
10291 *ptr
= MODEL_COLOR_LEN
+ len
; // length byte
10294 mDNSPlatformMemCopy(ptr
, MODEL_COLOR
, MODEL_COLOR_LEN
);
10295 ptr
+= MODEL_COLOR_LEN
;
10297 mDNSPlatformMemCopy(ptr
, rgb
, len
);
10302 return (ptr
- bufferStart
);
10305 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
10307 // Use the scalar version of SameDomainLabel() by default
10308 mDNSlocal mDNSBool
scalarSameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
);
10309 mDNSlocal mDNSBool
vectorSameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
);
10310 mDNSlocal
mDNSBool (*SameDomainLabelPointer
)(const mDNSu8
*a
, const mDNSu8
*b
) = scalarSameDomainLabel
;
10312 #include <System/machine/cpu_capabilities.h>
10313 #define _cpu_capabilities ((uint32_t*) _COMM_PAGE_CPU_CAPABILITIES)[0]
10315 #if TARGET_OS_EMBEDDED
10317 #include <arm_neon.h>
10319 // Cache line aligned table that returns 32 for the upper case letters.
10320 // This will take up 4 cache lines.
10321 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table
[256] = {
10322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10326 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
10327 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
10328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10330 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10331 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10332 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10333 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10335 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10336 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10337 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
10341 mDNSlocal mDNSBool
vectorSameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
10343 const int len
= *a
++;
10345 if (len
> MAX_DOMAIN_LABEL
)
10347 fprintf(stderr
, "v: Malformed label (too long)\n");
10356 uint32_t len_count
= len
;
10358 uint8x16_t vA
, vB
, vARotated
, vBRotated
, vMaskA
, vMaskB
;
10360 uint8x16_t v32
= vdupq_n_u8(32);
10361 uint8x16_t v37
= vdupq_n_u8(37);
10362 uint8x16_t v101
= vdupq_n_u8(101);
10363 #if !defined __arm64__
10364 uint32x4_t vtemp32
;
10365 uint32x2_t vtemp32d
;
10369 while(len_count
> 15)
10376 //Make vA to lowercase if there is any uppercase.
10377 vARotated
= vaddq_u8(vA
, v37
); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10378 vMaskA
= vcgtq_s8(vARotated
, v101
); //Check if anything is greater than '101' which means we have uppercase letters.
10379 vMaskA
= vandq_u8(vMaskA
, v32
); //Prepare 32 for the elements with uppercase letters.
10380 vA
= vaddq_u8(vA
, vMaskA
); //Add 32 only to the uppercase letters to make them lowercase letters.
10382 //Make vB to lowercase if there is any uppercase.
10383 vBRotated
= vaddq_u8(vB
, v37
); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10384 vMaskB
= vcgtq_s8(vBRotated
, v101
); //Check if anything is greater than '101' which means we have uppercase letters.
10385 vMaskB
= vandq_u8(vMaskB
, v32
); //Prepare 32 for the elements with uppercase letters.
10386 vB
= vaddq_u8(vB
, vMaskB
); //Add 32 only to the uppercase letters to make them lowercase letters.
10389 vA
= vceqq_u8(vA
, vB
);
10391 #if defined __arm64__
10392 //View 8-bit element as 32-bit => a3 a2 a1 a0
10393 //If min of 4 32-bit values in vA is 0xffffffff, then it means we have 0xff for all 16.
10394 if(vminvq_u32(vA
) != 0xffffffffU
)
10400 //See if any element was not same.
10401 //View 8-bit element as 16-bit => a7 a6 a5 a4 a3 a2 a1 a0
10402 //(a7+a6) (a5+a4) (a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
10403 vtemp32
= vpaddlq_u16(vA
);
10404 vtemp32d
= vpadd_u32(vget_low_u32(vtemp32
), vget_high_u32(vtemp32
));
10405 vtemp32d
= vpadd_u32(vtemp32d
, vtemp32d
);
10406 sum
= vget_lane_u32(vtemp32d
, 0);
10408 //0x0001fffe + 0x0001fffe + 0x0001fffe + 0x0001fffe = 0x0007fff8U when all same.
10409 if(sum
!= 0x0007fff8U
)
10418 uint8x8_t vAd
, vBd
, vARotatedd
, vBRotatedd
, vMaskAd
, vMaskBd
;
10420 uint8x8_t v32d
= vdup_n_u8(32);
10421 uint8x8_t v37d
= vdup_n_u8(37);
10422 uint8x8_t v101d
= vdup_n_u8(101);
10424 while(len_count
> 7)
10431 //Make vA to lowercase if there is any uppercase.
10432 vARotatedd
= vadd_u8(vAd
, v37d
); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10433 vMaskAd
= vcgt_s8(vARotatedd
, v101d
); //Check if anything is greater than '101' which means we have uppercase letters.
10434 vMaskAd
= vand_u8(vMaskAd
, v32d
); //Prepare 32 for the elements with uppercase letters.
10435 vAd
= vadd_u8(vAd
, vMaskAd
); //Add 32 only to the uppercase letters to make them lowercase letters.
10437 //Make vB to lowercase if there is any uppercase.
10438 vBRotatedd
= vadd_u8(vBd
, v37d
); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10439 vMaskBd
= vcgt_s8(vBRotatedd
, v101d
); //Check if anything is greater than '101' which means we have uppercase letters.
10440 vMaskBd
= vand_u8(vMaskBd
, v32d
); //Prepare 32 for the elements with uppercase letters.
10441 vBd
= vadd_u8(vBd
, vMaskBd
); //Add 32 only to the uppercase letters to make them lowercase letters.
10444 vAd
= vceq_u8(vAd
, vBd
);
10446 #if defined __arm64__
10447 //View 8-bit element as 32-bit => a1 a0
10448 //If min of 2 32-bit values in vAd is 0xffffffff, then it means we have 0xff for all 16.
10449 if(vminv_u32(vAd
) != 0xffffffffU
)
10455 //See if any element was not same.
10456 //View 8-bit element as 16-bit => a3 a2 a1 a0
10457 //(a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
10458 vtemp32d
= vpaddl_u16(vAd
);
10459 vtemp32d
= vpadd_u32(vtemp32d
, vtemp32d
);
10460 sum
= vget_lane_u32(vtemp32d
, 0);
10462 //0x0001fffe + 0x0001fffe = 0x0003fffc when all same.
10463 if(sum
!= 0x0003fffcU
)
10472 while(len_count
> 0)
10477 ac
+= upper_to_lower_case_table
[ac
];
10478 bc
+= upper_to_lower_case_table
[bc
];
10490 // Use vectorized implementation if it is supported on this platform.
10491 mDNSlocal
void setSameDomainLabelPointer(void)
10493 if(_cpu_capabilities
& kHasNeon
)
10496 SameDomainLabelPointer
= vectorSameDomainLabel
;
10497 LogMsg("setSameDomainLabelPointer: using vector code");
10500 LogMsg("setSameDomainLabelPointer: using scalar code");
10503 #else // TARGET_OS_EMBEDDED
10505 #include <smmintrin.h>
10507 // Cache line aligned table that returns 32 for the upper case letters.
10508 // This will take up 4 cache lines.
10509 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table
[256] = {
10510 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10511 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10512 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10513 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10514 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
10515 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
10516 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10517 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10518 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10519 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10520 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10521 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10522 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10523 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10524 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10525 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
10529 mDNSlocal mDNSBool
vectorSameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
10531 const int len
= *a
++;
10533 if (len
> MAX_DOMAIN_LABEL
)
10535 fprintf(stderr
, "v: Malformed label (too long)\n");
10544 uint32_t len_count
= len
;
10546 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 };
10547 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 };
10548 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 };
10549 __m128i v37
= _mm_load_si128((__m128i
*)c_37
);
10550 __m128i v101
= _mm_load_si128((__m128i
*)c_101
);
10551 __m128i v32
= _mm_load_si128((__m128i
*)c_32
);
10554 __m128i vA
, vB
, vARotated
, vBRotated
, vMaskA
, vMaskB
;
10556 //AVX code that uses higher bandwidth (more elements per vector) was removed
10557 //to speed up the processing on the small sizes.
10558 //When I had them, the performance of 1 ~ 8 characters were slower by about 10% ~ 30%.
10559 while(len_count
> 15)
10561 vA
= _mm_loadu_si128((__m128i
*)a
);
10562 vB
= _mm_loadu_si128((__m128i
*)b
);
10566 //Make vA to lowercase if there is any uppercase.
10567 vARotated
= _mm_add_epi8(vA
, v37
); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10568 vMaskA
= _mm_cmpgt_epi8(vARotated
, v101
); //Check if anything is greater than '101' which means we have uppercase letters.
10569 vMaskA
= _mm_and_si128(vMaskA
, v32
); //Prepare 32 for the elements with uppercase letters.
10570 vA
= _mm_add_epi8(vA
, vMaskA
); //Add 32 only to the uppercase letters to make them lowercase letters.
10572 //Make vB to lowercase if there is any uppercase.
10573 vBRotated
= _mm_add_epi8(vB
, v37
); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
10574 vMaskB
= _mm_cmpgt_epi8(vBRotated
, v101
); //Check if anything is greater than '101' which means we have uppercase letters.
10575 vMaskB
= _mm_and_si128(vMaskB
, v32
); //Prepare 32 for the elements with uppercase letters.
10576 vB
= _mm_add_epi8(vB
, vMaskB
); //Add 32 only to the uppercase letters to make them lowercase letters.
10579 vA
= _mm_cmpeq_epi8(vA
, vB
);
10581 //Return if any different.
10582 is_equal
= _mm_movemask_epi8(vA
);
10583 is_equal
= is_equal
& 0xffff;
10584 if(is_equal
!= 0xffff)
10592 while(len_count
> 0)
10597 //Table will return 32 for upper case letters only.
10598 //0 will be returned for all others.
10599 ac
+= upper_to_lower_case_table
[ac
];
10600 bc
+= upper_to_lower_case_table
[bc
];
10602 //Return if a & b are different.
10613 // Use vectorized implementation if it is supported on this platform.
10614 mDNSlocal
void setSameDomainLabelPointer(void)
10616 if(_cpu_capabilities
& kHasSSE4_1
)
10619 SameDomainLabelPointer
= vectorSameDomainLabel
;
10620 LogMsg("setSameDomainLabelPointer: using vector code");
10623 LogMsg("setSameDomainLabelPointer: using scalar code");
10626 #endif // TARGET_OS_EMBEDDED
10628 // Original SameDomainLabel() implementation.
10629 mDNSlocal mDNSBool
scalarSameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
10632 const int len
= *a
++;
10634 if (len
> MAX_DOMAIN_LABEL
)
10635 { debugf("Malformed label (too long)"); return(mDNSfalse
); }
10637 if (len
!= *b
++) return(mDNSfalse
);
10638 for (i
=0; i
<len
; i
++)
10642 if (mDNSIsUpperCase(ac
)) ac
+= 'a' - 'A';
10643 if (mDNSIsUpperCase(bc
)) bc
+= 'a' - 'A';
10644 if (ac
!= bc
) return(mDNSfalse
);
10649 mDNSexport mDNSBool
SameDomainLabel(const mDNSu8
*a
, const mDNSu8
*b
)
10651 return (*SameDomainLabelPointer
)(a
, b
);
10654 #endif // APPLE_OSX_mDNSResponder
10658 #include "../unittests/mdns_macosx_ut.c"