1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2016 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_private.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"
87 #include <SystemConfiguration/SCPrivate.h>
90 // For WiFiManagerClientRef etc, declarations.
91 #include <MobileGestalt.h>
92 #include <MobileWiFi/WiFiManagerClient.h>
94 #endif // TARGET_OS_IPHONE
96 // Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
97 #include <Kernel/IOKit/apple80211/apple80211_var.h>
99 #if APPLE_OSX_mDNSResponder
100 #include <DeviceToDeviceManager/DeviceToDeviceManager.h>
102 #include <ne_session.h> // for ne_session_set_socket_attributes()
106 D2DStatus
D2DInitialize(CFRunLoopRef runLoop
, D2DServiceCallback serviceCallback
, void* userData
) __attribute__((weak_import
));
107 D2DStatus
D2DRetain(D2DServiceInstance instanceHandle
, D2DTransportType transportType
) __attribute__((weak_import
));
108 D2DStatus
D2DStopAdvertisingPairOnTransport(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
, D2DTransportType transport
) __attribute__((weak_import
));
109 D2DStatus
D2DRelease(D2DServiceInstance instanceHandle
, D2DTransportType transportType
) __attribute__((weak_import
));
110 D2DStatus
D2DStartAdvertisingPairOnTransport(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
, D2DTransportType transport
) __attribute__((weak_import
));
111 D2DStatus
D2DStartBrowsingForKeyOnTransport(const Byte
*key
, const size_t keySize
, D2DTransportType transport
) __attribute__((weak_import
));
112 D2DStatus
D2DStopBrowsingForKeyOnTransport(const Byte
*key
, const size_t keySize
, D2DTransportType transport
) __attribute__((weak_import
));
113 void D2DStartResolvingPairOnTransport(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
, D2DTransportType transport
) __attribute__((weak_import
));
114 void D2DStopResolvingPairOnTransport(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
, D2DTransportType transport
) __attribute__((weak_import
));
115 D2DStatus
D2DTerminate() __attribute__((weak_import
));
117 void xD2DAddToCache(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
);
118 void xD2DRemoveFromCache(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
);
125 #endif // APPLE_OSX_mDNSResponder
127 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
128 #include <IOKit/platform/IOPlatformSupportPrivate.h>
129 #endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
131 #define kInterfaceSpecificOption "interface="
133 #define mDNS_IOREG_KEY "mDNS_KEY"
134 #define mDNS_IOREG_VALUE "2009-07-30"
135 #define mDNS_IOREG_KA_KEY "mDNS_Keepalive"
136 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
138 #define DARK_WAKE_TIME 16 // Time we hold an idle sleep assertion for maintenance after a wake notification
140 // cache the InterfaceID of the AWDL interface
141 mDNSInterfaceID AWDLInterfaceID
;
143 // ***************************************************************************
146 #if COMPILER_LIKES_PRAGMA_MARK
147 #pragma mark - Globals
150 // By default we don't offer sleep proxy service
151 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
152 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
153 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
154 mDNSexport
int OfferSleepProxyService
= 0;
155 mDNSexport
int DisableSleepProxyClient
= 0;
156 mDNSexport
int UseInternalSleepProxy
= 1; // Set to non-zero to use internal (in-NIC) Sleep Proxy
158 mDNSexport
int OSXVers
, iOSVers
;
159 mDNSexport
int KQueueFD
;
161 #ifndef NO_SECURITYFRAMEWORK
162 static CFArrayRef ServerCerts
;
163 OSStatus
SSLSetAllowAnonymousCiphers(SSLContextRef context
, Boolean enable
);
164 #endif /* NO_SECURITYFRAMEWORK */
166 static CFStringRef NetworkChangedKey_IPv4
;
167 static CFStringRef NetworkChangedKey_IPv6
;
168 static CFStringRef NetworkChangedKey_Hostnames
;
169 static CFStringRef NetworkChangedKey_Computername
;
170 static CFStringRef NetworkChangedKey_DNS
;
171 static CFStringRef NetworkChangedKey_StateInterfacePrefix
;
172 static CFStringRef NetworkChangedKey_DynamicDNS
= CFSTR("Setup:/Network/DynamicDNS");
173 static CFStringRef NetworkChangedKey_BackToMyMac
= CFSTR("Setup:/Network/BackToMyMac");
174 static CFStringRef NetworkChangedKey_BTMMConnectivity
= CFSTR("State:/Network/Connectivity");
175 static CFStringRef NetworkChangedKey_PowerSettings
= CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
177 static char HINFO_HWstring_buffer
[32];
178 static char *HINFO_HWstring
= "Device";
179 static int HINFO_HWstring_prefixlen
= 6;
181 mDNSexport
int WatchDogReportingThreshold
= 250;
183 dispatch_queue_t SSLqueue
;
185 #if TARGET_OS_EMBEDDED
186 #define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
189 #if APPLE_OSX_mDNSResponder
190 static mDNSu8 SPMetricPortability
= 99;
191 static mDNSu8 SPMetricMarginalPower
= 99;
192 static mDNSu8 SPMetricTotalPower
= 99;
193 static mDNSu8 SPMetricFeatures
= 1; /* The current version supports TCP Keep Alive Feature */
194 mDNSexport domainname ActiveDirectoryPrimaryDomain
;
195 mDNSexport
int ActiveDirectoryPrimaryDomainLabelCount
;
196 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer
;
197 #endif // APPLE_OSX_mDNSResponder
199 // Don't send triggers too often. We arbitrarily limit it to three minutes.
200 #define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
202 // Used by AutoTunnel
203 const char btmmprefix
[] = "btmmdns:";
204 const char dnsprefix
[] = "dns:";
206 // String Array used to write list of private domains to Dynamic Store
207 static CFArrayRef privateDnsArray
= NULL
;
209 // ***************************************************************************
210 #if COMPILER_LIKES_PRAGMA_MARK
212 #pragma mark - D2D Support
217 mDNSexport
void D2D_start_advertising_interface(NetworkInterfaceInfo
*interface
)
219 // AWDL wants the address and reverse address PTR record communicated
220 // via the D2D interface layer.
221 if (interface
->InterfaceID
== AWDLInterfaceID
)
223 // only log if we have a valid record to start advertising
224 if (interface
->RR_A
.resrec
.RecordType
|| interface
->RR_PTR
.resrec
.RecordType
)
225 LogInfo("D2D_start_advertising_interface: %s", interface
->ifname
);
227 if (interface
->RR_A
.resrec
.RecordType
)
228 external_start_advertising_service(&interface
->RR_A
.resrec
, 0);
229 if (interface
->RR_PTR
.resrec
.RecordType
)
230 external_start_advertising_service(&interface
->RR_PTR
.resrec
, 0);
234 mDNSexport
void D2D_stop_advertising_interface(NetworkInterfaceInfo
*interface
)
236 if (interface
->InterfaceID
== AWDLInterfaceID
)
238 // only log if we have a valid record to stop advertising
239 if (interface
->RR_A
.resrec
.RecordType
|| interface
->RR_PTR
.resrec
.RecordType
)
240 LogInfo("D2D_stop_advertising_interface: %s", interface
->ifname
);
242 if (interface
->RR_A
.resrec
.RecordType
)
243 external_stop_advertising_service(&interface
->RR_A
.resrec
, 0);
244 if (interface
->RR_PTR
.resrec
.RecordType
)
245 external_stop_advertising_service(&interface
->RR_PTR
.resrec
, 0);
249 // If record would have been advertised to the D2D plugin layer, stop that advertisement.
250 mDNSexport
void D2D_stop_advertising_record(AuthRecord
*ar
)
252 DNSServiceFlags flags
= deriveD2DFlagsFromAuthRecType(ar
->ARType
);
253 if (callExternalHelpers(ar
->resrec
.InterfaceID
, ar
->resrec
.name
, flags
))
255 external_stop_advertising_service(&ar
->resrec
, flags
);
259 // If record should be advertised to the D2D plugin layer, start that advertisement.
260 mDNSexport
void D2D_start_advertising_record(AuthRecord
*ar
)
262 DNSServiceFlags flags
= deriveD2DFlagsFromAuthRecType(ar
->ARType
);
263 if (callExternalHelpers(ar
->resrec
.InterfaceID
, ar
->resrec
.name
, flags
))
265 external_start_advertising_service(&ar
->resrec
, flags
);
269 // Name compression items for fake packet version number 1
270 static const mDNSu8 compression_packet_v1
= 0x01;
272 static DNSMessage compression_base_msg
= { { {{0}}, {{0}}, 2, 0, 0, 0 }, "\x04_tcp\x05local\x00\x00\x0C\x00\x01\x04_udp\xC0\x11\x00\x0C\x00\x01" };
273 static mDNSu8
*const compression_limit
= (mDNSu8
*) &compression_base_msg
+ sizeof(DNSMessage
);
274 static mDNSu8
*const compression_lhs
= (mDNSu8
*const) compression_base_msg
.data
+ 27;
276 mDNSlocal
void FreeD2DARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
277 mDNSlocal
void PrintHex(mDNSu8
*data
, mDNSu16 len
);
279 typedef struct D2DRecordListElem
281 struct D2DRecordListElem
*next
;
282 D2DServiceInstance instanceHandle
;
283 D2DTransportType transportType
;
284 AuthRecord ar
; // must be last in the structure to accomodate extra space
285 // allocated for large records.
288 static D2DRecordListElem
*D2DRecords
= NULL
; // List of records returned with D2DServiceFound events
290 typedef struct D2DBrowseListElem
292 struct D2DBrowseListElem
*next
;
295 unsigned int refCount
;
298 D2DBrowseListElem
* D2DBrowseList
= NULL
;
300 mDNSlocal mDNSu8
*putVal16(mDNSu8
*ptr
, mDNSu16 val
)
302 ptr
[0] = (mDNSu8
)((val
>> 8 ) & 0xFF);
303 ptr
[1] = (mDNSu8
)((val
) & 0xFF);
304 return ptr
+ sizeof(mDNSu16
);
307 mDNSlocal mDNSu8
*putVal32(mDNSu8
*ptr
, mDNSu32 val
)
309 ptr
[0] = (mDNSu8
)((val
>> 24) & 0xFF);
310 ptr
[1] = (mDNSu8
)((val
>> 16) & 0xFF);
311 ptr
[2] = (mDNSu8
)((val
>> 8) & 0xFF);
312 ptr
[3] = (mDNSu8
)((val
) & 0xFF);
313 return ptr
+ sizeof(mDNSu32
);
316 mDNSlocal
void DomainnameToLower(const domainname
* const in
, domainname
* const out
)
318 const mDNSu8
* const start
= (const mDNSu8
* const)in
;
319 mDNSu8
*ptr
= (mDNSu8
*)start
;
323 out
->c
[ptr
-start
] = *ptr
;
325 for (; c
; c
--,ptr
++) out
->c
[ptr
-start
] = mDNSIsUpperCase(*ptr
) ? (*ptr
- 'A' + 'a') : *ptr
;
327 out
->c
[ptr
-start
] = *ptr
;
330 mDNSlocal mDNSu8
* DNSNameCompressionBuildLHS(const domainname
* typeDomain
, DNS_TypeValues qtype
)
332 mDNSu8
*ptr
= putDomainNameAsLabels(&compression_base_msg
, compression_lhs
, compression_limit
, typeDomain
);
333 if (!ptr
) return ptr
;
334 *ptr
= (qtype
>> 8) & 0xff;
338 *ptr
= compression_packet_v1
;
342 mDNSlocal mDNSu8
* DNSNameCompressionBuildRHS(mDNSu8
*start
, const ResourceRecord
*const resourceRecord
)
344 return putRData(&compression_base_msg
, start
, compression_limit
, resourceRecord
);
347 #define PRINT_DEBUG_BYTES_LIMIT 64 // set limit on number of record bytes printed for debugging
349 mDNSlocal
void PrintHex(mDNSu8
*data
, mDNSu16 len
)
352 char buffer
[49] = {0};
353 char *bufend
= buffer
+ sizeof(buffer
);
355 if (len
> PRINT_DEBUG_BYTES_LIMIT
)
357 LogInfo(" (limiting debug output to %d bytes)", PRINT_DEBUG_BYTES_LIMIT
);
358 len
= PRINT_DEBUG_BYTES_LIMIT
;
365 for(; data
< end
&& ptr
< bufend
-1; ptr
+=3,data
++)
366 mDNS_snprintf(ptr
, bufend
- ptr
, "%02X ", *data
);
367 LogInfo(" %s", buffer
);
371 mDNSlocal
void PrintHelper(const char *const tag
, mDNSu8
*lhs
, mDNSu16 lhs_len
, mDNSu8
*rhs
, mDNSu16 rhs_len
)
373 if (!mDNS_LoggingEnabled
) return;
376 LogInfo(" LHS: (%d bytes)", lhs_len
);
377 PrintHex(lhs
, lhs_len
);
381 LogInfo(" RHS: (%d bytes)", rhs_len
);
382 PrintHex(rhs
, rhs_len
);
385 mDNSlocal
void FreeD2DARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
388 if (result
== mStatus_MemFree
)
390 D2DRecordListElem
**ptr
= &D2DRecords
;
391 D2DRecordListElem
*tmp
;
392 while (*ptr
&& &(*ptr
)->ar
!= rr
) ptr
= &(*ptr
)->next
;
393 if (!*ptr
) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m
, rr
)); return; }
394 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m
, rr
));
397 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
398 mDNSPlatformMemFree(tmp
);
402 mDNSexport
void external_connection_release(const domainname
*instance
)
405 D2DRecordListElem
*ptr
= D2DRecords
;
407 for ( ; ptr
; ptr
= ptr
->next
)
409 if ((ptr
->ar
.resrec
.rrtype
== kDNSServiceType_PTR
) &&
410 SameDomainName(&ptr
->ar
.rdatastorage
.u
.name
, instance
))
412 LogInfo("external_connection_release: Calling D2DRelease(instanceHandle = %p, transportType = %d",
413 ptr
->instanceHandle
, ptr
->transportType
);
414 if (D2DRelease
) D2DRelease(ptr
->instanceHandle
, ptr
->transportType
);
419 mDNSlocal
void xD2DClearCache(const domainname
*regType
, DNS_TypeValues qtype
)
421 D2DRecordListElem
*ptr
= D2DRecords
;
422 for ( ; ptr
; ptr
= ptr
->next
)
424 if ((ptr
->ar
.resrec
.rrtype
== qtype
) && SameDomainName(&ptr
->ar
.namestorage
, regType
))
426 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage
, &ptr
->ar
));
427 mDNS_Deregister(&mDNSStorage
, &ptr
->ar
);
432 mDNSlocal D2DBrowseListElem
** D2DFindInBrowseList(const domainname
*const name
, mDNSu16 type
)
434 D2DBrowseListElem
**ptr
= &D2DBrowseList
;
436 for ( ; *ptr
; ptr
= &(*ptr
)->next
)
437 if ((*ptr
)->type
== type
&& SameDomainName(&(*ptr
)->name
, name
))
443 mDNSlocal
unsigned int D2DBrowseListRefCount(const domainname
*const name
, mDNSu16 type
)
445 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
446 return *ptr
? (*ptr
)->refCount
: 0;
449 mDNSlocal
void D2DBrowseListRetain(const domainname
*const name
, mDNSu16 type
)
451 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
455 *ptr
= mDNSPlatformMemAllocate(sizeof(**ptr
));
456 mDNSPlatformMemZero(*ptr
, sizeof(**ptr
));
458 AssignDomainName(&(*ptr
)->name
, name
);
460 (*ptr
)->refCount
+= 1;
462 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
465 // Returns true if found in list, false otherwise
466 mDNSlocal
bool D2DBrowseListRelease(const domainname
*const name
, mDNSu16 type
)
468 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
470 if (!*ptr
) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name
->c
, DNSTypeName(type
)); return false; }
472 (*ptr
)->refCount
-= 1;
474 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
476 if (!(*ptr
)->refCount
)
478 D2DBrowseListElem
*tmp
= *ptr
;
480 mDNSPlatformMemFree(tmp
);
485 mDNSlocal mStatus
xD2DParse(mDNS
*const m
, const mDNSu8
* const lhs
, const mDNSu16 lhs_len
, const mDNSu8
* const rhs
, const mDNSu16 rhs_len
, D2DRecordListElem
**D2DListp
)
487 // Sanity check that key array (lhs) has one domain name, followed by the record type and single byte D2D
488 // plugin protocol version number.
489 // Note, we don't have a DNSMessage pointer at this point, so just pass in the lhs value as the lower bound
490 // of the input bytes we are processing. skipDomainName() does not try to follow name compression pointers,
491 // so it is safe to pass it the key byte array since it will stop parsing the DNS name and return a pointer
492 // to the byte after the first name compression pointer it encounters.
493 const mDNSu8
*keyp
= skipDomainName((const DNSMessage
*const) lhs
, lhs
, lhs
+ lhs_len
);
495 // There should be 3 bytes remaining in a valid key,
496 // two for the DNS record type, and one for the D2D protocol version number.
497 if (keyp
== NULL
|| (keyp
+ 3 != (lhs
+ lhs_len
)))
499 LogInfo("xD2DParse: Could not parse DNS name in key");
500 return mStatus_Incompatible
;
502 keyp
+= 2; // point to D2D compression packet format version byte
503 if (*keyp
!= compression_packet_v1
)
505 LogInfo("xD2DParse: Invalid D2D packet version: %d", *keyp
);
506 return mStatus_Incompatible
;
509 if (mDNS_LoggingEnabled
)
511 LogInfo("%s", __func__
);
512 LogInfo(" Static Bytes: (%d bytes)", compression_lhs
- (mDNSu8
*)&compression_base_msg
);
513 PrintHex((mDNSu8
*)&compression_base_msg
, compression_lhs
- (mDNSu8
*)&compression_base_msg
);
516 mDNSu8
*ptr
= compression_lhs
; // pointer to the end of our fake packet
518 // Check to make sure we're not going to go past the end of the DNSMessage data
519 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
520 if (ptr
+ lhs_len
- 7 + rhs_len
>= compression_limit
) return mStatus_NoMemoryErr
;
522 // Copy the LHS onto our fake wire packet
523 mDNSPlatformMemCopy(ptr
, lhs
, lhs_len
);
526 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
527 if (*ptr
!= compression_packet_v1
) return mStatus_Incompatible
;
529 // two bytes of CLASS
530 ptr
= putVal16(ptr
, kDNSClass_IN
| kDNSClass_UniqueRRSet
);
533 ptr
= putVal32(ptr
, 120);
535 // Copy the RHS length into the RDLENGTH of our fake wire packet
536 ptr
= putVal16(ptr
, rhs_len
);
538 // Copy the RHS onto our fake wire packet
539 mDNSPlatformMemCopy(ptr
, rhs
, rhs_len
);
542 if (mDNS_LoggingEnabled
)
544 LogInfo(" Our Bytes (%d bytes): ", ptr
- compression_lhs
);
545 PrintHex(compression_lhs
, ptr
- compression_lhs
);
548 ptr
= (mDNSu8
*) GetLargeResourceRecord(m
, &compression_base_msg
, compression_lhs
, ptr
, mDNSInterface_Any
, kDNSRecordTypePacketAns
, &m
->rec
);
549 if (!ptr
|| m
->rec
.r
.resrec
.RecordType
== kDNSRecordTypePacketNegative
)
551 LogMsg("xD2DParse: failed to get large RR");
552 m
->rec
.r
.resrec
.RecordType
= 0;
553 return mStatus_UnknownErr
;
557 LogInfo("xD2DParse: got rr: %s", CRDisplayString(m
, &m
->rec
.r
));
560 *D2DListp
= mDNSPlatformMemAllocate(sizeof(D2DRecordListElem
) + (m
->rec
.r
.resrec
.rdlength
<= sizeof(RDataBody
) ? 0 : m
->rec
.r
.resrec
.rdlength
- sizeof(RDataBody
)));
561 if (!*D2DListp
) return mStatus_NoMemoryErr
;
563 AuthRecord
*rr
= &(*D2DListp
)->ar
;
564 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_P2P
, m
->rec
.r
.resrec
.rrtype
, 7200, kDNSRecordTypeShared
, AuthRecordP2P
, FreeD2DARElemCallback
, NULL
);
565 AssignDomainName(&rr
->namestorage
, &m
->rec
.namestorage
);
566 rr
->resrec
.rdlength
= m
->rec
.r
.resrec
.rdlength
;
567 rr
->resrec
.rdata
->MaxRDLength
= m
->rec
.r
.resrec
.rdlength
;
568 mDNSPlatformMemCopy(rr
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdlength
);
569 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
570 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
572 m
->rec
.r
.resrec
.RecordType
= 0; // Mark m->rec as no longer in use
574 return mStatus_NoError
;
577 mDNSexport
void xD2DAddToCache(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
579 if (result
== kD2DSuccess
)
581 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
584 D2DRecordListElem
*ptr
= NULL
;
586 err
= xD2DParse(m
, (const mDNSu8
* const)key
, (const mDNSu16
)keySize
, (const mDNSu8
* const)value
, (const mDNSu16
)valueSize
, &ptr
);
589 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err
);
590 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
592 mDNSPlatformMemFree(ptr
);
596 // If the record was created based on a BLE beacon, update the interface index to indicate
597 // this and thus match BLE specific queries.
598 if (transportType
== D2DBLETransport
)
599 ptr
->ar
.resrec
.InterfaceID
= mDNSInterface_BLE
;
601 err
= mDNS_Register(m
, &ptr
->ar
);
604 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err
, ARDisplayString(m
, &ptr
->ar
));
605 mDNSPlatformMemFree(ptr
);
609 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m
, &ptr
->ar
));
610 ptr
->instanceHandle
= instanceHandle
;
611 ptr
->transportType
= transportType
;
612 ptr
->next
= D2DRecords
;
616 LogMsg("xD2DAddToCache: Unexpected result %d", result
);
619 mDNSlocal D2DRecordListElem
* xD2DFindInList(mDNS
*const m
, const Byte
*const key
, const size_t keySize
, const Byte
*const value
, const size_t valueSize
)
621 D2DRecordListElem
*ptr
= D2DRecords
;
622 D2DRecordListElem
*arptr
= NULL
;
624 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL
; }
626 mStatus err
= xD2DParse(m
, (const mDNSu8
*const)key
, (const mDNSu16
)keySize
, (const mDNSu8
*const)value
, (const mDNSu16
)valueSize
, &arptr
);
629 LogMsg("xD2DFindInList: xD2DParse returned error: %d", err
);
630 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
632 mDNSPlatformMemFree(arptr
);
638 if (IdenticalResourceRecord(&arptr
->ar
.resrec
, &ptr
->ar
.resrec
)) break;
642 if (!ptr
) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(m
, &arptr
->ar
));
643 mDNSPlatformMemFree(arptr
);
647 mDNSexport
void xD2DRemoveFromCache(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
649 (void)transportType
; // We don't care about this, yet.
650 (void)instanceHandle
; // We don't care about this, yet.
652 if (result
== kD2DSuccess
)
654 D2DRecordListElem
*ptr
= xD2DFindInList(m
, key
, keySize
, value
, valueSize
);
657 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m
, &ptr
->ar
));
658 mDNS_Deregister(m
, &ptr
->ar
);
662 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result
);
665 mDNSlocal
void xD2DServiceResolved(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
673 if (result
== kD2DSuccess
)
675 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle
);
676 if (D2DRetain
) D2DRetain(instanceHandle
, transportType
);
678 else LogMsg("xD2DServiceResolved: Unexpected result %d", result
);
681 mDNSlocal
void xD2DRetainHappened(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
684 (void)instanceHandle
;
691 if (result
== kD2DSuccess
) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle
);
692 else LogMsg("xD2DRetainHappened: Unexpected result %d", result
);
695 mDNSlocal
void xD2DReleaseHappened(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
698 (void)instanceHandle
;
705 if (result
== kD2DSuccess
) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle
);
706 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result
);
709 mDNSlocal
void xD2DServiceCallback(D2DServiceEvent event
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
, void *userData
)
711 mDNS
*m
= (mDNS
*) userData
;
712 const char *eventString
= "unknown";
716 if (keySize
> 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize
);
717 if (valueSize
> 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize
);
721 case D2DServiceFound
:
722 eventString
= "D2DServiceFound";
725 eventString
= "D2DServiceLost";
727 case D2DServiceResolved
:
728 eventString
= "D2DServiceResolved";
730 case D2DServiceRetained
:
731 eventString
= "D2DServiceRetained";
733 case D2DServiceReleased
:
734 eventString
= "D2DServiceReleased";
740 LogInfo("xD2DServiceCallback: event=%s result=%d instanceHandle=%p transportType=%d LHS=%p (%u) RHS=%p (%u) userData=%p", eventString
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
, userData
);
741 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
745 case D2DServiceFound
:
746 xD2DAddToCache(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
749 xD2DRemoveFromCache(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
751 case D2DServiceResolved
:
752 xD2DServiceResolved(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
754 case D2DServiceRetained
:
755 xD2DRetainHappened(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
757 case D2DServiceReleased
:
758 xD2DReleaseHappened(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
764 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
765 KQueueUnlock(m
, "xD2DServiceCallback");
768 // Map interface index and flags to a specific D2D transport type or D2DTransportMax if all plugins
770 // When D2DTransportMax is returned, if a specific transport should not be called, *excludedTransportType
771 // will be set to the excluded transport value, otherwise, it will be set to D2DTransportMax.
772 // If the return value is not D2DTransportMax, excludedTransportType is undefined.
774 mDNSlocal D2DTransportType
xD2DInterfaceToTransportType(mDNSInterfaceID InterfaceID
, DNSServiceFlags flags
, D2DTransportType
* excludedTransportType
)
776 NetworkInterfaceInfoOSX
*info
;
778 // Default exludes the D2DAWDLTransport when D2DTransportMax is returned.
779 *excludedTransportType
= D2DAWDLTransport
;
781 // Call all D2D plugins when both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set.
782 if ((flags
& kDNSServiceFlagsIncludeP2P
) && (flags
& kDNSServiceFlagsIncludeAWDL
))
784 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (including AWDL) since both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set");
785 *excludedTransportType
= D2DTransportMax
;
786 return D2DTransportMax
;
788 // Call all D2D plugins (exlcluding AWDL) when only kDNSServiceFlagsIncludeP2P is set.
789 else if (flags
& kDNSServiceFlagsIncludeP2P
)
791 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) since only kDNSServiceFlagsIncludeP2P is set");
792 return D2DTransportMax
;
794 // Call AWDL D2D plugin when only kDNSServiceFlagsIncludeAWDL is set.
795 else if (flags
& kDNSServiceFlagsIncludeAWDL
)
797 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport since only kDNSServiceFlagsIncludeAWDL is set");
798 return D2DAWDLTransport
;
801 if (InterfaceID
== mDNSInterface_P2P
)
803 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) for interface index mDNSInterface_P2P");
804 return D2DTransportMax
;
807 // Compare to cached AWDL interface ID.
808 if (AWDLInterfaceID
&& (InterfaceID
== AWDLInterfaceID
))
810 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport for interface index %d", InterfaceID
);
811 return D2DAWDLTransport
;
814 info
= IfindexToInterfaceInfoOSX(&mDNSStorage
, InterfaceID
);
817 LogInfo("xD2DInterfaceToTransportType: Invalid interface index %d", InterfaceID
);
818 return D2DTransportMax
;
821 // Recognize AirDrop specific p2p* interface based on interface name.
822 if (strncmp(info
->ifinfo
.ifname
, "p2p", 3) == 0)
824 LogInfo("xD2DInterfaceToTransportType: returning D2DWifiPeerToPeerTransport for interface index %d", InterfaceID
);
825 return D2DWifiPeerToPeerTransport
;
828 // Currently there is no way to identify Bluetooth interface by name,
829 // since they use "en*" based name strings.
831 LogInfo("xD2DInterfaceToTransportType: returning default D2DTransportMax for interface index %d", InterfaceID
);
832 return D2DTransportMax
;
835 // Similar to callExternalHelpers(), but without the checks for the BLE specific interface or flags.
836 // It's assumed that the domain was already verified to be .local once we are at this level.
837 mDNSlocal mDNSBool
callInternalHelpers(mDNSInterfaceID InterfaceID
, DNSServiceFlags flags
)
839 if ( ((InterfaceID
== mDNSInterface_Any
) && (flags
& (kDNSServiceFlagsIncludeP2P
| kDNSServiceFlagsIncludeAWDL
)))
840 || mDNSPlatformInterfaceIsD2D(InterfaceID
))
846 mDNSexport
void external_start_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
, DNSQuestion
* q
)
848 // BLE support currently not handled by a D2D plugin
849 if (applyToBLE(InterfaceID
, flags
))
853 DomainnameToLower(typeDomain
, &lower
);
854 // pass in the key and keySize
855 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
856 start_BLE_browse(q
, &lower
, qtype
, flags
, compression_lhs
, end
- compression_lhs
);
859 if (callInternalHelpers(InterfaceID
, flags
))
860 internal_start_browsing_for_service(InterfaceID
, typeDomain
, qtype
, flags
);
863 mDNSexport
void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
867 DomainnameToLower(typeDomain
, &lower
);
869 if (!D2DBrowseListRefCount(&lower
, qtype
))
871 D2DTransportType transportType
, excludedTransport
;
873 LogInfo("%s: Starting browse for: %##s %s", __func__
, lower
.c
, DNSTypeName(qtype
));
874 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
875 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
877 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
878 if (transportType
== D2DTransportMax
)
881 for (i
= 0; i
< D2DTransportMax
; i
++)
883 if (i
== excludedTransport
) continue;
884 if (D2DStartBrowsingForKeyOnTransport
) D2DStartBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, i
);
889 if (D2DStartBrowsingForKeyOnTransport
) D2DStartBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, transportType
);
892 D2DBrowseListRetain(&lower
, qtype
);
895 mDNSexport
void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
897 // BLE support currently not handled by a D2D plugin
898 if (applyToBLE(InterfaceID
, flags
))
902 // If this is the last instance of this browse, clear any cached records recieved for it.
903 // We are not guaranteed to get a D2DServiceLost event for all key, value pairs cached over BLE.
904 DomainnameToLower(typeDomain
, &lower
);
905 if (stop_BLE_browse(&lower
, qtype
, flags
))
906 xD2DClearCache(&lower
, qtype
);
909 if (callInternalHelpers(InterfaceID
, flags
))
910 internal_stop_browsing_for_service(InterfaceID
, typeDomain
, qtype
, flags
);
913 mDNSexport
void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
917 DomainnameToLower(typeDomain
, &lower
);
919 // If found in list and this is the last reference to this browse, remove the key from the D2D plugins.
920 if (D2DBrowseListRelease(&lower
, qtype
) && !D2DBrowseListRefCount(&lower
, qtype
))
922 D2DTransportType transportType
, excludedTransport
;
924 LogInfo("%s: Stopping browse for: %##s %s", __func__
, lower
.c
, DNSTypeName(qtype
));
925 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
926 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
928 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
929 if (transportType
== D2DTransportMax
)
932 for (i
= 0; i
< D2DTransportMax
; i
++)
934 if (i
== excludedTransport
) continue;
935 if (D2DStopBrowsingForKeyOnTransport
) D2DStopBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, i
);
940 if (D2DStopBrowsingForKeyOnTransport
) D2DStopBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, transportType
);
943 // The D2D driver may not generate the D2DServiceLost event for this key after
944 // the D2DStopBrowsingForKey*() call above. So, we flush the key from the D2D
946 xD2DClearCache(&lower
, qtype
);
950 mDNSexport
void external_start_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
952 // Note, start_BLE_advertise() is currently called directly from external_start_advertising_helper() since
953 // it needs to pass the ServiceRecordSet so that we can promote the record advertisements to AWDL
954 // when we see the corresponding browse indication over BLE.
956 if (callInternalHelpers(resourceRecord
->InterfaceID
, flags
))
957 internal_start_advertising_service(resourceRecord
, flags
);
960 mDNSexport
void internal_start_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
965 D2DTransportType transportType
, excludedTransport
;
966 DomainnameToLower(resourceRecord
->name
, &lower
);
968 LogInfo("%s: %s", __func__
, RRDisplayString(&mDNSStorage
, resourceRecord
));
970 // For SRV records, update packet filter if p2p interface already exists, otherwise,
971 // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface.
972 if (resourceRecord
->rrtype
== kDNSType_SRV
)
973 mDNSUpdatePacketFilter(NULL
);
975 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
976 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
977 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
979 transportType
= xD2DInterfaceToTransportType(resourceRecord
->InterfaceID
, flags
, & excludedTransport
);
980 if (transportType
== D2DTransportMax
)
983 for (i
= 0; i
< D2DTransportMax
; i
++)
985 if (i
== excludedTransport
) continue;
986 if (D2DStartAdvertisingPairOnTransport
) D2DStartAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
991 if (D2DStartAdvertisingPairOnTransport
) D2DStartAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
995 mDNSexport
void external_stop_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
997 // BLE support currently not handled by a D2D plugin
998 if (applyToBLE(resourceRecord
->InterfaceID
, flags
))
1002 DomainnameToLower(resourceRecord
->name
, &lower
);
1003 stop_BLE_advertise(&lower
, resourceRecord
->rrtype
, flags
);
1006 if (callInternalHelpers(resourceRecord
->InterfaceID
, flags
))
1007 internal_stop_advertising_service(resourceRecord
, flags
);
1010 mDNSexport
void internal_stop_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
1015 D2DTransportType transportType
, excludedTransport
;
1016 DomainnameToLower(resourceRecord
->name
, &lower
);
1018 LogInfo("%s: %s", __func__
, RRDisplayString(&mDNSStorage
, resourceRecord
));
1020 // For SRV records, update packet filter if p2p interface already exists, otherwise,
1021 // For SRV records, update packet filter to to remove this port from list
1022 if (resourceRecord
->rrtype
== kDNSType_SRV
)
1023 mDNSUpdatePacketFilter(resourceRecord
);
1025 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
1026 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
1027 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
1029 transportType
= xD2DInterfaceToTransportType(resourceRecord
->InterfaceID
, flags
, & excludedTransport
);
1030 if (transportType
== D2DTransportMax
)
1033 for (i
= 0; i
< D2DTransportMax
; i
++)
1035 if (i
== excludedTransport
) continue;
1036 if (D2DStopAdvertisingPairOnTransport
) D2DStopAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
1041 if (D2DStopAdvertisingPairOnTransport
) D2DStopAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
1045 mDNSexport
void external_start_resolving_service(mDNSInterfaceID InterfaceID
, const domainname
*const fqdn
, DNSServiceFlags flags
)
1050 mDNSBool AWDL_used
= false; // whether AWDL was used for this resolve
1051 D2DTransportType transportType
, excludedTransport
;
1052 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
1054 LogInfo("external_start_resolving_service: %##s", fqdn
->c
);
1055 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
1056 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
1057 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
1059 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
1060 if (transportType
== D2DTransportMax
)
1062 // Resolving over all the transports, except for excludedTransport if set.
1064 for (i
= 0; i
< D2DTransportMax
; i
++)
1066 if (i
== excludedTransport
) continue;
1067 if (D2DStartResolvingPairOnTransport
) D2DStartResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
1069 if (i
== D2DAWDLTransport
)
1075 // Resolving over one specific transport.
1076 if (D2DStartResolvingPairOnTransport
) D2DStartResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
1078 if (transportType
== D2DAWDLTransport
)
1082 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
1083 // We only want these records going to AWDL, so use AWDLInterfaceID as the
1084 // interface and don't set any other flags.
1085 if (AWDL_used
&& AWDLInterfaceID
)
1087 LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL");
1088 external_start_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_TXT
, 0, 0);
1089 external_start_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_SRV
, 0, 0);
1093 mDNSexport
void external_stop_resolving_service(mDNSInterfaceID InterfaceID
, const domainname
*const fqdn
, DNSServiceFlags flags
)
1098 mDNSBool AWDL_used
= false; // whether AWDL was used for this resolve
1099 D2DTransportType transportType
, excludedTransport
;
1100 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
1102 LogInfo("external_stop_resolving_service: %##s", fqdn
->c
);
1103 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
1104 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
1105 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
1107 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
1108 if (transportType
== D2DTransportMax
)
1111 for (i
= 0; i
< D2DTransportMax
; i
++)
1113 if (i
== excludedTransport
) continue;
1114 if (D2DStopResolvingPairOnTransport
) D2DStopResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
1116 if (i
== D2DAWDLTransport
)
1122 if (D2DStopResolvingPairOnTransport
) D2DStopResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
1124 if (transportType
== D2DAWDLTransport
)
1128 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
1129 // We only want these records going to AWDL, so use AWDLInterfaceID as the
1130 // interface and don't set any other flags.
1131 if (AWDL_used
&& AWDLInterfaceID
)
1133 LogInfo("external_stop_resolving_service: stop browse for TXT and SRV on AWDL");
1134 external_stop_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_TXT
, 0);
1135 external_stop_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_SRV
, 0);
1139 #elif APPLE_OSX_mDNSResponder
1141 mDNSexport
void internal_start_browsing_for_service(mDNS
*const m
, const domainname
*const type
, DNS_TypeValues qtype
, DNSServiceFlags flags
) { (void)m
; (void)type
; (void)qtype
; (void)flags
}
1142 mDNSexport
void internal_stop_browsing_for_service(mDNS
*const m
, const domainname
*const type
, DNS_TypeValues qtype
, DNSServiceFlags flags
) { (void)m
; (void)type
; (void)qtype
; (void)flags
;}
1143 mDNSexport
void internal_start_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
) { (void)resourceRecord
; (void)flags
;}
1144 mDNSexport
void internal_stop_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
) { (void)resourceRecord
; (void)flags
;}
1146 mDNSexport
void external_start_browsing_for_service(mDNS
*const m
, const domainname
*const type
, DNS_TypeValues qtype
, DNSServiceFlags flags
) { (void)m
; (void)type
; (void)qtype
; (void)flags
; (void)q
}
1147 mDNSexport
void external_stop_browsing_for_service(mDNS
*const m
, const domainname
*const type
, DNS_TypeValues qtype
, DNSServiceFlags flags
) { (void)m
; (void)type
; (void)qtype
; (void)flags
;}
1148 mDNSexport
void external_start_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
) { (void)resourceRecord
; (void)flags
;}
1149 mDNSexport
void external_stop_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
) { (void)resourceRecord
; (void)flags
;}
1150 mDNSexport
void external_start_resolving_service(const domainname
*const fqdn
, DNSServiceFlags flags
) { (void)fqdn
; (void)flags
;}
1151 mDNSexport
void external_stop_resolving_service(const domainname
*const fqdn
, DNSServiceFlags flags
) { (void)fqdn
; (void)flags
;}
1155 // ***************************************************************************
1158 #if COMPILER_LIKES_PRAGMA_MARK
1160 #pragma mark - Utility Functions
1163 // We only attempt to send and receive multicast packets on interfaces that are
1164 // (a) flagged as multicast-capable
1165 // (b) *not* flagged as point-to-point (e.g. modem)
1166 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
1167 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
1168 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
1170 #if BONJOUR_ON_DEMAND
1171 #define MulticastInterface(i) ((i)->m->BonjourEnabled && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
1173 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
1175 #define SPSInterface(i) ((i)->ifinfo.McastTxRx && !((i)->ifa_flags & IFF_LOOPBACK) && !(i)->D2DInterface)
1177 mDNSexport
void NotifyOfElusiveBug(const char *title
, const char *msg
) // Both strings are UTF-8 text
1179 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
1182 // Determine if we're at Apple (17.*.*.*)
1183 NetworkInterfaceInfoOSX
*i
;
1184 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
1185 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& i
->ifinfo
.ip
.ip
.v4
.b
[0] == 17)
1188 return; // If not at Apple, don't show the alert
1192 LogMsg("NotifyOfElusiveBug: %s", title
);
1193 LogMsg("NotifyOfElusiveBug: %s", msg
);
1195 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
1196 // To avoid this, we don't try to display alerts in the first three minutes after boot.
1197 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180))
1199 LogMsg("Suppressing notification early in boot: %d", mDNSPlatformRawTime());
1203 #ifndef NO_CFUSERNOTIFICATION
1204 static int notifyCount
= 0; // To guard against excessive display of warning notifications
1205 if (notifyCount
< 5)
1208 mDNSNotify(title
, msg
);
1210 #endif /* NO_CFUSERNOTIFICATION */
1214 // Write a syslog message and display an alert, then if ForceAlerts is set, generate a stack trace
1215 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
1216 mDNSexport
void LogMemCorruption(const char *format
, ...)
1220 va_start(ptr
,format
);
1221 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
1223 LogMsg("!!!! %s !!!!", buffer
);
1224 NotifyOfElusiveBug("Memory Corruption", buffer
);
1226 *(volatile long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
1231 // Like LogMemCorruption above, but only display the alert if ForceAlerts is set and we're going to generate a stack trace
1232 #if APPLE_OSX_mDNSResponder
1233 mDNSexport
void LogFatalError(const char *format
, ...)
1237 va_start(ptr
,format
);
1238 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
1240 LogMsg("!!!! %s !!!!", buffer
);
1242 NotifyOfElusiveBug("Fatal Error. See /Library/Logs/DiagnosticReports", buffer
);
1243 *(volatile long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
1248 // Returns true if it is an AppleTV based hardware running iOS, false otherwise
1249 mDNSlocal mDNSBool
IsAppleTV(void)
1251 #if TARGET_OS_EMBEDDED
1252 static mDNSBool sInitialized
= mDNSfalse
;
1253 static mDNSBool sIsAppleTV
= mDNSfalse
;
1254 CFStringRef deviceClass
= NULL
;
1258 deviceClass
= (CFStringRef
) MGCopyAnswer(kMGQDeviceClass
, NULL
);
1261 if(CFEqual(deviceClass
, kMGDeviceClassAppleTV
))
1262 sIsAppleTV
= mDNStrue
;
1263 CFRelease(deviceClass
);
1265 sInitialized
= mDNStrue
;
1270 #endif // TARGET_OS_EMBEDDED
1273 mDNSlocal
struct ifaddrs
*myGetIfAddrs(int refresh
)
1275 static struct ifaddrs
*ifa
= NULL
;
1288 mDNSlocal
void DynamicStoreWrite(int key
, const char* subkey
, uintptr_t value
, signed long valueCnt
)
1290 CFStringRef sckey
= NULL
;
1291 Boolean release_sckey
= FALSE
;
1292 CFDataRef bytes
= NULL
;
1293 CFPropertyListRef plist
= NULL
;
1295 switch ((enum mDNSDynamicStoreSetConfigKey
)key
)
1297 case kmDNSMulticastConfig
:
1298 sckey
= CFSTR("State:/Network/" kDNSServiceCompMulticastDNS
);
1300 case kmDNSDynamicConfig
:
1301 sckey
= CFSTR("State:/Network/DynamicDNS");
1303 case kmDNSPrivateConfig
:
1304 sckey
= CFSTR("State:/Network/" kDNSServiceCompPrivateDNS
);
1306 case kmDNSBackToMyMacConfig
:
1307 sckey
= CFSTR("State:/Network/BackToMyMac");
1309 case kmDNSSleepProxyServersState
:
1311 CFMutableStringRef tmp
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
1312 CFStringAppend(tmp
, CFSTR("State:/Network/Interface/"));
1313 CFStringAppendCString(tmp
, subkey
, kCFStringEncodingUTF8
);
1314 CFStringAppend(tmp
, CFSTR("/SleepProxyServers"));
1315 sckey
= CFStringCreateCopy(kCFAllocatorDefault
, tmp
);
1316 release_sckey
= TRUE
;
1320 case kmDNSDebugState
:
1321 sckey
= CFSTR("State:/Network/mDNSResponder/DebugState");
1324 LogMsg("unrecognized key %d", key
);
1327 if (NULL
== (bytes
= CFDataCreateWithBytesNoCopy(NULL
, (void *)value
,
1328 valueCnt
, kCFAllocatorNull
)))
1330 LogMsg("CFDataCreateWithBytesNoCopy of value failed");
1333 if (NULL
== (plist
= CFPropertyListCreateWithData(NULL
, bytes
, kCFPropertyListImmutable
, NULL
, NULL
)))
1335 LogMsg("CFPropertyListCreateWithData of bytes failed");
1340 SCDynamicStoreSetValue(NULL
, sckey
, plist
);
1347 if (release_sckey
&& sckey
)
1351 mDNSexport
void mDNSDynamicStoreSetConfig(int key
, const char *subkey
, CFPropertyListRef value
)
1353 CFPropertyListRef valueCopy
;
1354 char *subkeyCopy
= NULL
;
1358 // We need to copy the key and value before we dispatch off the block below as the
1359 // caller will free the memory once we return from this function.
1360 valueCopy
= CFPropertyListCreateDeepCopy(NULL
, value
, kCFPropertyListImmutable
);
1363 LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
1368 int len
= strlen(subkey
);
1369 subkeyCopy
= mDNSPlatformMemAllocate(len
+ 1);
1372 LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
1373 CFRelease(valueCopy
);
1376 mDNSPlatformMemCopy(subkeyCopy
, subkey
, len
);
1377 subkeyCopy
[len
] = 0;
1380 dispatch_async(dispatch_get_main_queue(), ^{
1381 CFWriteStreamRef stream
= NULL
;
1382 CFDataRef bytes
= NULL
;
1384 KQueueLock(&mDNSStorage
);
1386 if (NULL
== (stream
= CFWriteStreamCreateWithAllocatedBuffers(NULL
, NULL
)))
1388 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
1391 CFWriteStreamOpen(stream
);
1392 ret
= CFPropertyListWrite(valueCopy
, stream
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
1395 LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
1398 if (NULL
== (bytes
= CFWriteStreamCopyProperty(stream
, kCFStreamPropertyDataWritten
)))
1400 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
1403 CFWriteStreamClose(stream
);
1406 DynamicStoreWrite(key
, subkeyCopy
? subkeyCopy
: "", (uintptr_t)CFDataGetBytePtr(bytes
), CFDataGetLength(bytes
));
1409 CFRelease(valueCopy
);
1412 CFWriteStreamClose(stream
);
1418 mDNSPlatformMemFree(subkeyCopy
);
1420 KQueueUnlock(&mDNSStorage
, "mDNSDynamicStoreSetConfig");
1424 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
1425 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, const char *ifname
, int type
)
1427 NetworkInterfaceInfoOSX
*i
;
1428 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1429 if (i
->Exists
&& !strcmp(i
->ifinfo
.ifname
, ifname
) &&
1430 ((type
== AF_UNSPEC
) ||
1431 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
1432 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
))) return(i
);
1436 mDNSlocal
int myIfIndexToName(u_short ifindex
, char *name
)
1438 struct ifaddrs
*ifa
;
1439 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
1440 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
1441 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== ifindex
)
1442 { strlcpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
1446 mDNSexport NetworkInterfaceInfoOSX
*IfindexToInterfaceInfoOSX(const mDNS
*const m
, mDNSInterfaceID ifindex
)
1448 mDNSu32 scope_id
= (mDNSu32
)(uintptr_t)ifindex
;
1449 NetworkInterfaceInfoOSX
*i
;
1451 // Don't get tricked by inactive interfaces
1452 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1453 if (i
->Registered
&& i
->scope_id
== scope_id
) return(i
);
1458 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS
*const m
, mDNSu32 ifindex
)
1460 if (ifindex
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
1461 if (ifindex
== kDNSServiceInterfaceIndexP2P
) return(mDNSInterface_P2P
);
1462 if (ifindex
== kDNSServiceInterfaceIndexBLE
) return(mDNSInterface_BLE
);
1463 if (ifindex
== kDNSServiceInterfaceIndexAny
) return(mDNSNULL
);
1465 NetworkInterfaceInfoOSX
* ifi
= IfindexToInterfaceInfoOSX(m
, (mDNSInterfaceID
)(uintptr_t)ifindex
);
1468 // Not found. Make sure our interface list is up to date, then try again.
1469 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex
);
1470 mDNSMacOSXNetworkChanged(m
);
1471 ifi
= IfindexToInterfaceInfoOSX(m
, (mDNSInterfaceID
)(uintptr_t)ifindex
);
1474 if (!ifi
) return(mDNSNULL
);
1476 return(ifi
->ifinfo
.InterfaceID
);
1480 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS
*const m
, mDNSInterfaceID id
, mDNSBool suppressNetworkChange
)
1482 NetworkInterfaceInfoOSX
*i
;
1483 if (id
== mDNSInterface_Any
) return(0);
1484 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
1485 if (id
== mDNSInterface_Unicast
) return(0);
1486 if (id
== mDNSInterface_P2P
) return(kDNSServiceInterfaceIndexP2P
);
1487 if (id
== mDNSInterface_BLE
) return(kDNSServiceInterfaceIndexBLE
);
1489 mDNSu32 scope_id
= (mDNSu32
)(uintptr_t)id
;
1491 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
1492 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1493 if (i
->scope_id
== scope_id
) return(i
->scope_id
);
1495 // If we are supposed to suppress network change, return "id" back
1496 if (suppressNetworkChange
) return scope_id
;
1498 // Not found. Make sure our interface list is up to date, then try again.
1499 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id
);
1500 mDNSMacOSXNetworkChanged(m
);
1501 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1502 if (i
->scope_id
== scope_id
) return(i
->scope_id
);
1507 #if APPLE_OSX_mDNSResponder
1508 mDNSexport
void mDNSASLLog(uuid_t
*uuid
, const char *subdomain
, const char *result
, const char *signature
, const char *fmt
, ...)
1511 return; // No ASL on iOS
1513 static char buffer
[512];
1514 aslmsg asl_msg
= asl_new(ASL_TYPE_MSG
);
1516 if (!asl_msg
) { LogMsg("mDNSASLLog: asl_new failed"); return; }
1520 uuid_unparse(*uuid
, uuidStr
);
1521 asl_set (asl_msg
, "com.apple.message.uuid", uuidStr
);
1524 static char domainBase
[] = "com.apple.mDNSResponder.%s";
1525 mDNS_snprintf (buffer
, sizeof(buffer
), domainBase
, subdomain
);
1526 asl_set (asl_msg
, "com.apple.message.domain", buffer
);
1528 if (result
) asl_set(asl_msg
, "com.apple.message.result", result
);
1529 if (signature
) asl_set(asl_msg
, "com.apple.message.signature", signature
);
1533 mDNS_vsnprintf(buffer
, sizeof(buffer
), fmt
, ptr
);
1536 int old_filter
= asl_set_filter(NULL
,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
));
1537 asl_log(NULL
, asl_msg
, ASL_LEVEL_DEBUG
, "%s", buffer
);
1538 asl_set_filter(NULL
, old_filter
);
1543 mDNSlocal
void mDNSLogDNSSECStatistics(mDNS
*const m
)
1547 aslmsg aslmsg
= asl_new(ASL_TYPE_MSG
);
1549 // If we failed to allocate an aslmsg structure, keep accumulating
1550 // the statistics and try again at the next log interval.
1553 LogMsg("mDNSLogDNSSECStatistics: asl_new() failed!");
1557 asl_set(aslmsg
,"com.apple.message.domain", "com.apple.mDNSResponder.DNSSECstatistics");
1559 if (m
->rrcache_totalused_unicast
)
1561 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", (mDNSu32
) ((unsigned long)(m
->DNSSECStats
.TotalMemUsed
* 100))/m
->rrcache_totalused_unicast
);
1565 LogMsg("mDNSLogDNSSECStatistics: unicast is zero");
1568 asl_set(aslmsg
,"com.apple.message.MemUsage", buffer
);
1570 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.Latency0
);
1571 asl_set(aslmsg
,"com.apple.message.Latency0", buffer
);
1572 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.Latency10
);
1573 asl_set(aslmsg
,"com.apple.message.Latency10", buffer
);
1574 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.Latency20
);
1575 asl_set(aslmsg
,"com.apple.message.Latency20", buffer
);
1576 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.Latency50
);
1577 asl_set(aslmsg
,"com.apple.message.Latency50", buffer
);
1578 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.Latency100
);
1579 asl_set(aslmsg
,"com.apple.message.Latency100", buffer
);
1581 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.ExtraPackets0
);
1582 asl_set(aslmsg
,"com.apple.message.ExtraPackets0", buffer
);
1583 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.ExtraPackets3
);
1584 asl_set(aslmsg
,"com.apple.message.ExtraPackets3", buffer
);
1585 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.ExtraPackets7
);
1586 asl_set(aslmsg
,"com.apple.message.ExtraPackets7", buffer
);
1587 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.ExtraPackets10
);
1588 asl_set(aslmsg
,"com.apple.message.ExtraPackets10", buffer
);
1590 // Ignore IndeterminateStatus as we don't log them
1591 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.SecureStatus
);
1592 asl_set(aslmsg
,"com.apple.message.SecureStatus", buffer
);
1593 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.InsecureStatus
);
1594 asl_set(aslmsg
,"com.apple.message.InsecureStatus", buffer
);
1595 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.BogusStatus
);
1596 asl_set(aslmsg
,"com.apple.message.BogusStatus", buffer
);
1597 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.NoResponseStatus
);
1598 asl_set(aslmsg
,"com.apple.message.NoResponseStatus", buffer
);
1600 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.NumProbesSent
);
1601 asl_set(aslmsg
,"com.apple.message.NumProbesSent", buffer
);
1602 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.MsgSize0
);
1603 asl_set(aslmsg
,"com.apple.message.MsgSize0", buffer
);
1604 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.MsgSize1
);
1605 asl_set(aslmsg
,"com.apple.message.MsgSize1", buffer
);
1606 mDNS_snprintf(buffer
, sizeof(buffer
), "%u", m
->DNSSECStats
.MsgSize2
);
1607 asl_set(aslmsg
,"com.apple.message.MsgSize2", buffer
);
1609 asl_log(NULL
, aslmsg
, ASL_LEVEL_NOTICE
, "");
1613 // Calculate packets per hour given total packet count and interval in seconds.
1614 // Cast one term of multiplication to (long) to use 64-bit arithmetic
1615 // and avoid a potential 32-bit overflow prior to the division.
1616 #define ONE_HOUR 3600
1617 #define PACKET_RATE(PACKETS, INTERVAL) (int)(((long) (PACKETS) * ONE_HOUR)/(INTERVAL))
1619 // Put packet rate data in discrete buckets.
1620 mDNSlocal
int mDNSBucketData(int inputData
, int interval
)
1624 LogMsg("mDNSBucketData: interval is zero!");
1628 int ratePerHour
= PACKET_RATE(inputData
, interval
);
1631 if (ratePerHour
== 0)
1633 else if (ratePerHour
<= 10)
1635 else if (ratePerHour
<= 100)
1637 else if (ratePerHour
<= 1000)
1639 else if (ratePerHour
<= 5000)
1641 else if (ratePerHour
<= 10000)
1643 else if (ratePerHour
<= 50000)
1645 else if (ratePerHour
<= 100000)
1647 else if (ratePerHour
<= 250000)
1649 else if (ratePerHour
<= 500000)
1657 mDNSlocal
void mDNSLogBonjourStatistics(mDNS
*const m
)
1659 static mDNSs32 last_PktNum
, last_MPktNum
;
1660 static mDNSs32 last_UnicastPacketsSent
, last_MulticastPacketsSent
;
1661 static mDNSs32 last_RemoteSubnet
;
1665 mDNSs32 inMulticast
= m
->MPktNum
- last_MPktNum
;
1666 mDNSs32 inUnicast
= m
->PktNum
- last_PktNum
- inMulticast
;
1667 mDNSs32 outUnicast
= m
->UnicastPacketsSent
- last_UnicastPacketsSent
;
1668 mDNSs32 outMulticast
= m
->MulticastPacketsSent
- last_MulticastPacketsSent
;
1669 mDNSs32 remoteSubnet
= m
->RemoteSubnet
- last_RemoteSubnet
;
1672 // save starting values for new interval
1673 last_PktNum
= m
->PktNum
;
1674 last_MPktNum
= m
->MPktNum
;
1675 last_UnicastPacketsSent
= m
->UnicastPacketsSent
;
1676 last_MulticastPacketsSent
= m
->MulticastPacketsSent
;
1677 last_RemoteSubnet
= m
->RemoteSubnet
;
1679 // Need a non-zero active time interval.
1680 if (!m
->ActiveStatTime
)
1683 // Round interval time to nearest hour boundary. Less then 30 minutes rounds to zero.
1684 interval
= (m
->ActiveStatTime
+ ONE_HOUR
/2)/ONE_HOUR
;
1686 // Use a minimum of 30 minutes of awake time to calculate average packet rates.
1687 // The rounded awake interval should not be greater than the rounded reporting
1689 if ((interval
== 0) || (interval
> (kDefaultNextStatsticsLogTime
+ ONE_HOUR
/2)/ONE_HOUR
))
1692 aslmsg aslmsg
= asl_new(ASL_TYPE_MSG
);
1696 LogMsg("mDNSLogBonjourStatistics: asl_new() failed!");
1699 // log in MessageTracer format
1700 asl_set(aslmsg
,"com.apple.message.domain", "com.apple.mDNSResponder.statistics");
1702 snprintf(buffer
, sizeof(buffer
), "%d", interval
);
1703 asl_set(aslmsg
,"com.apple.message.interval", buffer
);
1705 // log the packet rates as packets per hour
1706 snprintf(buffer
, sizeof(buffer
), "%d",
1707 mDNSBucketData(inUnicast
, m
->ActiveStatTime
));
1708 asl_set(aslmsg
,"com.apple.message.UnicastIn", buffer
);
1710 snprintf(buffer
, sizeof(buffer
), "%d",
1711 mDNSBucketData(inMulticast
, m
->ActiveStatTime
));
1712 asl_set(aslmsg
,"com.apple.message.MulticastIn", buffer
);
1714 snprintf(buffer
, sizeof(buffer
), "%d",
1715 mDNSBucketData(outUnicast
, m
->ActiveStatTime
));
1716 asl_set(aslmsg
,"com.apple.message.UnicastOut", buffer
);
1718 snprintf(buffer
, sizeof(buffer
), "%d",
1719 mDNSBucketData(outMulticast
, m
->ActiveStatTime
));
1720 asl_set(aslmsg
,"com.apple.message.MulticastOut", buffer
);
1722 snprintf(buffer
, sizeof(buffer
), "%d",
1723 mDNSBucketData(remoteSubnet
, m
->ActiveStatTime
));
1724 asl_set(aslmsg
,"com.apple.message.RemoteSubnet", buffer
);
1726 asl_log(NULL
, aslmsg
, ASL_LEVEL_NOTICE
, "");
1731 // Log multicast and unicast traffic statistics to MessageTracer on OSX
1732 mDNSexport
void mDNSLogStatistics(mDNS
*const m
)
1734 // MessageTracer only available on OSX
1738 mDNSs32 currentUTC
= mDNSPlatformUTC();
1740 // log runtime statistics
1741 if ((currentUTC
- m
->NextStatLogTime
) >= 0)
1743 m
->NextStatLogTime
= currentUTC
+ kDefaultNextStatsticsLogTime
;
1744 // If StatStartTime is zero, it hasn't been reinitialized yet
1745 // in the wakeup code path.
1746 if (m
->StatStartTime
)
1748 m
->ActiveStatTime
+= currentUTC
- m
->StatStartTime
;
1751 // Only log statistics if we have recorded some active time during
1752 // this statistics interval.
1753 if (m
->ActiveStatTime
)
1755 mDNSLogBonjourStatistics(m
);
1756 mDNSLogDNSSECStatistics(m
);
1759 // Start a new statistics gathering interval.
1760 m
->StatStartTime
= currentUTC
;
1761 m
->ActiveStatTime
= 0;
1765 #endif // APPLE_OSX_mDNSResponder
1767 #if COMPILER_LIKES_PRAGMA_MARK
1769 #pragma mark - UDP & TCP send & receive
1772 mDNSlocal mDNSBool
AddrRequiresPPPConnection(const struct sockaddr
*addr
)
1774 mDNSBool result
= mDNSfalse
;
1775 SCNetworkConnectionFlags flags
;
1776 CFDataRef remote_addr
;
1777 CFMutableDictionaryRef options
;
1778 SCNetworkReachabilityRef ReachRef
= NULL
;
1780 options
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1781 remote_addr
= CFDataCreate(NULL
, (const UInt8
*)addr
, addr
->sa_len
);
1782 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, remote_addr
);
1783 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionServerBypass
, kCFBooleanTrue
);
1784 ReachRef
= SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault
, options
);
1786 CFRelease(remote_addr
);
1790 LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions");
1793 if (!SCNetworkReachabilityGetFlags(ReachRef
, &flags
))
1795 LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags");
1798 result
= flags
& kSCNetworkFlagsConnectionRequired
;
1802 CFRelease(ReachRef
);
1806 // Set traffic class for socket
1807 mDNSlocal
void setTrafficClass(int socketfd
, mDNSBool useBackgroundTrafficClass
)
1811 if (useBackgroundTrafficClass
)
1812 traffic_class
= SO_TC_BK_SYS
;
1814 traffic_class
= SO_TC_CTL
;
1816 (void) setsockopt(socketfd
, SOL_SOCKET
, SO_TRAFFIC_CLASS
, (void *)&traffic_class
, sizeof(traffic_class
));
1819 mDNSlocal
int mDNSPlatformGetSocktFd(void *sockCxt
, mDNSTransport_Type transType
, mDNSAddr_Type addrType
)
1821 if (transType
== mDNSTransport_UDP
)
1823 UDPSocket
* sock
= (UDPSocket
*) sockCxt
;
1824 return (addrType
== mDNSAddrType_IPv4
) ? sock
->ss
.sktv4
: sock
->ss
.sktv6
;
1826 else if (transType
== mDNSTransport_TCP
)
1828 TCPSocket
* sock
= (TCPSocket
*) sockCxt
;
1829 return (addrType
== mDNSAddrType_IPv4
) ? sock
->ss
.sktv4
: sock
->ss
.sktv6
;
1833 LogInfo("mDNSPlatformGetSocktFd: invalid transport %d", transType
);
1834 return kInvalidSocketRef
;
1838 mDNSexport
void mDNSPlatformSetSocktOpt(void *sockCxt
, mDNSTransport_Type transType
, mDNSAddr_Type addrType
, DNSQuestion
*q
)
1841 char unenc_name
[MAX_ESCAPED_DOMAIN_NAME
];
1843 // verify passed-in arguments exist and that sockfd is valid
1844 if (q
== mDNSNULL
|| sockCxt
== mDNSNULL
|| (sockfd
= mDNSPlatformGetSocktFd(sockCxt
, transType
, addrType
)) < 0)
1849 if (setsockopt(sockfd
, SOL_SOCKET
, SO_DELEGATED
, &q
->pid
, sizeof(q
->pid
)) == -1)
1850 LogMsg("mDNSPlatformSetSocktOpt: Delegate PID failed %s for PID %d", strerror(errno
), q
->pid
);
1854 if (setsockopt(sockfd
, SOL_SOCKET
, SO_DELEGATED_UUID
, &q
->uuid
, sizeof(q
->uuid
)) == -1)
1855 LogMsg("mDNSPlatformSetSocktOpt: Delegate UUID failed %s", strerror(errno
));
1858 // set the domain on the socket
1859 ConvertDomainNameToCString(&q
->qname
, unenc_name
);
1860 if (!(ne_session_set_socket_attributes(sockfd
, unenc_name
, NULL
)))
1861 LogInfo("mDNSPlatformSetSocktOpt: ne_session_set_socket_attributes()-> setting domain failed for %s", unenc_name
);
1864 if (setsockopt(sockfd
, SOL_SOCKET
, SO_NOWAKEFROMSLEEP
, &nowake
, sizeof(nowake
)) == -1)
1865 LogInfo("mDNSPlatformSetSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno
));
1867 if ((q
->flags
& kDNSServiceFlagsDenyCellular
) || (q
->flags
& kDNSServiceFlagsDenyExpensive
))
1869 #if defined(SO_RESTRICT_DENY_CELLULAR)
1870 if (q
->flags
& kDNSServiceFlagsDenyCellular
)
1872 int restrictions
= 0;
1873 restrictions
= SO_RESTRICT_DENY_CELLULAR
;
1874 if (setsockopt(sockfd
, SOL_SOCKET
, SO_RESTRICTIONS
, &restrictions
, sizeof(restrictions
)) == -1)
1875 LogMsg("mDNSPlatformSetSocktOpt: SO_RESTRICT_DENY_CELLULAR failed %s", strerror(errno
));
1878 #if defined(SO_RESTRICT_DENY_EXPENSIVE)
1879 if (q
->flags
& kDNSServiceFlagsDenyExpensive
)
1881 int restrictions
= 0;
1882 restrictions
= SO_RESTRICT_DENY_EXPENSIVE
;
1883 if (setsockopt(sockfd
, SOL_SOCKET
, SO_RESTRICTIONS
, &restrictions
, sizeof(restrictions
)) == -1)
1884 LogMsg("mDNSPlatformSetSocktOpt: SO_RESTRICT_DENY_EXPENSIVE failed %s", strerror(errno
));
1890 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
1891 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
1892 // OR send via our primary v4 unicast socket
1893 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
1894 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
1895 mDNSInterfaceID InterfaceID
, UDPSocket
*src
, const mDNSAddr
*dst
,
1896 mDNSIPPort dstPort
, mDNSBool useBackgroundTrafficClass
)
1898 NetworkInterfaceInfoOSX
*info
= mDNSNULL
;
1899 struct sockaddr_storage to
;
1901 mStatus result
= mStatus_NoError
;
1905 info
= IfindexToInterfaceInfoOSX(m
, InterfaceID
);
1908 // We may not have registered interfaces with the "core" as we may not have
1909 // seen any interface notifications yet. This typically happens during wakeup
1910 // where we might try to send DNS requests (non-SuppressUnusable questions internal
1911 // to mDNSResponder) before we receive network notifications.
1912 LogInfo("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID
);
1913 return mStatus_BadParamErr
;
1917 char *ifa_name
= InterfaceID
? info
->ifinfo
.ifname
: "unicast";
1919 if (dst
->type
== mDNSAddrType_IPv4
)
1921 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
1922 sin_to
->sin_len
= sizeof(*sin_to
);
1923 sin_to
->sin_family
= AF_INET
;
1924 sin_to
->sin_port
= dstPort
.NotAnInteger
;
1925 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1926 s
= (src
? src
->ss
: m
->p
->permanentsockets
).sktv4
;
1928 if (info
) // Specify outgoing interface
1930 if (!mDNSAddrIsDNSMulticast(dst
))
1933 if (info
->scope_id
== 0)
1934 LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info
, ifa_name
);
1936 setsockopt(s
, IPPROTO_IP
, IP_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1939 static int displayed
= 0;
1940 if (displayed
< 1000)
1943 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
1949 #ifdef IP_MULTICAST_IFINDEX
1951 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IFINDEX
, &info
->scope_id
, sizeof(info
->scope_id
));
1952 // We get an error when we compile on a machine that supports this option and run the binary on
1953 // a different machine that does not support it
1956 if (errno
!= ENOPROTOOPT
) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno
);
1957 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
1958 if (err
< 0 && !m
->NetworkChanged
)
1959 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
1964 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
1965 if (err
< 0 && !m
->NetworkChanged
)
1966 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
1973 else if (dst
->type
== mDNSAddrType_IPv6
)
1975 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
1976 sin6_to
->sin6_len
= sizeof(*sin6_to
);
1977 sin6_to
->sin6_family
= AF_INET6
;
1978 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
1979 sin6_to
->sin6_flowinfo
= 0;
1980 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1981 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
1982 s
= (src
? src
->ss
: m
->p
->permanentsockets
).sktv6
;
1983 if (info
&& mDNSAddrIsDNSMulticast(dst
)) // Specify outgoing interface
1985 err
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1988 char name
[IFNAMSIZ
];
1989 if (if_indextoname(info
->scope_id
, name
) != NULL
)
1990 LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err
, errno
, strerror(errno
));
1992 LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info
->scope_id
);
1995 #ifdef IPV6_BOUND_IF
1996 if (info
) // Specify outgoing interface for non-multicast destination
1998 if (!mDNSAddrIsDNSMulticast(dst
))
2000 if (info
->scope_id
== 0)
2001 LogInfo("IPV6_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info
, ifa_name
);
2003 setsockopt(s
, IPPROTO_IPV6
, IPV6_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
2011 LogFatalError("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
2012 return mStatus_BadParamErr
;
2016 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
2017 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
2019 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
2020 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
2022 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
2023 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
2024 if (s
< 0) return(mStatus_Invalid
);
2026 // switch to background traffic class for this message if requested
2027 if (useBackgroundTrafficClass
)
2028 setTrafficClass(s
, useBackgroundTrafficClass
);
2030 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
2032 // set traffic class back to default value
2033 if (useBackgroundTrafficClass
)
2034 setTrafficClass(s
, mDNSfalse
);
2038 static int MessageCount
= 0;
2039 LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
2040 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
2041 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
2043 if (errno
== EHOSTUNREACH
) return(mStatus_HostUnreachErr
);
2044 if (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== ENETUNREACH
) return(mStatus_TransientErr
);
2046 // Don't report EHOSTUNREACH in the first three minutes after boot
2047 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
2048 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
2049 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(mStatus_TransientErr
);
2050 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
2051 if (errno
== EADDRNOTAVAIL
&& m
->NetworkChanged
) return(mStatus_TransientErr
);
2052 if (errno
== EHOSTUNREACH
|| errno
== EADDRNOTAVAIL
|| errno
== ENETDOWN
)
2053 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
2054 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
2058 if (MessageCount
< 50) // Cap and ensure NO spamming of LogMsgs
2059 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",
2060 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
), MessageCount
);
2061 else // If logging is enabled, remove the cap and log aggressively
2062 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",
2063 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
), MessageCount
);
2066 result
= mStatus_UnknownErr
;
2072 mDNSexport ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
2073 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
2075 static unsigned int numLogMessages
= 0;
2076 struct iovec databuffers
= { (char *)buffer
, max
};
2079 struct cmsghdr
*cmPtr
;
2080 char ancillary
[1024];
2082 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
2084 // Set up the message
2085 msg
.msg_name
= (caddr_t
)from
;
2086 msg
.msg_namelen
= *fromlen
;
2087 msg
.msg_iov
= &databuffers
;
2089 msg
.msg_control
= (caddr_t
)&ancillary
;
2090 msg
.msg_controllen
= sizeof(ancillary
);
2094 n
= recvmsg(s
, &msg
, 0);
2097 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
2100 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
2102 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d",
2103 s
, n
, msg
.msg_controllen
, sizeof(struct cmsghdr
), errno
);
2106 if (msg
.msg_flags
& MSG_CTRUNC
)
2108 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
2112 *fromlen
= msg
.msg_namelen
;
2114 // Parse each option out of the ancillary data.
2115 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
2117 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
2118 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
2120 dstaddr
->type
= mDNSAddrType_IPv4
;
2121 dstaddr
->ip
.v4
= *(mDNSv4Addr
*)CMSG_DATA(cmPtr
);
2122 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
2124 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
2126 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
2127 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
2129 mDNSPlatformMemCopy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
2130 ifname
[sdl
->sdl_nlen
] = 0;
2131 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
2134 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
2135 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
2136 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
2138 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
2139 dstaddr
->type
= mDNSAddrType_IPv6
;
2140 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
2141 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
2143 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
2144 *ttl
= *(int*)CMSG_DATA(cmPtr
);
2150 // What is this for, and why does it use xor instead of a simple quality check? -- SC
2151 mDNSlocal mDNSInterfaceID
FindMyInterface(mDNS
*const m
, const mDNSAddr
*addr
)
2153 NetworkInterfaceInfo
*intf
;
2155 if (addr
->type
== mDNSAddrType_IPv4
)
2157 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
2159 if (intf
->ip
.type
== addr
->type
&& intf
->McastTxRx
)
2161 if ((intf
->ip
.ip
.v4
.NotAnInteger
^ addr
->ip
.v4
.NotAnInteger
) == 0)
2163 return(intf
->InterfaceID
);
2169 if (addr
->type
== mDNSAddrType_IPv6
)
2171 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
2173 if (intf
->ip
.type
== addr
->type
&& intf
->McastTxRx
)
2175 if (((intf
->ip
.ip
.v6
.l
[0] ^ addr
->ip
.v6
.l
[0]) == 0) &&
2176 ((intf
->ip
.ip
.v6
.l
[1] ^ addr
->ip
.v6
.l
[1]) == 0) &&
2177 ((intf
->ip
.ip
.v6
.l
[2] ^ addr
->ip
.v6
.l
[2]) == 0) &&
2178 (((intf
->ip
.ip
.v6
.l
[3] ^ addr
->ip
.v6
.l
[3]) == 0)))
2180 return(intf
->InterfaceID
);
2185 return(mDNSInterface_Any
);
2188 mDNSexport
void myKQSocketCallBack(int s1
, short filter
, void *context
)
2190 KQSocketSet
*const ss
= (KQSocketSet
*)context
;
2191 mDNS
*const m
= ss
->m
;
2192 int err
= 0, count
= 0, closed
= 0;
2194 if (filter
!= EVFILT_READ
)
2195 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter
, EVFILT_READ
);
2197 if (s1
!= ss
->sktv4
&& s1
!= ss
->sktv6
)
2199 LogMsg("myKQSocketCallBack: native socket %d", s1
);
2200 LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss
->sktv4
, ss
->sktv6
);
2205 mDNSAddr senderAddr
, destAddr
= zeroAddr
;
2206 mDNSIPPort senderPort
;
2207 struct sockaddr_storage from
;
2208 size_t fromlen
= sizeof(from
);
2209 char packetifname
[IF_NAMESIZE
] = "";
2211 err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
2214 if ((destAddr
.type
== mDNSAddrType_IPv4
&& (destAddr
.ip
.v4
.b
[0] & 0xF0) == 0xE0) ||
2215 (destAddr
.type
== mDNSAddrType_IPv6
&& (destAddr
.ip
.v6
.b
[0] == 0xFF))) m
->p
->num_mcasts
++;
2218 if (from
.ss_family
== AF_INET
)
2220 struct sockaddr_in
*s
= (struct sockaddr_in
*)&from
;
2221 senderAddr
.type
= mDNSAddrType_IPv4
;
2222 senderAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
2223 senderPort
.NotAnInteger
= s
->sin_port
;
2224 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
2226 else if (from
.ss_family
== AF_INET6
)
2228 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
2229 senderAddr
.type
= mDNSAddrType_IPv6
;
2230 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
2231 senderPort
.NotAnInteger
= sin6
->sin6_port
;
2232 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
2236 LogMsg("myKQSocketCallBack from is unknown address family %d", from
.ss_family
);
2240 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
2241 mDNSInterfaceID InterfaceID
= mDNSNULL
;
2242 NetworkInterfaceInfoOSX
*intf
= m
->p
->InterfaceList
;
2245 if (intf
->Exists
&& !strcmp(intf
->ifinfo
.ifname
, packetifname
))
2250 // When going to sleep we deregister all our interfaces, but if the machine
2251 // takes a few seconds to sleep we may continue to receive multicasts
2252 // during that time, which would confuse mDNSCoreReceive, because as far
2253 // as it's concerned, we should have no active interfaces any more.
2254 // Hence we ignore multicasts for which we can find no matching InterfaceID.
2256 InterfaceID
= intf
->ifinfo
.InterfaceID
;
2257 else if (mDNSAddrIsDNSMulticast(&destAddr
))
2262 InterfaceID
= FindMyInterface(m
, &destAddr
);
2265 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
2266 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
2268 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
2269 // loop when that happens, or we may try to read from an invalid FD. We do this by
2270 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
2271 // if it closes the socketset.
2272 ss
->closeFlag
= &closed
;
2276 m
->p
->UDPProxyCallback(m
, &m
->p
->UDPProxy
, (unsigned char *)&m
->imsg
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
,
2277 senderPort
, &destAddr
, ss
->port
, InterfaceID
, NULL
);
2281 mDNSCoreReceive(m
, &m
->imsg
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, ss
->port
, InterfaceID
);
2284 // if we didn't close, we can safely dereference the socketset, and should to
2285 // reset the closeFlag, since it points to something on the stack
2286 if (!closed
) ss
->closeFlag
= mDNSNULL
;
2289 // If a client application is put in the background, it's socket to us can go defunct and
2290 // we'll get an ENOTCONN error on that connection. Just close the socket in that case.
2291 if (err
< 0 && errno
== ENOTCONN
)
2293 LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
2298 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
2300 // Something is busted here.
2301 // kqueue says there is a packet, but myrecvfrom says there is not.
2302 // Try calling select() to get another opinion.
2303 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
2304 // All of this is racy, as data may have arrived after the call to select()
2305 static unsigned int numLogMessages
= 0;
2306 int save_errno
= errno
;
2310 socklen_t solen
= sizeof(int);
2312 struct timeval timeout
;
2315 FD_SET(s1
, &readfds
);
2317 timeout
.tv_usec
= 0;
2318 selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
2319 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
2320 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
2321 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
2322 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
2323 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
2324 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno
);
2325 if (numLogMessages
++ < 100)
2326 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
2327 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
2328 if (numLogMessages
> 5)
2329 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
2330 "Congratulations, you've reproduced an elusive bug.\r"
2331 "Please contact the current assignee of <rdar://problem/3375328>.\r"
2332 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2333 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2335 sleep(1); // After logging this error, rate limit so we don't flood syslog
2339 mDNSlocal
void doTcpSocketCallback(TCPSocket
*sock
)
2341 mDNSBool c
= !sock
->connected
;
2342 sock
->connected
= mDNStrue
;
2343 sock
->callback(sock
, sock
->context
, c
, sock
->err
);
2344 // Note: the callback may call CloseConnection here, which frees the context structure!
2347 #ifndef NO_SECURITYFRAMEWORK
2349 mDNSlocal OSStatus
tlsWriteSock(SSLConnectionRef connection
, const void *data
, size_t *dataLength
)
2351 int ret
= send(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
2352 if (ret
>= 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
2353 if (ret
>= 0) { *dataLength
= ret
; return(noErr
); }
2355 if (errno
== EAGAIN
) return(errSSLWouldBlock
);
2356 if (errno
== ENOENT
) return(errSSLClosedGraceful
);
2357 if (errno
== EPIPE
|| errno
== ECONNRESET
) return(errSSLClosedAbort
);
2358 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket
*)connection
)->fd
, errno
, strerror(errno
));
2359 return(errSSLClosedAbort
);
2362 mDNSlocal OSStatus
tlsReadSock(SSLConnectionRef connection
, void *data
, size_t *dataLength
)
2364 int ret
= recv(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
2365 if (ret
> 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
2366 if (ret
> 0) { *dataLength
= ret
; return(noErr
); }
2368 if (ret
== 0 || errno
== ENOENT
) return(errSSLClosedGraceful
);
2369 if ( errno
== EAGAIN
) return(errSSLWouldBlock
);
2370 if ( errno
== ECONNRESET
) return(errSSLClosedAbort
);
2371 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno
, strerror(errno
));
2372 return(errSSLClosedAbort
);
2375 mDNSlocal OSStatus
tlsSetupSock(TCPSocket
*sock
, SSLProtocolSide pside
, SSLConnectionType ctype
)
2377 char domname_cstr
[MAX_ESCAPED_DOMAIN_NAME
];
2379 sock
->tlsContext
= SSLCreateContext(kCFAllocatorDefault
, pside
, ctype
);
2380 if (!sock
->tlsContext
)
2382 LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
2383 return(mStatus_UnknownErr
);
2386 mStatus err
= SSLSetIOFuncs(sock
->tlsContext
, tlsReadSock
, tlsWriteSock
);
2389 LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err
);
2393 err
= SSLSetConnection(sock
->tlsContext
, (SSLConnectionRef
) sock
);
2396 LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err
);
2400 // Instead of listing all the acceptable ciphers, we just disable the bad ciphers. It does not disable
2401 // all the bad ciphers like RC4_MD5, but it assumes that the servers don't offer them.
2402 err
= SSLSetAllowAnonymousCiphers(sock
->tlsContext
, 0);
2405 LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err
);
2409 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
2410 // (error not in OSStatus space) is okay.
2411 if (!sock
->hostname
.c
[0])
2413 LogMsg("ERROR: tlsSetupSock: hostname NULL");
2418 ConvertDomainNameToCString(&sock
->hostname
, domname_cstr
);
2419 err
= SSLSetPeerDomainName(sock
->tlsContext
, domname_cstr
, strlen(domname_cstr
));
2422 LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr
, err
);
2429 if (sock
->tlsContext
)
2430 CFRelease(sock
->tlsContext
);
2434 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2435 mDNSlocal
void doSSLHandshake(TCPSocket
*sock
)
2437 mStatus err
= SSLHandshake(sock
->tlsContext
);
2439 //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
2440 //defined, KQueueLock is a noop. Hence we need to serialize here
2442 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
2443 //We need the rest of the logic also. Otherwise, we can enable the READ
2444 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
2445 //ConnFailed which means we are going to free the tcpInfo. While it
2446 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
2447 //and potentially call doTCPCallback with error which can close the fd and free the
2448 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
2451 dispatch_async(dispatch_get_main_queue(), ^{
2453 LogInfo("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
2455 if (sock
->handshake
== handshake_to_be_closed
)
2457 LogInfo("SSLHandshake completed after close");
2458 mDNSPlatformTCPCloseConnection(sock
);
2462 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
2463 else LogMsg("doSSLHandshake: sock->fd is -1");
2465 if (err
== errSSLWouldBlock
)
2466 sock
->handshake
= handshake_required
;
2471 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
2472 CFRelease(sock
->tlsContext
);
2473 sock
->tlsContext
= NULL
;
2476 sock
->err
= err
? mStatus_ConnFailed
: 0;
2477 sock
->handshake
= handshake_completed
;
2479 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
2480 doTcpSocketCallback(sock
);
2484 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
2488 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2489 mDNSlocal
void *doSSLHandshake(TCPSocket
*sock
)
2491 // Warning: Touching sock without the kqueue lock!
2492 // We're protected because sock->handshake == handshake_in_progress
2493 mDNS
* const m
= sock
->m
; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
2494 mStatus err
= SSLHandshake(sock
->tlsContext
);
2497 debugf("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
2499 if (sock
->handshake
== handshake_to_be_closed
)
2501 LogInfo("SSLHandshake completed after close");
2502 mDNSPlatformTCPCloseConnection(sock
);
2506 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
2507 else LogMsg("doSSLHandshake: sock->fd is -1");
2509 if (err
== errSSLWouldBlock
)
2510 sock
->handshake
= handshake_required
;
2515 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
2516 CFRelease(sock
->tlsContext
);
2517 sock
->tlsContext
= NULL
;
2520 sock
->err
= err
? mStatus_ConnFailed
: 0;
2521 sock
->handshake
= handshake_completed
;
2523 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
2524 doTcpSocketCallback(sock
);
2528 debugf("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
2529 KQueueUnlock(m
, "doSSLHandshake");
2532 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2534 mDNSlocal
void spawnSSLHandshake(TCPSocket
* sock
)
2536 debugf("spawnSSLHandshake %p: entry", sock
);
2538 if (sock
->handshake
!= handshake_required
) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock
->handshake
);
2539 sock
->handshake
= handshake_in_progress
;
2540 KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_READ
, sock
->kqEntry
);
2542 // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
2543 // to limit the number of threads used for SSLHandshake
2544 dispatch_async(SSLqueue
, ^{doSSLHandshake(sock
);});
2546 debugf("spawnSSLHandshake %p: done for %d", sock
, sock
->fd
);
2549 #endif /* NO_SECURITYFRAMEWORK */
2551 mDNSlocal
void tcpKQSocketCallback(__unused
int fd
, short filter
, void *context
)
2553 TCPSocket
*sock
= context
;
2554 sock
->err
= mStatus_NoError
;
2556 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
2557 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
2558 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
2559 if (filter
== EVFILT_WRITE
)
2560 KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_WRITE
, sock
->kqEntry
);
2562 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
2564 #ifndef NO_SECURITYFRAMEWORK
2567 sock
->setup
= mDNStrue
;
2568 sock
->err
= tlsSetupSock(sock
, kSSLClientSide
, kSSLStreamType
);
2571 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock
->err
);
2575 if (sock
->handshake
== handshake_required
)
2577 spawnSSLHandshake(sock
);
2580 else if (sock
->handshake
== handshake_in_progress
|| sock
->handshake
== handshake_to_be_closed
)
2584 else if (sock
->handshake
!= handshake_completed
)
2587 sock
->err
= mStatus_UnknownErr
;
2588 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock
->handshake
);
2590 #else /* NO_SECURITYFRAMEWORK */
2591 sock
->err
= mStatus_UnsupportedErr
;
2592 #endif /* NO_SECURITYFRAMEWORK */
2595 doTcpSocketCallback(sock
);
2598 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2599 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, KQueueEntry
*const entryRef
)
2601 dispatch_queue_t queue
= dispatch_get_main_queue();
2602 dispatch_source_t source
;
2603 if (flags
== EV_DELETE
)
2605 if (filter
== EVFILT_READ
)
2607 dispatch_source_cancel(entryRef
->readSource
);
2608 dispatch_release(entryRef
->readSource
);
2609 entryRef
->readSource
= mDNSNULL
;
2610 debugf("KQueueSet: source cancel for read %p, %p", entryRef
->readSource
, entryRef
->writeSource
);
2612 else if (filter
== EVFILT_WRITE
)
2614 dispatch_source_cancel(entryRef
->writeSource
);
2615 dispatch_release(entryRef
->writeSource
);
2616 entryRef
->writeSource
= mDNSNULL
;
2617 debugf("KQueueSet: source cancel for write %p, %p", entryRef
->readSource
, entryRef
->writeSource
);
2620 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter
);
2623 if (flags
!= EV_ADD
) LogMsg("KQueueSet: Invalid flags %d", flags
);
2625 if (filter
== EVFILT_READ
)
2627 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, fd
, 0, queue
);
2629 else if (filter
== EVFILT_WRITE
)
2631 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE
, fd
, 0, queue
);
2635 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter
);
2638 if (!source
) return -1;
2639 dispatch_source_set_event_handler(source
, ^{
2641 mDNSs32 stime
= mDNSPlatformRawTime();
2642 entryRef
->KQcallback(fd
, filter
, entryRef
->KQcontext
);
2643 mDNSs32 etime
= mDNSPlatformRawTime();
2644 if (etime
- stime
>= WatchDogReportingThreshold
)
2645 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime
- stime
);
2647 // Trigger the event delivery to the application. Even though we trigger the
2648 // event completion after handling every event source, these all will hopefully
2650 TriggerEventCompletion();
2653 dispatch_source_set_cancel_handler(source
, ^{
2654 if (entryRef
->fdClosed
)
2656 //LogMsg("CancelHandler: closing fd %d", fd);
2660 dispatch_resume(source
);
2661 if (filter
== EVFILT_READ
)
2662 entryRef
->readSource
= source
;
2664 entryRef
->writeSource
= source
;
2669 mDNSexport
void KQueueLock(mDNS
*const m
)
2673 mDNSexport
void KQueueUnlock(mDNS
*const m
, const char const *task
)
2676 (void)task
; //unused
2679 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, const KQueueEntry
*const entryRef
)
2681 struct kevent new_event
;
2682 EV_SET(&new_event
, fd
, filter
, flags
, 0, 0, (void*)entryRef
);
2683 return (kevent(KQueueFD
, &new_event
, 1, NULL
, 0, NULL
) < 0) ? errno
: 0;
2686 mDNSexport
void KQueueLock(mDNS
*const m
)
2688 pthread_mutex_lock(&m
->p
->BigMutex
);
2689 m
->p
->BigMutexStartTime
= mDNSPlatformRawTime();
2692 mDNSexport
void KQueueUnlock(mDNS
*const m
, const char* task
)
2694 mDNSs32 end
= mDNSPlatformRawTime();
2696 if (end
- m
->p
->BigMutexStartTime
>= WatchDogReportingThreshold
)
2697 LogInfo("WARNING: %s took %dms to complete", task
, end
- m
->p
->BigMutexStartTime
);
2699 pthread_mutex_unlock(&m
->p
->BigMutex
);
2702 if (send(m
->p
->WakeKQueueLoopFD
, &wake
, sizeof(wake
), 0) == -1)
2703 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno
, strerror(errno
));
2707 mDNSexport
void mDNSPlatformCloseFD(KQueueEntry
*kq
, int fd
)
2709 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2713 dispatch_source_cancel(kq
->readSource
);
2714 kq
->readSource
= mDNSNULL
;
2716 if (kq
->writeSource
)
2718 dispatch_source_cancel(kq
->writeSource
);
2719 kq
->writeSource
= mDNSNULL
;
2721 // Close happens in the cancellation handler
2722 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd
);
2723 kq
->fdClosed
= mDNStrue
;
2730 mDNSlocal mStatus
SetupTCPSocket(TCPSocket
*sock
, u_short sa_family
, mDNSIPPort
*port
, mDNSBool useBackgroundTrafficClass
)
2732 KQSocketSet
*cp
= &sock
->ss
;
2733 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
2734 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
2735 const int on
= 1; // "on" for setsockopt
2738 int skt
= socket(sa_family
, SOCK_STREAM
, IPPROTO_TCP
);
2739 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
));return(skt
); }
2741 // for TCP sockets, the traffic class is set once and not changed
2742 setTrafficClass(skt
, useBackgroundTrafficClass
);
2744 if (sa_family
== AF_INET
)
2747 struct sockaddr_in addr
;
2748 mDNSPlatformMemZero(&addr
, sizeof(addr
));
2749 addr
.sin_family
= AF_INET
;
2750 addr
.sin_port
= port
->NotAnInteger
;
2751 err
= bind(skt
, (struct sockaddr
*) &addr
, sizeof(addr
));
2752 if (err
< 0) { LogMsg("ERROR: bind %s", strerror(errno
)); close(skt
); return err
; }
2754 // Receive interface identifiers
2755 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
2756 if (err
< 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
)); close(skt
); return err
; }
2758 mDNSPlatformMemZero(&addr
, sizeof(addr
));
2759 socklen_t len
= sizeof(addr
);
2760 err
= getsockname(skt
, (struct sockaddr
*) &addr
, &len
);
2761 if (err
< 0) { LogMsg("getsockname - %s", strerror(errno
)); close(skt
); return err
; }
2763 port
->NotAnInteger
= addr
.sin_port
;
2768 struct sockaddr_in6 addr6
;
2769 mDNSPlatformMemZero(&addr6
, sizeof(addr6
));
2770 addr6
.sin6_family
= AF_INET6
;
2771 addr6
.sin6_port
= port
->NotAnInteger
;
2772 err
= bind(skt
, (struct sockaddr
*) &addr6
, sizeof(addr6
));
2773 if (err
< 0) { LogMsg("ERROR: bind6 %s", strerror(errno
)); close(skt
); return err
; }
2775 // We want to receive destination addresses and receive interface identifiers
2776 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
2777 if (err
< 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno
)); close(skt
); return err
; }
2779 mDNSPlatformMemZero(&addr6
, sizeof(addr6
));
2780 socklen_t len
= sizeof(addr6
);
2781 err
= getsockname(skt
, (struct sockaddr
*) &addr6
, &len
);
2782 if (err
< 0) { LogMsg("getsockname6 - %s", strerror(errno
)); close(skt
); return err
; }
2784 port
->NotAnInteger
= addr6
.sin6_port
;
2788 k
->KQcallback
= tcpKQSocketCallback
;
2789 k
->KQcontext
= sock
;
2790 k
->KQtask
= "mDNSPlatformTCPSocket";
2791 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2792 k
->readSource
= mDNSNULL
;
2793 k
->writeSource
= mDNSNULL
;
2794 k
->fdClosed
= mDNSfalse
;
2796 return mStatus_NoError
;
2799 mDNSexport TCPSocket
*mDNSPlatformTCPSocket(mDNS
*const m
, TCPSocketFlags flags
, mDNSIPPort
*port
, mDNSBool useBackgroundTrafficClass
)
2804 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket
));
2805 if (!sock
) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL
); }
2807 mDNSPlatformMemZero(sock
, sizeof(TCPSocket
));
2810 sock
->ss
.sktv4
= -1;
2811 sock
->ss
.sktv6
= -1;
2812 err
= SetupTCPSocket(sock
, AF_INET
, port
, useBackgroundTrafficClass
);
2816 err
= SetupTCPSocket(sock
, AF_INET6
, port
, useBackgroundTrafficClass
);
2817 if (err
) { mDNSPlatformCloseFD(&sock
->ss
.kqsv4
, sock
->ss
.sktv4
); sock
->ss
.sktv4
= -1; }
2821 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock
->fd
, errno
, strerror(errno
));
2822 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
2825 // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
2826 sock
->fd
= sock
->ss
.sktv4
;
2827 sock
->callback
= mDNSNULL
;
2828 sock
->flags
= flags
;
2829 sock
->context
= mDNSNULL
;
2830 sock
->setup
= mDNSfalse
;
2831 sock
->connected
= mDNSfalse
;
2832 sock
->handshake
= handshake_required
;
2834 sock
->err
= mStatus_NoError
;
2839 mDNSexport mStatus
mDNSPlatformTCPConnect(TCPSocket
*sock
, const mDNSAddr
*dst
, mDNSOpaque16 dstport
, domainname
*hostname
, mDNSInterfaceID InterfaceID
, TCPConnectionCallback callback
, void *context
)
2841 KQSocketSet
*cp
= &sock
->ss
;
2842 int *s
= (dst
->type
== mDNSAddrType_IPv4
) ? &cp
->sktv4
: &cp
->sktv6
;
2843 KQueueEntry
*k
= (dst
->type
== mDNSAddrType_IPv4
) ? &cp
->kqsv4
: &cp
->kqsv6
;
2844 mStatus err
= mStatus_NoError
;
2845 struct sockaddr_storage ss
;
2847 sock
->callback
= callback
;
2848 sock
->context
= context
;
2849 sock
->setup
= mDNSfalse
;
2850 sock
->connected
= mDNSfalse
;
2851 sock
->handshake
= handshake_required
;
2852 sock
->err
= mStatus_NoError
;
2854 if (hostname
) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname
->c
); AssignDomainName(&sock
->hostname
, hostname
); }
2856 if (dst
->type
== mDNSAddrType_IPv4
)
2858 struct sockaddr_in
*saddr
= (struct sockaddr_in
*)&ss
;
2859 mDNSPlatformMemZero(saddr
, sizeof(*saddr
));
2860 saddr
->sin_family
= AF_INET
;
2861 saddr
->sin_port
= dstport
.NotAnInteger
;
2862 saddr
->sin_len
= sizeof(*saddr
);
2863 saddr
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
2867 struct sockaddr_in6
*saddr6
= (struct sockaddr_in6
*)&ss
;
2868 mDNSPlatformMemZero(saddr6
, sizeof(*saddr6
));
2869 saddr6
->sin6_family
= AF_INET6
;
2870 saddr6
->sin6_port
= dstport
.NotAnInteger
;
2871 saddr6
->sin6_len
= sizeof(*saddr6
);
2872 saddr6
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
2875 // Watch for connect complete (write is ready)
2876 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
2877 if (KQueueSet(*s
, EV_ADD
/* | EV_ONESHOT */, EVFILT_WRITE
, k
))
2879 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
2883 // Watch for incoming data
2884 if (KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
))
2886 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
2890 if (fcntl(*s
, F_SETFL
, fcntl(*s
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
2892 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
2893 return mStatus_UnknownErr
;
2896 // We bind to the interface and all subsequent packets including the SYN will be sent out
2897 // on this interface
2899 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
2900 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
2901 if (InterfaceID
&& InterfaceID
!= mDNSInterface_Unicast
)
2903 NetworkInterfaceInfoOSX
*info
= IfindexToInterfaceInfoOSX(&mDNSStorage
, InterfaceID
);
2904 if (dst
->type
== mDNSAddrType_IPv4
)
2907 if (info
) setsockopt(*s
, IPPROTO_IP
, IP_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
2908 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID
); return mStatus_BadParamErr
; }
2910 (void)InterfaceID
; // Unused
2911 (void)info
; // Unused
2916 #ifdef IPV6_BOUND_IF
2917 if (info
) setsockopt(*s
, IPPROTO_IPV6
, IPV6_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
2918 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID
); return mStatus_BadParamErr
; }
2920 (void)InterfaceID
; // Unused
2921 (void)info
; // Unused
2926 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
2927 // from which we can infer the destination address family. Hence we need to remember that here.
2928 // Instead of remembering the address family, we remember the right fd.
2931 // initiate connection wth peer
2932 if (connect(*s
, (struct sockaddr
*)&ss
, ss
.ss_len
) < 0)
2934 if (errno
== EINPROGRESS
) return mStatus_ConnPending
;
2935 if (errno
== EHOSTUNREACH
|| errno
== EADDRNOTAVAIL
|| errno
== ENETDOWN
)
2936 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock
->fd
, errno
, strerror(errno
));
2938 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock
->fd
, errno
, strerror(errno
), ss
.ss_len
);
2939 return mStatus_ConnFailed
;
2942 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
2943 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
2947 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
2948 mDNSexport TCPSocket
*mDNSPlatformTCPAccept(TCPSocketFlags flags
, int fd
)
2950 mStatus err
= mStatus_NoError
;
2952 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket
));
2953 if (!sock
) return(mDNSNULL
);
2955 mDNSPlatformMemZero(sock
, sizeof(*sock
));
2957 sock
->flags
= flags
;
2959 if (flags
& kTCPSocketFlags_UseTLS
)
2961 #ifndef NO_SECURITYFRAMEWORK
2962 if (!ServerCerts
) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err
= mStatus_UnknownErr
; goto exit
; }
2964 err
= tlsSetupSock(sock
, kSSLServerSide
, kSSLStreamType
);
2965 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err
); goto exit
; }
2967 err
= SSLSetCertificate(sock
->tlsContext
, ServerCerts
);
2968 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err
); goto exit
; }
2970 err
= mStatus_UnsupportedErr
;
2971 #endif /* NO_SECURITYFRAMEWORK */
2973 #ifndef NO_SECURITYFRAMEWORK
2977 if (err
) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock
); return(mDNSNULL
); }
2981 mDNSexport mDNSu16
mDNSPlatformGetUDPPort(UDPSocket
*sock
)
2988 port
= sock
->ss
.port
.NotAnInteger
;
2993 mDNSlocal
void CloseSocketSet(KQSocketSet
*ss
)
2995 if (ss
->sktv4
!= -1)
2997 mDNSPlatformCloseFD(&ss
->kqsv4
, ss
->sktv4
);
3000 if (ss
->sktv6
!= -1)
3002 mDNSPlatformCloseFD(&ss
->kqsv6
, ss
->sktv6
);
3005 if (ss
->closeFlag
) *ss
->closeFlag
= 1;
3008 mDNSexport
void mDNSPlatformTCPCloseConnection(TCPSocket
*sock
)
3012 #ifndef NO_SECURITYFRAMEWORK
3013 if (sock
->tlsContext
)
3015 if (sock
->handshake
== handshake_in_progress
) // SSLHandshake thread using this sock (esp. tlsContext)
3017 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
3018 // When we come back from SSLHandshake, we will notice that a close was here and
3019 // call this function again which will do the cleanup then.
3020 sock
->handshake
= handshake_to_be_closed
;
3024 SSLClose(sock
->tlsContext
);
3025 CFRelease(sock
->tlsContext
);
3026 sock
->tlsContext
= NULL
;
3028 #endif /* NO_SECURITYFRAMEWORK */
3029 if (sock
->ss
.sktv4
!= -1)
3030 shutdown(sock
->ss
.sktv4
, 2);
3031 if (sock
->ss
.sktv6
!= -1)
3032 shutdown(sock
->ss
.sktv6
, 2);
3033 CloseSocketSet(&sock
->ss
);
3036 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock
);
3040 mDNSexport
long mDNSPlatformReadTCP(TCPSocket
*sock
, void *buf
, unsigned long buflen
, mDNSBool
*closed
)
3043 *closed
= mDNSfalse
;
3045 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
3047 #ifndef NO_SECURITYFRAMEWORK
3048 if (sock
->handshake
== handshake_required
) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
3049 else if (sock
->handshake
== handshake_in_progress
) return 0;
3050 else if (sock
->handshake
!= handshake_completed
) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock
->handshake
);
3052 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
3053 mStatus err
= SSLRead(sock
->tlsContext
, buf
, buflen
, (size_t *)&nread
);
3054 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
3055 if (err
== errSSLClosedGraceful
) { nread
= 0; *closed
= mDNStrue
; }
3056 else if (err
&& err
!= errSSLWouldBlock
)
3057 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err
); nread
= -1; *closed
= mDNStrue
; }
3061 #endif /* NO_SECURITYFRAMEWORK */
3065 static int CLOSEDcount
= 0;
3066 static int EAGAINcount
= 0;
3067 nread
= recv(sock
->fd
, buf
, buflen
, 0);
3073 } // On success, clear our error counters
3074 else if (nread
== 0)
3077 if ((++CLOSEDcount
% 1000) == 0)
3079 LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock
->fd
, CLOSEDcount
);
3080 assert(CLOSEDcount
< 1000);
3081 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
3082 // crash mDNSResponder using assert() and restart fresh. See advantages below:
3083 // 1.Better User Experience
3084 // 2.CrashLogs frequency can be monitored
3085 // 3.StackTrace can be used for more info
3088 // else nread is negative -- see what kind of error we got
3089 else if (errno
== ECONNRESET
) { nread
= 0; *closed
= mDNStrue
; }
3090 else if (errno
!= EAGAIN
) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno
, strerror(errno
)); nread
= -1; }
3091 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
3094 if ((++EAGAINcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock
->fd
, EAGAINcount
); sleep(1); }
3101 mDNSexport
long mDNSPlatformWriteTCP(TCPSocket
*sock
, const char *msg
, unsigned long len
)
3105 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
3107 #ifndef NO_SECURITYFRAMEWORK
3109 if (sock
->handshake
== handshake_required
) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
3110 if (sock
->handshake
== handshake_in_progress
) return 0;
3111 else if (sock
->handshake
!= handshake_completed
) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock
->handshake
);
3113 mStatus err
= SSLWrite(sock
->tlsContext
, msg
, len
, &processed
);
3115 if (!err
) nsent
= (int) processed
;
3116 else if (err
== errSSLWouldBlock
) nsent
= 0;
3117 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err
); nsent
= -1; }
3120 #endif /* NO_SECURITYFRAMEWORK */
3124 nsent
= send(sock
->fd
, msg
, len
, 0);
3127 if (errno
== EAGAIN
) nsent
= 0;
3128 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno
)); nsent
= -1; }
3135 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
3140 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
3141 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
3142 mDNSlocal mStatus
SetupSocket(KQSocketSet
*cp
, const mDNSIPPort port
, u_short sa_family
, mDNSIPPort
*const outport
)
3144 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
3145 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
3147 const int twofivefive
= 255;
3148 mStatus err
= mStatus_NoError
;
3149 char *errstr
= mDNSNULL
;
3152 cp
->closeFlag
= mDNSNULL
;
3154 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
3155 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
));return(skt
); }
3157 // set default traffic class
3158 setTrafficClass(skt
, mDNSfalse
);
3160 #ifdef SO_RECV_ANYIF
3161 // Enable inbound packets on IFEF_AWDL interface.
3162 // Only done for multicast sockets, since we don't expect unicast socket operations
3163 // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
3164 if (mDNSSameIPPort(port
, MulticastDNSPort
))
3166 err
= setsockopt(skt
, SOL_SOCKET
, SO_RECV_ANYIF
, &on
, sizeof(on
));
3167 if (err
< 0) { errstr
= "setsockopt - SO_RECV_ANYIF"; goto fail
; }
3169 #endif // SO_RECV_ANYIF
3171 // ... with a shared UDP port, if it's for multicast receiving
3172 if (mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSSameIPPort(port
, NATPMPAnnouncementPort
))
3174 err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
3175 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
3178 // Don't want to wake from sleep for inbound packets on the mDNS sockets
3179 if (mDNSSameIPPort(port
, MulticastDNSPort
))
3182 if (setsockopt(skt
, SOL_SOCKET
, SO_NOWAKEFROMSLEEP
, &nowake
, sizeof(nowake
)) == -1)
3183 LogInfo("SetupSocket: SO_NOWAKEFROMSLEEP failed %s", strerror(errno
));
3186 if (sa_family
== AF_INET
)
3188 // We want to receive destination addresses
3189 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
3190 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
3192 // We want to receive interface identifiers
3193 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
3194 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
3196 // We want to receive packet TTL value so we can check it
3197 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
3198 if (err
< 0) { errstr
= "setsockopt - IP_RECVTTL"; goto fail
; }
3200 // Send unicast packets with TTL 255
3201 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
3202 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
3204 // And multicast packets with TTL 255 too
3205 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
3206 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
3208 // And start listening for packets
3209 struct sockaddr_in listening_sockaddr
;
3210 listening_sockaddr
.sin_family
= AF_INET
;
3211 listening_sockaddr
.sin_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
3212 listening_sockaddr
.sin_addr
.s_addr
= mDNSSameIPPort(port
, NATPMPAnnouncementPort
) ? AllHosts_v4
.NotAnInteger
: 0;
3213 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
3214 if (err
) { errstr
= "bind"; goto fail
; }
3215 if (outport
) outport
->NotAnInteger
= listening_sockaddr
.sin_port
;
3217 else if (sa_family
== AF_INET6
)
3219 // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
3220 if (mDNSSameIPPort(port
, NATPMPAnnouncementPort
)) { if (outport
) *outport
= zeroIPPort
; close(skt
); return mStatus_NoError
; }
3222 // We want to receive destination addresses and receive interface identifiers
3223 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
3224 if (err
< 0) { errstr
= "setsockopt - IPV6_RECVPKTINFO"; goto fail
; }
3226 // We want to receive packet hop count value so we can check it
3227 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &on
, sizeof(on
));
3228 if (err
< 0) { errstr
= "setsockopt - IPV6_RECVHOPLIMIT"; goto fail
; }
3230 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
3231 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
3232 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
3233 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
3235 // Send unicast packets with TTL 255
3236 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
3237 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
3239 // And multicast packets with TTL 255 too
3240 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
3241 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
3243 // Want to receive our own packets
3244 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
3245 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
3247 // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
3248 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_USE_MIN_MTU
, &mtu
, sizeof(mtu
));
3249 if (err
< 0) // Since it is an optimization if we fail just log the err, no need to close the skt
3250 LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
3251 skt
, err
, errno
, strerror(errno
));
3253 // And start listening for packets
3254 struct sockaddr_in6 listening_sockaddr6
;
3255 mDNSPlatformMemZero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
3256 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
3257 listening_sockaddr6
.sin6_family
= AF_INET6
;
3258 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
3259 listening_sockaddr6
.sin6_flowinfo
= 0;
3260 listening_sockaddr6
.sin6_addr
= in6addr_any
; // Want to receive multicasts AND unicasts on this socket
3261 listening_sockaddr6
.sin6_scope_id
= 0;
3262 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
3263 if (err
) { errstr
= "bind"; goto fail
; }
3264 if (outport
) outport
->NotAnInteger
= listening_sockaddr6
.sin6_port
;
3267 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
3268 fcntl(skt
, F_SETFD
, 1); // set close-on-exec
3270 k
->KQcallback
= myKQSocketCallBack
;
3272 k
->KQtask
= "UDP packet reception";
3273 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3274 k
->readSource
= mDNSNULL
;
3275 k
->writeSource
= mDNSNULL
;
3276 k
->fdClosed
= mDNSfalse
;
3278 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
3280 return(mStatus_NoError
);
3283 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
3284 if (strcmp(errstr
, "bind") || mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSIPPortIsZero(port
))
3285 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr
, skt
, mDNSVal16(port
), err
, errno
, strerror(errno
));
3287 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
3288 if (!strcmp(errstr
, "bind") && errno
== EADDRINUSE
)
3291 if (mDNSSameIPPort(port
, MulticastDNSPort
))
3292 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
3293 "Congratulations, you've reproduced an elusive bug.\r"
3294 "Please contact the current assignee of <rdar://problem/3814904>.\r"
3295 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
3296 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
3299 mDNSPlatformCloseFD(k
, skt
);
3303 mDNSexport UDPSocket
*mDNSPlatformUDPSocket(mDNS
*const m
, const mDNSIPPort requestedport
)
3306 mDNSIPPort port
= requestedport
;
3307 mDNSBool randomizePort
= mDNSIPPortIsZero(requestedport
);
3308 int i
= 10000; // Try at most 10000 times to get a unique random port
3309 UDPSocket
*p
= mallocL("UDPSocket", sizeof(UDPSocket
));
3310 if (!p
) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL
); }
3311 mDNSPlatformMemZero(p
, sizeof(UDPSocket
));
3312 p
->ss
.port
= zeroIPPort
;
3316 p
->ss
.proxy
= mDNSfalse
;
3320 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
3321 if (randomizePort
) port
= mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
3322 err
= SetupSocket(&p
->ss
, port
, AF_INET
, &p
->ss
.port
);
3325 err
= SetupSocket(&p
->ss
, port
, AF_INET6
, &p
->ss
.port
);
3326 if (err
) { mDNSPlatformCloseFD(&p
->ss
.kqsv4
, p
->ss
.sktv4
); p
->ss
.sktv4
= -1; }
3329 } while (err
== EADDRINUSE
&& randomizePort
&& i
);
3333 // In customer builds we don't want to log failures with port 5351, because this is a known issue
3334 // of failing to bind to this port when Internet Sharing has already bound to it
3335 // We also don't want to log about port 5350, due to a known bug when some other
3336 // process is bound to it.
3337 if (mDNSSameIPPort(requestedport
, NATPMPPort
) || mDNSSameIPPort(requestedport
, NATPMPAnnouncementPort
))
3338 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
3339 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
3340 freeL("UDPSocket", p
);
3346 mDNSexport
void mDNSPlatformUDPClose(UDPSocket
*sock
)
3348 CloseSocketSet(&sock
->ss
);
3349 freeL("UDPSocket", sock
);
3352 #if COMPILER_LIKES_PRAGMA_MARK
3354 #pragma mark - BPF Raw packet sending/receiving
3357 #if APPLE_OSX_mDNSResponder
3359 mDNSexport
void mDNSPlatformSendRawPacket(const void *const msg
, const mDNSu8
*const end
, mDNSInterfaceID InterfaceID
)
3361 if (!InterfaceID
) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
3362 NetworkInterfaceInfoOSX
*info
;
3364 info
= IfindexToInterfaceInfoOSX(&mDNSStorage
, InterfaceID
);
3367 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID
);
3370 if (info
->BPF_fd
< 0)
3371 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info
->ifinfo
.ifname
, info
->BPF_fd
);
3374 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
3375 if (write(info
->BPF_fd
, msg
, end
- (mDNSu8
*)msg
) < 0)
3376 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info
->BPF_fd
, errno
, strerror(errno
));
3380 mDNSexport
void mDNSPlatformSetLocalAddressCacheEntry(mDNS
*const m
, const mDNSAddr
*const tpa
, const mDNSEthAddr
*const tha
, mDNSInterfaceID InterfaceID
)
3382 if (!InterfaceID
) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
3383 NetworkInterfaceInfoOSX
*info
;
3384 info
= IfindexToInterfaceInfoOSX(m
, InterfaceID
);
3385 if (info
== NULL
) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID
); return; }
3386 // Manually inject an entry into our local ARP cache.
3387 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
3388 if (!mDNS_AddressIsLocalSubnet(m
, InterfaceID
, tpa
))
3389 LogSPS("Don't need address cache entry for %s %#a %.6a", info
->ifinfo
.ifname
, tpa
, tha
);
3392 int result
= mDNSSetLocalAddressCacheEntry(info
->scope_id
, tpa
->type
, tpa
->ip
.v6
.b
, tha
->b
);
3393 if (result
) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info
->ifinfo
.ifname
, tpa
, tha
, result
);
3394 else LogSPS("Set local address cache entry for %s %#a %.6a", info
->ifinfo
.ifname
, tpa
, tha
);
3398 mDNSlocal
void CloseBPF(NetworkInterfaceInfoOSX
*const i
)
3400 LogSPS("%s closing BPF fd %d", i
->ifinfo
.ifname
, i
->BPF_fd
);
3401 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3402 // close will happen in the cancel handler
3403 dispatch_source_cancel(i
->BPF_source
);
3406 // Note: MUST NOT close() the underlying native BSD sockets.
3407 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
3408 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
3409 CFRunLoopRemoveSource(CFRunLoopGetMain(), i
->BPF_rls
, kCFRunLoopDefaultMode
);
3410 CFRelease(i
->BPF_rls
);
3411 CFSocketInvalidate(i
->BPF_cfs
);
3412 CFRelease(i
->BPF_cfs
);
3415 if (i
->BPF_mcfd
>= 0) { close(i
->BPF_mcfd
); i
->BPF_mcfd
= -1; }
3418 mDNSlocal
void bpf_callback_common(NetworkInterfaceInfoOSX
*info
)
3420 KQueueLock(info
->m
);
3422 // 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
3423 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
3424 if (info
->BPF_fd
< 0) goto exit
;
3426 ssize_t n
= read(info
->BPF_fd
, &info
->m
->imsg
, info
->BPF_len
);
3427 const mDNSu8
*ptr
= (const mDNSu8
*)&info
->m
->imsg
;
3428 const mDNSu8
*end
= (const mDNSu8
*)&info
->m
->imsg
+ n
;
3429 debugf("%3d: bpf_callback got %d bytes on %s", info
->BPF_fd
, n
, info
->ifinfo
.ifname
);
3433 /* <rdar://problem/10287386>
3434 * sometimes there can be a race condition btw when the bpf socket
3435 * gets data and the callback get scheduled and when we call BIOCSETF (which
3436 * clears the socket). this can cause the read to hang for a really long time
3437 * and effectively prevent us from responding to requests for long periods of time.
3438 * to prevent this make the socket non blocking and just bail if we dont get anything
3440 if (errno
== EAGAIN
)
3442 LogMsg("bpf_callback got EAGAIN bailing");
3445 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info
->ifinfo
.ifname
, info
->BPF_fd
, errno
, strerror(errno
));
3452 const struct bpf_hdr
*const bh
= (const struct bpf_hdr
*)ptr
;
3453 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
3454 info
->BPF_fd
, ptr
, bh
->bh_hdrlen
, ptr
+ bh
->bh_hdrlen
, bh
->bh_caplen
, bh
->bh_datalen
,
3455 ptr
+ BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
), end
- (ptr
+ BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
)));
3456 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
3457 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
3458 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
3459 mDNSCoreReceiveRawPacket(info
->m
, ptr
+ bh
->bh_hdrlen
, ptr
+ bh
->bh_hdrlen
+ bh
->bh_caplen
, info
->ifinfo
.InterfaceID
);
3460 ptr
+= BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
);
3463 KQueueUnlock(info
->m
, "bpf_callback");
3465 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3466 mDNSlocal
void bpf_callback_dispatch(NetworkInterfaceInfoOSX
*const info
)
3468 bpf_callback_common(info
);
3471 mDNSlocal
void bpf_callback(const CFSocketRef cfs
, const CFSocketCallBackType CallBackType
, const CFDataRef address
, const void *const data
, void *const context
)
3477 bpf_callback_common((NetworkInterfaceInfoOSX
*)context
);
3481 mDNSexport
void mDNSPlatformSendKeepalive(mDNSAddr
*sadd
, mDNSAddr
*dadd
, mDNSIPPort
*lport
, mDNSIPPort
*rport
, mDNSu32 seq
, mDNSu32 ack
, mDNSu16 win
)
3483 LogMsg("mDNSPlatformSendKeepalive called\n");
3484 mDNSSendKeepalive(sadd
->ip
.v6
.b
, dadd
->ip
.v6
.b
, lport
->NotAnInteger
, rport
->NotAnInteger
, seq
, ack
, win
);
3487 mDNSexport mStatus
mDNSPlatformClearSPSData(void)
3489 CFStringRef spsAddress
= NULL
;
3490 CFStringRef ownerOPTRec
= NULL
;
3492 if ((spsAddress
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyAddress")))
3494 if (SCDynamicStoreRemoveValue(NULL
, spsAddress
) == false)
3495 LogSPS("mDNSPlatformClearSPSData: Unable to remove sleep proxy address key");
3498 if((ownerOPTRec
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyOPTRecord")))
3500 if (SCDynamicStoreRemoveValue(NULL
, ownerOPTRec
) == false)
3501 LogSPS("mDNSPlatformClearSPSData: Unable to remove sleep proxy owner option record key");
3504 if (spsAddress
) CFRelease(spsAddress
);
3505 if (ownerOPTRec
) CFRelease(ownerOPTRec
);
3506 return KERN_SUCCESS
;
3509 mDNSlocal
int getMACAddress(int family
, v6addr_t raddr
, v6addr_t gaddr
, int *gfamily
, ethaddr_t eth
)
3513 struct rt_msghdr m_rtm
;
3517 struct rt_msghdr
*rtm
= &(m_rtmsg
.m_rtm
);
3518 char *cp
= m_rtmsg
.m_space
;
3519 int seq
= 6367, sock
, rlen
, i
;
3520 struct sockaddr_in
*sin
= NULL
;
3521 struct sockaddr_in6
*sin6
= NULL
;
3522 struct sockaddr_dl
*sdl
= NULL
;
3523 struct sockaddr_storage sins
;
3524 struct sockaddr_dl sdl_m
;
3526 #define NEXTADDR(w, s, len) \
3527 if (rtm->rtm_addrs & (w)) \
3529 bcopy((char *)s, cp, len); \
3533 bzero(&sins
, sizeof(struct sockaddr_storage
));
3534 bzero(&sdl_m
, sizeof(struct sockaddr_dl
));
3535 bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
3537 sock
= socket(PF_ROUTE
, SOCK_RAW
, 0);
3540 LogMsg("getMACAddress: Can not open the socket - %s", strerror(errno
));
3544 rtm
->rtm_addrs
|= RTA_DST
| RTA_GATEWAY
;
3545 rtm
->rtm_type
= RTM_GET
;
3547 rtm
->rtm_version
= RTM_VERSION
;
3548 rtm
->rtm_seq
= ++seq
;
3550 sdl_m
.sdl_len
= sizeof(sdl_m
);
3551 sdl_m
.sdl_family
= AF_LINK
;
3552 if (family
== AF_INET
)
3554 sin
= (struct sockaddr_in
*)&sins
;
3555 sin
->sin_family
= AF_INET
;
3556 sin
->sin_len
= sizeof(struct sockaddr_in
);
3557 memcpy(&sin
->sin_addr
, raddr
, sizeof(struct in_addr
));
3558 NEXTADDR(RTA_DST
, sin
, sin
->sin_len
);
3560 else if (family
== AF_INET6
)
3562 sin6
= (struct sockaddr_in6
*)&sins
;
3563 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
3564 sin6
->sin6_family
= AF_INET6
;
3565 memcpy(&sin6
->sin6_addr
, raddr
, sizeof(struct in6_addr
));
3566 NEXTADDR(RTA_DST
, sin6
, sin6
->sin6_len
);
3568 NEXTADDR(RTA_GATEWAY
, &sdl_m
, sdl_m
.sdl_len
);
3569 rtm
->rtm_msglen
= rlen
= cp
- (char *)&m_rtmsg
;
3571 if (write(sock
, (char *)&m_rtmsg
, rlen
) < 0)
3573 LogMsg("getMACAddress: writing to routing socket: %s", strerror(errno
));
3580 rlen
= read(sock
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
3582 while (rlen
> 0 && (rtm
->rtm_seq
!= seq
|| rtm
->rtm_pid
!= getpid()));
3585 LogMsg("getMACAddress: Read from routing socket failed");
3587 if (family
== AF_INET
)
3589 sin
= (struct sockaddr_in
*) (rtm
+ 1);
3590 sdl
= (struct sockaddr_dl
*) (sin
->sin_len
+ (char *) sin
);
3592 else if (family
== AF_INET6
)
3594 sin6
= (struct sockaddr_in6
*) (rtm
+1);
3595 sdl
= (struct sockaddr_dl
*) (sin6
->sin6_len
+ (char *) sin6
);
3600 LogMsg("getMACAddress: sdl is NULL for family %d", family
);
3605 // If the address is not on the local net, we get the IP address of the gateway.
3606 // We would have to repeat the process to get the MAC address of the gateway
3607 *gfamily
= sdl
->sdl_family
;
3608 if (sdl
->sdl_family
== AF_INET
)
3612 struct sockaddr_in
*new_sin
= (struct sockaddr_in
*)(sin
->sin_len
+(char*) sin
);
3613 memcpy(gaddr
, &new_sin
->sin_addr
, sizeof(struct in_addr
));
3617 LogMsg("getMACAddress: sin is NULL");
3622 else if (sdl
->sdl_family
== AF_INET6
)
3626 struct sockaddr_in6
*new_sin6
= (struct sockaddr_in6
*)(sin6
->sin6_len
+(char*) sin6
);
3627 memcpy(gaddr
, &new_sin6
->sin6_addr
, sizeof(struct in6_addr
));
3631 LogMsg("getMACAddress: sin6 is NULL");
3637 unsigned char *ptr
= (unsigned char *)LLADDR(sdl
);
3638 for (i
= 0; i
< ETHER_ADDR_LEN
; i
++)
3639 (eth
)[i
] = *(ptr
+i
);
3643 return KERN_SUCCESS
;
3646 mDNSlocal
int GetRemoteMacinternal(int family
, v6addr_t raddr
, ethaddr_t eth
)
3655 ret
= getMACAddress(family
, raddr
, gateway
, &gfamily
, eth
);
3658 memcpy(raddr
, gateway
, sizeof(family
));
3663 while ((ret
== -1) && (count
< 5));
3667 mDNSlocal
int StoreSPSMACAddressinternal(int family
, v6addr_t spsaddr
, const char *ifname
)
3670 char spsip
[INET6_ADDRSTRLEN
];
3672 CFStringRef sckey
= NULL
;
3673 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL
, NULL
);
3674 SCDynamicStoreRef ipstore
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL
, NULL
);
3675 CFMutableDictionaryRef dict
= NULL
;
3676 CFStringRef entityname
= NULL
;
3677 CFDictionaryRef ipdict
= NULL
;
3678 CFArrayRef addrs
= NULL
;
3680 if ((store
== NULL
) || (ipstore
== NULL
))
3682 LogMsg("StoreSPSMACAddressinternal: Unable to accesss SC Dynamic Store");
3687 // Get the MAC address of the Sleep Proxy Server
3688 memset(eth
, 0, sizeof(eth
));
3689 ret
= GetRemoteMacinternal(family
, spsaddr
, eth
);
3692 LogMsg("StoreSPSMACAddressinternal: Failed to determine the MAC address");
3696 // Create/Update the dynamic store entry for the specified interface
3697 sckey
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname
, "/BonjourSleepProxyAddress");
3698 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3701 LogMsg("StoreSPSMACAddressinternal: SPSCreateDict() Could not create CFDictionary dict");
3706 CFStringRef macaddr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
3707 CFDictionarySetValue(dict
, CFSTR("MACAddress"), macaddr
);
3708 if (NULL
!= macaddr
)
3711 if( NULL
== inet_ntop(family
, (void *)spsaddr
, spsip
, sizeof(spsip
)))
3713 LogMsg("StoreSPSMACAddressinternal: inet_ntop failed: %s", strerror(errno
));
3718 CFStringRef ipaddr
= CFStringCreateWithCString(NULL
, spsip
, kCFStringEncodingUTF8
);
3719 CFDictionarySetValue(dict
, CFSTR("IPAddress"), ipaddr
);
3723 // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup
3724 if ((entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/IPv6"), ifname
)) != NULL
)
3726 if ((ipdict
= SCDynamicStoreCopyValue(ipstore
, entityname
)) != NULL
)
3728 if((addrs
= CFDictionaryGetValue(ipdict
, CFSTR("Addresses"))) != NULL
)
3730 addrs
= CFRetain(addrs
);
3731 CFDictionarySetValue(dict
, CFSTR("RegisteredAddresses"), addrs
);
3735 SCDynamicStoreSetValue(store
, sckey
, dict
);
3738 if (store
) CFRelease(store
);
3739 if (ipstore
) CFRelease(ipstore
);
3740 if (sckey
) CFRelease(sckey
);
3741 if (dict
) CFRelease(dict
);
3742 if (ipdict
) CFRelease(ipdict
);
3743 if (entityname
) CFRelease(entityname
);
3744 if (addrs
) CFRelease(addrs
);
3749 mDNSlocal
void mDNSStoreSPSMACAddress(int family
, v6addr_t spsaddr
, char *ifname
)
3757 mDNSPlatformMemCopy(addr
.saddr
, spsaddr
, sizeof(v6addr_t
));
3759 err
= StoreSPSMACAddressinternal(family
, (uint8_t *)addr
.saddr
, ifname
);
3761 LogMsg("mDNSStoreSPSMACAddress : failed");
3764 mDNSexport mStatus
mDNSPlatformStoreSPSMACAddr(mDNSAddr
*spsaddr
, char *ifname
)
3766 int family
= (spsaddr
->type
== mDNSAddrType_IPv4
) ? AF_INET
: AF_INET6
;
3768 LogInfo("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr
, ifname
);
3769 mDNSStoreSPSMACAddress(family
, spsaddr
->ip
.v6
.b
, ifname
);
3771 return KERN_SUCCESS
;
3775 mDNSexport mStatus
mDNSPlatformStoreOwnerOptRecord(char *ifname
, DNSMessage
* msg
, int length
)
3778 CFStringRef sckey
= NULL
;
3779 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:StoreOwnerOPTRecord"), NULL
, NULL
);
3780 CFMutableDictionaryRef dict
= NULL
;
3784 LogMsg("mDNSPlatformStoreOwnerOptRecord: Unable to accesss SC Dynamic Store");
3789 // Create/Update the dynamic store entry for the specified interface
3790 sckey
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname
, "/BonjourSleepProxyOPTRecord");
3791 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3794 LogMsg("mDNSPlatformStoreOwnerOptRecord: Could not create CFDictionary dictionary to store OPT Record");
3799 CFDataRef optRec
= NULL
;
3800 optRec
= CFDataCreate(NULL
, (const uint8_t *)msg
, (CFIndex
)length
);
3801 CFDictionarySetValue(dict
, CFSTR("OwnerOPTRecord"), optRec
);
3802 if (NULL
!= optRec
) CFRelease(optRec
);
3804 SCDynamicStoreSetValue(store
, sckey
, dict
);
3807 if (NULL
!= store
) CFRelease(store
);
3808 if (NULL
!= sckey
) CFRelease(sckey
);
3809 if (NULL
!= dict
) CFRelease(dict
);
3813 mDNSlocal
void mDNSGet_RemoteMAC(mDNS
*const m
, int family
, v6addr_t raddr
)
3816 IPAddressMACMapping
*addrMapping
;
3817 int kr
= KERN_FAILURE
;
3823 mDNSPlatformMemCopy(dst
.addr
, raddr
, sizeof(v6addr_t
));
3825 kr
= GetRemoteMacinternal(family
, (uint8_t *)dst
.addr
, eth
);
3827 // If the call to get the remote MAC address succeeds, allocate and copy
3828 // the values and schedule a task to update the MAC address in the TCP Keepalive record.
3831 addrMapping
= mDNSPlatformMemAllocate(sizeof(IPAddressMACMapping
));
3832 snprintf(addrMapping
->ethaddr
, sizeof(addrMapping
->ethaddr
), "%02x:%02x:%02x:%02x:%02x:%02x",
3833 eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
3834 if (family
== AF_INET
)
3836 addrMapping
->ipaddr
.type
= mDNSAddrType_IPv4
;
3837 mDNSPlatformMemCopy(addrMapping
->ipaddr
.ip
.v4
.b
, raddr
, sizeof(v6addr_t
));
3841 addrMapping
->ipaddr
.type
= mDNSAddrType_IPv6
;
3842 mDNSPlatformMemCopy(addrMapping
->ipaddr
.ip
.v6
.b
, raddr
, sizeof(v6addr_t
));
3844 UpdateRMAC(m
, addrMapping
);
3848 mDNSexport mStatus
mDNSPlatformGetRemoteMacAddr(mDNS
*const m
, mDNSAddr
*raddr
)
3850 int family
= (raddr
->type
== mDNSAddrType_IPv4
) ? AF_INET
: AF_INET6
;
3852 LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC");
3853 mDNSGet_RemoteMAC(m
, family
, raddr
->ip
.v6
.b
);
3855 return KERN_SUCCESS
;
3858 mDNSexport mStatus
mDNSPlatformRetrieveTCPInfo(mDNS
*const m
, mDNSAddr
*laddr
, mDNSIPPort
*lport
, mDNSAddr
*raddr
, mDNSIPPort
*rport
, mDNSTCPInfo
*mti
)
3862 int family
= (laddr
->type
== mDNSAddrType_IPv4
) ? AF_INET
: AF_INET6
;
3864 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
);
3865 if (error
!= KERN_SUCCESS
)
3867 LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__
, error
);
3870 mti
->IntfId
= mDNSPlatformInterfaceIDfromInterfaceIndex(m
, intfid
);
3874 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
3876 mDNSlocal
int CountProxyTargets(mDNS
*const m
, NetworkInterfaceInfoOSX
*x
, int *p4
, int *p6
)
3878 int numv4
= 0, numv6
= 0;
3881 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3882 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
3884 if (p4
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv4
, &rr
->AddressProxy
.ip
.v4
);
3888 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3889 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
3891 if (p6
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv6
, &rr
->AddressProxy
.ip
.v6
);
3895 if (p4
) *p4
= numv4
;
3896 if (p6
) *p6
= numv6
;
3897 return(numv4
+ numv6
);
3900 mDNSexport
void mDNSPlatformUpdateProxyList(mDNS
*const m
, const mDNSInterfaceID InterfaceID
)
3902 NetworkInterfaceInfoOSX
*x
;
3904 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
3905 for (x
= m
->p
->InterfaceList
; x
; x
= x
->next
) if ((x
->ifinfo
.InterfaceID
== InterfaceID
) && (x
->BPF_fd
>= 0)) break;
3907 if (!x
) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID
); return; }
3909 #define MAX_BPF_ADDRS 250
3910 int numv4
= 0, numv6
= 0;
3912 if (CountProxyTargets(m
, x
, &numv4
, &numv6
) > MAX_BPF_ADDRS
)
3914 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4
, numv6
);
3915 if (numv4
> MAX_BPF_ADDRS
) numv4
= MAX_BPF_ADDRS
;
3916 numv6
= MAX_BPF_ADDRS
- numv4
;
3919 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x
->BPF_fd
, x
->ifinfo
.ifname
, &x
->ifinfo
.MAC
, numv4
, numv6
);
3921 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
3922 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
3923 static struct bpf_insn filter
[17 + MAX_BPF_ADDRS
] =
3925 BPF_STMT(BPF_LD
+ BPF_H
+ BPF_ABS
, 12), // 0 Read Ethertype (bytes 12,13)
3927 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
3928 BPF_STMT(BPF_RET
+ BPF_K
, 42), // 2 Return 42-byte ARP
3930 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
3932 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
3933 BPF_STMT(BPF_LD
+ BPF_H
+ BPF_ABS
, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
3934 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
3935 BPF_STMT(BPF_RET
+ BPF_K
, 86), // 7 Return 86-byte ND
3937 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
3938 BPF_STMT(BPF_LD
+ BPF_W
+ BPF_ABS
, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
3941 struct bpf_insn
*pc
= &filter
[9];
3942 struct bpf_insn
*chk6
= pc
+ numv4
+ 1; // numv4 address checks, plus a "return 0"
3943 struct bpf_insn
*fail
= chk6
+ 1 + numv6
; // Get v6 Dst LSW, plus numv6 address checks
3944 struct bpf_insn
*ret4
= fail
+ 1;
3945 struct bpf_insn
*ret6
= ret4
+ 4;
3947 static const struct bpf_insn rf
= BPF_STMT(BPF_RET
+ BPF_K
, 0); // No match: Return nothing
3949 static const struct bpf_insn g6
= BPF_STMT(BPF_LD
+ BPF_W
+ BPF_ABS
, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
3951 static const struct bpf_insn r4a
= BPF_STMT(BPF_LDX
+ BPF_B
+ BPF_MSH
, 14); // Get IP Header length (normally 20)
3952 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)
3953 static const struct bpf_insn r4c
= BPF_STMT(BPF_ALU
+ BPF_ADD
+ BPF_X
, 0); // A += IP Header length
3954 static const struct bpf_insn r4d
= BPF_STMT(BPF_RET
+ BPF_A
, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
3956 static const struct bpf_insn r6a
= BPF_STMT(BPF_RET
+ BPF_K
, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
3958 BPF_SetOffset(&filter
[4], jf
, fail
); // If Ethertype not ARP, IPv4, or IPv6, fail
3959 BPF_SetOffset(&filter
[6], jf
, chk6
); // If IPv6 but not ICMPv6, go to IPv6 address list check
3961 // BPF Byte-Order Note
3962 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
3963 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
3964 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
3965 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
3966 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
3967 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
3968 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
3969 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
3970 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
3971 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
3973 // IPSEC capture size notes:
3974 // 8 bytes UDP header
3975 // 4 bytes Non-ESP Marker
3976 // 28 bytes IKE Header
3978 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
3981 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3982 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
3984 mDNSv4Addr a
= rr
->AddressProxy
.ip
.v4
;
3985 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
3986 BPF_SetOffset(pc
, jt
, ret4
);
3988 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];
3993 if (pc
!= chk6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc
, chk6
);
3994 *pc
++ = g6
; // chk6 points here
3996 // First cancel any previous ND group memberships we had, then create a fresh socket
3997 if (x
->BPF_mcfd
>= 0) close(x
->BPF_mcfd
);
3998 x
->BPF_mcfd
= socket(AF_INET6
, SOCK_DGRAM
, 0);
4000 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4001 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
4003 const mDNSv6Addr
*const a
= &rr
->AddressProxy
.ip
.v6
;
4004 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
4005 BPF_SetOffset(pc
, jt
, ret6
);
4007 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];
4010 struct ipv6_mreq i6mr
;
4011 i6mr
.ipv6mr_interface
= x
->scope_id
;
4012 i6mr
.ipv6mr_multiaddr
= *(const struct in6_addr
*)&NDP_prefix
;
4013 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xD] = a
->b
[0xD];
4014 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xE] = a
->b
[0xE];
4015 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xF] = a
->b
[0xF];
4017 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
4018 mStatus err
= setsockopt(x
->BPF_mcfd
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
4019 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
4020 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
4022 err
= setsockopt(x
->BPF_mcfd
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
4023 if (err
< 0 && (errno
!= EADDRINUSE
)) // Joining same group twice can give "Address already in use" error -- no need to report that
4024 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
4026 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr
.ipv6mr_multiaddr
, a
);
4029 if (pc
!= fail
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc
, fail
);
4030 *pc
++ = rf
; // fail points here
4032 if (pc
!= ret4
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc
, ret4
);
4033 *pc
++ = r4a
; // ret4 points here
4038 if (pc
!= ret6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc
, ret6
);
4039 *pc
++ = r6a
; // ret6 points here
4041 struct bpf_program prog
= { pc
- filter
, filter
};
4044 // For debugging BPF filter program
4046 for (q
=0; q
<prog
.bf_len
; q
++)
4047 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
);
4050 if (!numv4
&& !numv6
)
4052 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
4053 if (m
->timenow
== 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
4054 // Schedule check to see if we can close this BPF_fd now
4055 if (!m
->NetworkChanged
) m
->NetworkChanged
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2);
4056 // prog.bf_len = 0; This seems to panic the kernel
4057 if (x
->BPF_fd
< 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
4060 if (ioctl(x
->BPF_fd
, BIOCSETFNR
, &prog
) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog
.bf_len
, errno
, strerror(errno
));
4061 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog
.bf_len
);
4064 mDNSexport
void mDNSPlatformReceiveBPF_fd(mDNS
*const m
, int fd
)
4068 NetworkInterfaceInfoOSX
*i
;
4069 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
) if (i
->BPF_fd
== -2) break;
4070 if (!i
) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd
); close(fd
); }
4073 LogSPS("%s using BPF fd %d", i
->ifinfo
.ifname
, fd
);
4075 struct bpf_version v
;
4076 if (ioctl(fd
, BIOCVERSION
, &v
) < 0)
4077 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
4078 else if (BPF_MAJOR_VERSION
!= v
.bv_major
|| BPF_MINOR_VERSION
!= v
.bv_minor
)
4079 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
4080 fd
, i
->ifinfo
.ifname
, BPF_MAJOR_VERSION
, BPF_MINOR_VERSION
, v
.bv_major
, v
.bv_minor
);
4082 if (ioctl(fd
, BIOCGBLEN
, &i
->BPF_len
) < 0)
4083 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
4085 if (i
->BPF_len
> sizeof(m
->imsg
))
4087 i
->BPF_len
= sizeof(m
->imsg
);
4088 if (ioctl(fd
, BIOCSBLEN
, &i
->BPF_len
) < 0)
4089 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
4091 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd
, i
->ifinfo
.ifname
, i
->BPF_len
);
4094 static const u_int opt_one
= 1;
4095 if (ioctl(fd
, BIOCIMMEDIATE
, &opt_one
) < 0)
4096 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
4098 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
4099 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
4101 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
4102 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
4104 /* <rdar://problem/10287386>
4105 * make socket non blocking see comments in bpf_callback_common for more info
4107 if (fcntl(fd
, F_SETFL
, fcntl(fd
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
4109 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
4113 mDNSPlatformMemZero(&ifr
, sizeof(ifr
));
4114 strlcpy(ifr
.ifr_name
, i
->ifinfo
.ifname
, sizeof(ifr
.ifr_name
));
4115 if (ioctl(fd
, BIOCSETIF
, &ifr
) < 0)
4116 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
)); i
->BPF_fd
= -3; }
4119 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
4121 i
->BPF_source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, fd
, 0, dispatch_get_main_queue());
4122 if (!i
->BPF_source
) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
4123 dispatch_source_set_event_handler(i
->BPF_source
, ^{bpf_callback_dispatch(i
);});
4124 dispatch_source_set_cancel_handler(i
->BPF_source
, ^{close(fd
);});
4125 dispatch_resume(i
->BPF_source
);
4127 CFSocketContext myCFSocketContext
= { 0, i
, NULL
, NULL
, NULL
};
4129 i
->BPF_cfs
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
, bpf_callback
, &myCFSocketContext
);
4130 i
->BPF_rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, i
->BPF_cfs
, 0);
4131 CFRunLoopAddSource(CFRunLoopGetMain(), i
->BPF_rls
, kCFRunLoopDefaultMode
);
4133 mDNSPlatformUpdateProxyList(m
, i
->ifinfo
.InterfaceID
);
4140 #endif // APPLE_OSX_mDNSResponder
4142 #if COMPILER_LIKES_PRAGMA_MARK
4144 #pragma mark - Key Management
4147 #ifndef NO_SECURITYFRAMEWORK
4148 mDNSlocal CFArrayRef
CopyCertChain(SecIdentityRef identity
)
4150 CFMutableArrayRef certChain
= NULL
;
4151 if (!identity
) { LogMsg("CopyCertChain: identity is NULL"); return(NULL
); }
4152 SecCertificateRef cert
;
4153 OSStatus err
= SecIdentityCopyCertificate(identity
, &cert
);
4154 if (err
|| !cert
) LogMsg("CopyCertChain: SecIdentityCopyCertificate() returned %d", (int) err
);
4157 #pragma clang diagnostic push
4158 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
4159 SecPolicySearchRef searchRef
;
4160 err
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, &CSSMOID_APPLE_X509_BASIC
, NULL
, &searchRef
);
4161 if (err
|| !searchRef
) LogMsg("CopyCertChain: SecPolicySearchCreate() returned %d", (int) err
);
4164 SecPolicyRef policy
;
4165 err
= SecPolicySearchCopyNext(searchRef
, &policy
);
4166 if (err
|| !policy
) LogMsg("CopyCertChain: SecPolicySearchCopyNext() returned %d", (int) err
);
4169 CFArrayRef wrappedCert
= CFArrayCreate(NULL
, (const void**) &cert
, 1, &kCFTypeArrayCallBacks
);
4170 if (!wrappedCert
) LogMsg("CopyCertChain: wrappedCert is NULL");
4174 err
= SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
);
4175 if (err
|| !trust
) LogMsg("CopyCertChain: SecTrustCreateWithCertificates() returned %d", (int) err
);
4178 err
= SecTrustEvaluate(trust
, NULL
);
4179 if (err
) LogMsg("CopyCertChain: SecTrustEvaluate() returned %d", (int) err
);
4182 CFArrayRef rawCertChain
;
4183 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
4184 err
= SecTrustGetResult(trust
, NULL
, &rawCertChain
, &statusChain
);
4185 if (err
|| !rawCertChain
|| !statusChain
) LogMsg("CopyCertChain: SecTrustGetResult() returned %d", (int) err
);
4188 certChain
= CFArrayCreateMutableCopy(NULL
, 0, rawCertChain
);
4189 if (!certChain
) LogMsg("CopyCertChain: certChain is NULL");
4192 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
4193 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
4194 CFArraySetValueAtIndex(certChain
, 0, identity
);
4195 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
4196 if (CFArrayGetCount(certChain
) > 1) CFArrayRemoveValueAtIndex(certChain
, CFArrayGetCount(certChain
) - 1);
4198 CFRelease(rawCertChain
);
4199 // Do not free statusChain:
4200 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
4201 // certChain: Call the CFRelease function to release this object when you are finished with it.
4202 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
4207 CFRelease(wrappedCert
);
4211 CFRelease(searchRef
);
4213 #pragma clang diagnostic pop
4218 #endif /* NO_SECURITYFRAMEWORK */
4220 mDNSexport mStatus
mDNSPlatformTLSSetupCerts(void)
4222 #ifdef NO_SECURITYFRAMEWORK
4223 return mStatus_UnsupportedErr
;
4225 SecIdentityRef identity
= nil
;
4226 SecIdentitySearchRef srchRef
= nil
;
4229 #pragma clang diagnostic push
4230 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
4231 // search for "any" identity matching specified key use
4232 // In this app, we expect there to be exactly one
4233 err
= SecIdentitySearchCreate(NULL
, CSSM_KEYUSE_DECRYPT
, &srchRef
);
4234 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err
); return err
; }
4236 err
= SecIdentitySearchCopyNext(srchRef
, &identity
);
4237 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err
); return err
; }
4238 #pragma clang diagnostic pop
4240 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
4241 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr
; }
4243 // Found one. Call CopyCertChain to create the correct certificate chain.
4244 ServerCerts
= CopyCertChain(identity
);
4245 if (ServerCerts
== nil
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: CopyCertChain error"); return mStatus_UnknownErr
; }
4247 return mStatus_NoError
;
4248 #endif /* NO_SECURITYFRAMEWORK */
4251 mDNSexport
void mDNSPlatformTLSTearDownCerts(void)
4253 #ifndef NO_SECURITYFRAMEWORK
4254 if (ServerCerts
) { CFRelease(ServerCerts
); ServerCerts
= NULL
; }
4255 #endif /* NO_SECURITYFRAMEWORK */
4258 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
4259 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
4261 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
4262 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
4265 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
4270 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
4271 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
4273 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
4276 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
4281 mDNSexport mDNSBool
DictionaryIsEnabled(CFDictionaryRef dict
)
4284 CFNumberRef state
= (CFNumberRef
)CFDictionaryGetValue(dict
, CFSTR("Enabled"));
4285 if (!state
) return mDNSfalse
;
4286 if (!CFNumberGetValue(state
, kCFNumberSInt32Type
, &val
))
4287 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse
; }
4288 return val
? mDNStrue
: mDNSfalse
;
4291 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
4293 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
4295 if (sa
->sa_family
== AF_INET
)
4297 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
4298 ip
->type
= mDNSAddrType_IPv4
;
4299 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
4300 return(mStatus_NoError
);
4303 if (sa
->sa_family
== AF_INET6
)
4305 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
4306 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
4307 // value into the second word of the IPv6 link-local address, so they can just
4308 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
4309 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
4310 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
4311 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
4312 ip
->type
= mDNSAddrType_IPv6
;
4313 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
4314 return(mStatus_NoError
);
4317 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
4318 return(mStatus_Invalid
);
4321 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
4323 mDNSEthAddr eth
= zeroEthAddr
;
4325 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
4328 CFDictionaryRef dict
= SCDynamicStoreCopyValue(NULL
, entityname
);
4331 CFRange range
= { 0, 6 }; // Offset, length
4332 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
4333 if (data
&& CFDataGetLength(data
) == 6)
4334 CFDataGetBytes(data
, range
, eth
.b
);
4337 CFRelease(entityname
);
4343 mDNSlocal
int GetMAC(mDNSEthAddr
*eth
, u_short ifindex
)
4345 struct ifaddrs
*ifa
;
4346 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
4347 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
4349 const struct sockaddr_dl
*const sdl
= (const struct sockaddr_dl
*)ifa
->ifa_addr
;
4350 if (sdl
->sdl_index
== ifindex
)
4351 { mDNSPlatformMemCopy(eth
->b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6); return 0; }
4357 #ifndef SIOCGIFWAKEFLAGS
4358 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
4361 #ifndef IF_WAKE_ON_MAGIC_PACKET
4362 #define IF_WAKE_ON_MAGIC_PACKET 0x01
4365 #ifndef ifr_wake_flags
4366 #define ifr_wake_flags ifr_ifru.ifru_intval
4369 mDNSlocal mDNSBool
CheckInterfaceSupport(NetworkInterfaceInfo
*const intf
, const char *key
)
4371 io_service_t service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOBSDNameMatching(kIOMasterPortDefault
, 0, intf
->ifname
));
4374 LogSPS("CheckInterfaceSupport: No service for interface %s", intf
->ifname
);
4379 IOObjectGetClass(service
, n1
);
4381 mDNSBool ret
= mDNSfalse
;
4382 kern_return_t kr
= IORegistryEntryGetParentEntry(service
, kIOServicePlane
, &parent
);
4383 if (kr
== KERN_SUCCESS
)
4385 CFStringRef keystr
= CFStringCreateWithCString(NULL
, key
, kCFStringEncodingUTF8
);
4386 IOObjectGetClass(parent
, n2
);
4387 LogSPS("CheckInterfaceSupport: Interface %s service %s parent %s", intf
->ifname
, n1
, n2
);
4388 const CFTypeRef ref
= IORegistryEntryCreateCFProperty(parent
, keystr
, kCFAllocatorDefault
, mDNSNULL
);
4391 LogSPS("CheckInterfaceSupport: No mDNS_IOREG_KEY for interface %s/%s/%s", intf
->ifname
, n1
, n2
);
4399 IOObjectRelease(parent
);
4404 LogSPS("CheckInterfaceSupport: IORegistryEntryGetParentEntry for %s/%s failed %d", intf
->ifname
, n1
, kr
);
4407 IOObjectRelease(service
);
4412 mDNSlocal mDNSBool
InterfaceSupportsKeepAlive(NetworkInterfaceInfo
*const intf
)
4414 return CheckInterfaceSupport(intf
, mDNS_IOREG_KA_KEY
);
4417 mDNSlocal mDNSBool
NetWakeInterface(NetworkInterfaceInfoOSX
*i
)
4419 // We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D.
4420 if (!SPSInterface(i
)) return(mDNSfalse
);
4422 // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
4423 // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
4424 // when the power source is not AC Power.
4425 if (InterfaceSupportsKeepAlive(&i
->ifinfo
))
4427 LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i
->ifinfo
.ifname
);
4431 int s
= socket(AF_INET
, SOCK_DGRAM
, 0);
4432 if (s
< 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i
->ifinfo
.ifname
, s
, errno
, strerror(errno
)); return(mDNSfalse
); }
4435 strlcpy(ifr
.ifr_name
, i
->ifinfo
.ifname
, sizeof(ifr
.ifr_name
));
4436 if (ioctl(s
, SIOCGIFWAKEFLAGS
, &ifr
) < 0)
4438 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
4439 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
4440 // error code is being returned from the kernel, we need to use the kernel version.
4441 #define KERNEL_EOPNOTSUPP 102
4442 if (errno
!= KERNEL_EOPNOTSUPP
) // "Operation not supported on socket", the expected result on Leopard and earlier
4443 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i
->ifinfo
.ifname
, errno
, strerror(errno
));
4444 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
4445 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
4446 ifr
.ifr_wake_flags
= (errno
== KERNEL_EOPNOTSUPP
&& !(i
)->BSSID
.l
[0] && i
->m
->SystemWakeOnLANEnabled
) ? IF_WAKE_ON_MAGIC_PACKET
: 0;
4451 // 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
4453 LogSPS("%-6s %#-14a %s WOMP", i
->ifinfo
.ifname
, &i
->ifinfo
.ip
, (ifr
.ifr_wake_flags
& IF_WAKE_ON_MAGIC_PACKET
) ? "supports" : "no");
4455 return((ifr
.ifr_wake_flags
& IF_WAKE_ON_MAGIC_PACKET
) != 0);
4458 mDNSlocal u_int64_t
getExtendedFlags(char * ifa_name
)
4463 sockFD
= socket(AF_INET
, SOCK_DGRAM
, 0);
4466 LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno
, strerror(errno
));
4470 ifr
.ifr_addr
.sa_family
= AF_INET
;
4471 strlcpy(ifr
.ifr_name
, ifa_name
, sizeof(ifr
.ifr_name
));
4473 if (ioctl(sockFD
, SIOCGIFEFLAGS
, (caddr_t
)&ifr
) == -1)
4475 LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno
, strerror(errno
));
4478 LogInfo("getExtendedFlags: %s ifr_eflags = 0x%x", ifa_name
, ifr
.ifr_eflags
);
4481 return ifr
.ifr_eflags
;
4484 #if TARGET_OS_IPHONE
4486 // Function pointers for the routines we use in the MobileWiFi framework.
4487 static WiFiManagerClientRef (*WiFiManagerClientCreate_p
)(CFAllocatorRef allocator
, WiFiClientType type
) = mDNSNULL
;
4488 static CFArrayRef (*WiFiManagerClientCopyDevices_p
)(WiFiManagerClientRef manager
) = mDNSNULL
;
4489 static WiFiNetworkRef (*WiFiDeviceClientCopyCurrentNetwork_p
)(WiFiDeviceClientRef device
) = mDNSNULL
;
4490 static bool (*WiFiNetworkIsCarPlay_p
)(WiFiNetworkRef network
) = mDNSNULL
;
4492 mDNSlocal mDNSBool
MobileWiFiLibLoad(void)
4494 static mDNSBool isInitialized
= mDNSfalse
;
4495 static void *MobileWiFiLib_p
= mDNSNULL
;
4496 static const char path
[] = "/System/Library/PrivateFrameworks/MobileWiFi.framework/MobileWiFi";
4500 if (!MobileWiFiLib_p
)
4502 MobileWiFiLib_p
= dlopen(path
, RTLD_LAZY
| RTLD_LOCAL
);
4503 if (!MobileWiFiLib_p
)
4505 LogInfo("MobileWiFiLibLoad: dlopen() failed.");
4510 if (!WiFiManagerClientCreate_p
)
4512 WiFiManagerClientCreate_p
= dlsym(MobileWiFiLib_p
, "WiFiManagerClientCreate");
4513 if (!WiFiManagerClientCreate_p
)
4515 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCreate symbol failed.");
4520 if (!WiFiManagerClientCopyDevices_p
)
4522 WiFiManagerClientCopyDevices_p
= dlsym(MobileWiFiLib_p
, "WiFiManagerClientCopyDevices");
4523 if (!WiFiManagerClientCopyDevices_p
)
4525 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCopyDevices symbol failed.");
4530 if (!WiFiDeviceClientCopyCurrentNetwork_p
)
4532 WiFiDeviceClientCopyCurrentNetwork_p
= dlsym(MobileWiFiLib_p
, "WiFiDeviceClientCopyCurrentNetwork");
4533 if (!WiFiDeviceClientCopyCurrentNetwork_p
)
4535 LogInfo("MobileWiFiLibLoad: load of WiFiDeviceClientCopyCurrentNetwork symbol failed.");
4540 if (!WiFiNetworkIsCarPlay_p
)
4542 WiFiNetworkIsCarPlay_p
= dlsym(MobileWiFiLib_p
, "WiFiNetworkIsCarPlay");
4543 if (!WiFiNetworkIsCarPlay_p
)
4545 LogInfo("MobileWiFiLibLoad: load of WiFiNetworkIsCarPlay symbol failed.");
4550 isInitialized
= mDNStrue
;
4554 return isInitialized
;
4557 // Return true if the interface is associate to a CarPlay hosted SSID.
4558 mDNSlocal mDNSBool
IsCarPlaySSID(char *ifa_name
)
4560 static WiFiManagerClientRef manager
= NULL
;
4561 mDNSBool rvalue
= mDNSfalse
;
4563 if (!MobileWiFiLibLoad())
4566 // If we have associated with a CarPlay hosted SSID, then use the same
4567 // optimizations that are used if an interface has the IFEF_DIRECTLINK flag set.
4569 // Get one WiFiManagerClientRef to use for all calls.
4570 if (manager
== NULL
)
4571 manager
= WiFiManagerClientCreate_p(NULL
, kWiFiClientTypeNormal
);
4573 if (manager
== NULL
)
4575 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
4581 devices
= WiFiManagerClientCopyDevices_p(manager
);
4582 if (devices
!= NULL
)
4584 WiFiDeviceClientRef device
;
4585 WiFiNetworkRef network
;
4587 device
= (WiFiDeviceClientRef
)CFArrayGetValueAtIndex(devices
, 0);
4588 network
= WiFiDeviceClientCopyCurrentNetwork_p(device
);
4589 if (network
!= NULL
)
4591 if (WiFiNetworkIsCarPlay_p(network
))
4593 LogInfo("%s is CarPlay hosted", ifa_name
);
4605 #else // TARGET_OS_IPHONE
4607 mDNSlocal mDNSBool
IsCarPlaySSID(char *ifa_name
)
4609 (void)ifa_name
; // unused
4611 // OSX WifiManager currently does not implement WiFiNetworkIsCarPlay()
4615 #endif // TARGET_OS_IPHONE
4617 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
4618 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
4619 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
4620 // (e.g. sa_family not AF_INET or AF_INET6)
4621 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
, mDNSs32 utc
)
4623 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
4624 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
4625 u_int64_t eflags
= getExtendedFlags(ifa
->ifa_name
);
4628 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
4629 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
4631 NetworkInterfaceInfoOSX
**p
;
4632 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
4633 if (scope_id
== (*p
)->scope_id
&&
4634 mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) &&
4635 mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
4637 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
);
4638 // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
4639 // When interfaces are created with same MAC address, kernel resurrects the old interface.
4640 // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
4641 // we get the corresponding name for the interface index on which the packet was received and check against
4642 // the InterfaceList for a matching name. So, keep the name in sync
4643 strlcpy((*p
)->ifinfo
.ifname
, ifa
->ifa_name
, sizeof((*p
)->ifinfo
.ifname
));
4644 (*p
)->Exists
= mDNStrue
;
4645 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
4646 if ((*p
)->LastSeen
!= utc
) (*p
)->AppearanceTime
= utc
;
4648 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
4649 // we may need to start or stop or sleep proxy browse operation
4650 const mDNSBool NetWake
= NetWakeInterface(*p
);
4651 if ((*p
)->ifinfo
.NetWake
!= NetWake
)
4653 (*p
)->ifinfo
.NetWake
= NetWake
;
4654 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
4655 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
4656 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
4657 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
4658 if ((*p
)->Registered
)
4661 if (NetWake
) mDNS_ActivateNetWake_internal (m
, &(*p
)->ifinfo
);
4662 else mDNS_DeactivateNetWake_internal(m
, &(*p
)->ifinfo
);
4666 // Reset the flag if it has changed this time.
4667 (*p
)->ifinfo
.IgnoreIPv4LL
= ((eflags
& IFEF_ARPLL
) != 0) ? mDNSfalse
: mDNStrue
;
4672 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
4673 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
4674 if (!i
) return(mDNSNULL
);
4675 mDNSPlatformMemZero(i
, sizeof(NetworkInterfaceInfoOSX
));
4676 i
->ifinfo
.InterfaceID
= (mDNSInterfaceID
)(uintptr_t)scope_id
;
4678 i
->ifinfo
.mask
= mask
;
4679 strlcpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
4680 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
4681 // We can be configured to disable multicast advertisement, but we want to to support
4682 // local-only services, which need a loopback address record.
4683 i
->ifinfo
.Advertise
= m
->DivertMulticastAdvertisements
? ((ifa
->ifa_flags
& IFF_LOOPBACK
) ? mDNStrue
: mDNSfalse
) : m
->AdvertiseLocalAddresses
;
4684 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
4685 i
->ifinfo
.Loopback
= ((ifa
->ifa_flags
& IFF_LOOPBACK
) != 0) ? mDNStrue
: mDNSfalse
;
4686 i
->ifinfo
.IgnoreIPv4LL
= ((eflags
& IFEF_ARPLL
) != 0) ? mDNSfalse
: mDNStrue
;
4688 // Setting DirectLink indicates we can do the optimization of skipping the probe phase
4689 // for the interface address records since they should be unique.
4690 if (eflags
& IFEF_DIRECTLINK
)
4691 i
->ifinfo
.DirectLink
= mDNStrue
;
4693 i
->ifinfo
.DirectLink
= IsCarPlaySSID(ifa
->ifa_name
);
4697 i
->Exists
= mDNStrue
;
4698 i
->Flashing
= mDNSfalse
;
4699 i
->Occulting
= mDNSfalse
;
4700 i
->D2DInterface
= (eflags
& IFEF_LOCALNET_PRIVATE
) ? mDNStrue
: mDNSfalse
;
4701 if (eflags
& IFEF_AWDL
)
4703 // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
4704 // limited AWDL resources so we don't set the kDNSQClass_UnicastResponse bit in
4705 // Bonjour requests over the AWDL interface.
4706 i
->ifinfo
.SupportsUnicastMDNSResponse
= mDNSfalse
;
4707 AWDLInterfaceID
= i
->ifinfo
.InterfaceID
;
4708 i
->ifinfo
.DirectLink
= mDNStrue
;
4709 LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID
);
4713 i
->ifinfo
.SupportsUnicastMDNSResponse
= mDNStrue
;
4715 i
->AppearanceTime
= utc
; // Brand new interface; AppearanceTime is now
4717 i
->ifa_flags
= ifa
->ifa_flags
;
4718 i
->scope_id
= scope_id
;
4720 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
4724 i
->Registered
= mDNSNULL
;
4726 // Do this AFTER i->BSSID has been set up
4727 i
->ifinfo
.NetWake
= (eflags
& IFEF_EXPENSIVE
)? mDNSfalse
: NetWakeInterface(i
);
4728 GetMAC(&i
->ifinfo
.MAC
, scope_id
);
4729 if (i
->ifinfo
.NetWake
&& !i
->ifinfo
.MAC
.l
[0])
4730 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i
->ifinfo
.MAC
, scope_id
, i
->ifinfo
.ifname
, &ip
);
4736 #if APPLE_OSX_mDNSResponder
4738 #if COMPILER_LIKES_PRAGMA_MARK
4740 #pragma mark - AutoTunnel
4743 #define kRacoonPort 4500
4745 static DomainAuthInfo
* AnonymousRacoonConfig
= mDNSNULL
;
4747 #ifndef NO_SECURITYFRAMEWORK
4749 static CFMutableDictionaryRef domainStatusDict
= NULL
;
4751 mDNSlocal mStatus
CheckQuestionForStatus(const DNSQuestion
*const q
)
4755 if (q
->servAddr
.type
== mDNSAddrType_IPv4
&& mDNSIPv4AddressIsOnes(q
->servAddr
.ip
.v4
))
4756 return mStatus_NoSuchRecord
;
4757 else if (q
->state
== LLQ_Poll
)
4758 return mStatus_PollingMode
;
4759 else if (q
->state
!= LLQ_Established
&& !q
->DuplicateOf
)
4760 return mStatus_TransientErr
;
4763 return mStatus_NoError
;
4766 mDNSlocal mStatus
UpdateLLQStatus(const mDNS
*const m
, char *buffer
, int bufsz
, const DomainAuthInfo
*const info
)
4768 mStatus status
= mStatus_NoError
;
4769 DNSQuestion
* q
, *worst_q
= mDNSNULL
;
4770 for (q
= m
->Questions
; q
; q
=q
->next
)
4771 if (q
->AuthInfo
== info
)
4773 mStatus newStatus
= CheckQuestionForStatus(q
);
4774 if (newStatus
== mStatus_NoSuchRecord
) { status
= newStatus
; worst_q
= q
; break; }
4775 else if (newStatus
== mStatus_PollingMode
) { status
= newStatus
; worst_q
= q
; }
4776 else if (newStatus
== mStatus_TransientErr
&& status
== mStatus_NoError
) { status
= newStatus
; worst_q
= q
; }
4779 if (status
== mStatus_NoError
) mDNS_snprintf(buffer
, bufsz
, "Success");
4780 else if (status
== mStatus_NoSuchRecord
) mDNS_snprintf(buffer
, bufsz
, "GetZoneData %s: %##s", worst_q
->nta
? "not yet complete" : "failed", worst_q
->qname
.c
);
4781 else if (status
== mStatus_PollingMode
) mDNS_snprintf(buffer
, bufsz
, "Query polling %##s", worst_q
->qname
.c
);
4782 else if (status
== mStatus_TransientErr
) mDNS_snprintf(buffer
, bufsz
, "Query not yet established %##s", worst_q
->qname
.c
);
4786 mDNSlocal mStatus
UpdateRRStatus(const mDNS
*const m
, char *buffer
, int bufsz
, const DomainAuthInfo
*const info
)
4790 if (info
->deltime
) return mStatus_NoError
;
4791 for (r
= m
->ResourceRecords
; r
; r
= r
->next
)
4793 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
4794 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
4795 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
4796 // has already checked
4797 const domainname
*n
= r
->resrec
.name
;
4800 DomainAuthInfo
*ptr
;
4801 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
4802 if (SameDomainName(&ptr
->domain
, n
))
4804 if (ptr
== info
&& (r
->updateError
== mStatus_BadSig
|| r
->updateError
== mStatus_BadKey
|| r
->updateError
== mStatus_BadTime
))
4806 mDNS_snprintf(buffer
, bufsz
, "Resource record update failed for %##s", r
->resrec
.name
);
4807 return r
->updateError
;
4810 n
= (const domainname
*)(n
->c
+ 1 + n
->c
[0]);
4813 return mStatus_NoError
;
4816 #endif // ndef NO_SECURITYFRAMEWORK
4818 // MUST be called with lock held
4819 mDNSlocal
void UpdateAutoTunnelDomainStatus(const mDNS
*const m
, const DomainAuthInfo
*const info
)
4821 #ifdef NO_SECURITYFRAMEWORK
4825 // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
4826 // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
4827 const NATTraversalInfo
*const llq
= m
->LLQNAT
.clientCallback
? &m
->LLQNAT
: mDNSNULL
;
4828 const NATTraversalInfo
*const tun
= m
->AutoTunnelNAT
.clientContext
? &m
->AutoTunnelNAT
: mDNSNULL
;
4830 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
4831 CFStringRef domain
= NULL
;
4832 CFStringRef tmp
= NULL
;
4833 CFNumberRef num
= NULL
;
4834 mStatus status
= mStatus_NoError
;
4835 mStatus llqStatus
= mStatus_NoError
;
4836 char llqBuffer
[1024];
4840 if (!domainStatusDict
)
4842 domainStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
4843 if (!domainStatusDict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
4846 if (!dict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
4848 mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", info
->domain
.c
);
4849 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
4850 if (!domain
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
4854 if (CFDictionaryContainsKey(domainStatusDict
, domain
))
4856 CFDictionaryRemoveValue(domainStatusDict
, domain
);
4857 if (!m
->ShutdownTime
) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, mDNSNULL
, domainStatusDict
);
4865 mDNS_snprintf(buffer
, sizeof(buffer
), "%#a", &m
->Router
);
4866 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
4868 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
4871 CFDictionarySetValue(dict
, CFSTR("RouterAddress"), tmp
);
4877 mDNSu32 port
= mDNSVal16(llq
->ExternalPort
);
4879 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
4881 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
4884 CFDictionarySetValue(dict
, CFSTR("LLQExternalPort"), num
);
4890 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &llq
->Result
);
4892 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
4895 CFDictionarySetValue(dict
, CFSTR("LLQNPMStatus"), num
);
4903 mDNSu32 port
= mDNSVal16(tun
->ExternalPort
);
4905 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
4907 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
4910 CFDictionarySetValue(dict
, CFSTR("AutoTunnelExternalPort"), num
);
4914 mDNS_snprintf(buffer
, sizeof(buffer
), "%.4a", &tun
->ExternalAddress
);
4915 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
4917 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
4920 CFDictionarySetValue(dict
, CFSTR("ExternalAddress"), tmp
);
4926 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tun
->Result
);
4928 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
4931 CFDictionarySetValue(dict
, CFSTR("AutoTunnelNPMStatus"), num
);
4938 mDNSu32 code
= m
->LastNATMapResultCode
;
4940 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &code
);
4942 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
4945 CFDictionarySetValue(dict
, CFSTR("LastNATMapResultCode"), num
);
4950 mDNS_snprintf(buffer
, sizeof(buffer
), "Success");
4951 llqStatus
= UpdateLLQStatus(m
, llqBuffer
, sizeof(llqBuffer
), info
);
4952 status
= UpdateRRStatus(m
, buffer
, sizeof(buffer
), info
);
4954 // If we have a bad signature error updating a RR, it overrides any error as it needs to be
4955 // reported so that it can be fixed automatically (or the user needs to be notified)
4956 if (status
!= mStatus_NoError
)
4958 LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status
, buffer
);
4960 else if (m
->Router
.type
== mDNSAddrType_None
)
4962 status
= mStatus_NoRouter
;
4963 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - none");
4965 else if (m
->Router
.type
== mDNSAddrType_IPv4
&& mDNSIPv4AddressIsZero(m
->Router
.ip
.v4
))
4967 status
= mStatus_NoRouter
;
4968 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - v4 zero");
4970 else if (mDNSIPv6AddressIsZero(info
->AutoTunnelInnerAddress
))
4972 status
= mStatus_ServiceNotRunning
;
4973 mDNS_snprintf(buffer
, sizeof(buffer
), "No inner address");
4975 else if (!llq
&& !tun
)
4977 status
= mStatus_NotInitializedErr
;
4978 mDNS_snprintf(buffer
, sizeof(buffer
), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
4980 else if (llqStatus
== mStatus_NoSuchRecord
)
4983 mDNS_snprintf(buffer
, sizeof(buffer
), "%s", llqBuffer
);
4985 else if ((llq
&& llq
->Result
== mStatus_DoubleNAT
) || (tun
&& tun
->Result
== mStatus_DoubleNAT
))
4987 status
= mStatus_DoubleNAT
;
4988 mDNS_snprintf(buffer
, sizeof(buffer
), "Double NAT: Router is reporting a private address");
4990 else if ((llq
&& llq
->Result
== mStatus_NATPortMappingDisabled
) ||
4991 (tun
&& tun
->Result
== mStatus_NATPortMappingDisabled
) ||
4992 (m
->LastNATMapResultCode
== NATErr_Refused
&& ((llq
&& !llq
->Result
&& mDNSIPPortIsZero(llq
->ExternalPort
)) || (tun
&& !tun
->Result
&& mDNSIPPortIsZero(tun
->ExternalPort
)))))
4994 status
= mStatus_NATPortMappingDisabled
;
4995 mDNS_snprintf(buffer
, sizeof(buffer
), "PCP/NAT-PMP is disabled on the router");
4997 else if ((llq
&& llq
->Result
) || (tun
&& tun
->Result
))
4999 status
= mStatus_NATTraversal
;
5000 mDNS_snprintf(buffer
, sizeof(buffer
), "Error obtaining NAT port mapping from router");
5002 else if ((llq
&& mDNSIPPortIsZero(llq
->ExternalPort
)) || (tun
&& mDNSIPPortIsZero(tun
->ExternalPort
)))
5004 status
= mStatus_NATTraversal
;
5005 mDNS_snprintf(buffer
, sizeof(buffer
), "Unable to obtain NAT port mapping from router");
5010 mDNS_snprintf(buffer
, sizeof(buffer
), "%s", llqBuffer
);
5011 LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status
, buffer
);
5014 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
);
5016 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
5019 CFDictionarySetValue(dict
, CFSTR("StatusCode"), num
);
5023 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
5025 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
5028 CFDictionarySetValue(dict
, CFSTR("StatusMessage"), tmp
);
5032 if (!CFDictionaryContainsKey(domainStatusDict
, domain
) ||
5033 !CFEqual(dict
, (CFMutableDictionaryRef
)CFDictionaryGetValue(domainStatusDict
, domain
)))
5035 CFDictionarySetValue(domainStatusDict
, domain
, dict
);
5036 if (!m
->ShutdownTime
)
5038 static char statusBuf
[16];
5039 mDNS_snprintf(statusBuf
, sizeof(statusBuf
), "%d", (int)status
);
5040 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.domainstatus", status
? "failure" : "success", statusBuf
, "");
5041 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, mDNSNULL
, domainStatusDict
);
5048 debugf("UpdateAutoTunnelDomainStatus: %s", buffer
);
5049 #endif // def NO_SECURITYFRAMEWORK
5052 // MUST be called with lock held
5053 mDNSexport
void UpdateAutoTunnelDomainStatuses(const mDNS
*const m
)
5055 #ifdef NO_SECURITYFRAMEWORK
5059 DomainAuthInfo
* info
;
5060 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
5061 if (info
->AutoTunnel
&& !info
->deltime
)
5062 UpdateAutoTunnelDomainStatus(m
, info
);
5063 #endif // def NO_SECURITYFRAMEWORK
5066 mDNSlocal
void UpdateAnonymousRacoonConfig(mDNS
*m
) // Determine whether we need racoon to accept incoming connections
5068 DomainAuthInfo
*info
;
5070 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
5071 if (info
->AutoTunnel
&& !info
->deltime
&& (!mDNSIPPortIsZero(m
->AutoTunnelNAT
.ExternalPort
) || !mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
)))
5074 if (info
!= AnonymousRacoonConfig
)
5076 AnonymousRacoonConfig
= info
;
5077 LogInfo("UpdateAnonymousRacoonConfig need not be done in mDNSResponder");
5081 mDNSlocal
void AutoTunnelRecordCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
5083 // Caller must hold the lock
5084 mDNSlocal mDNSBool
DeregisterAutoTunnelRecord(mDNS
*m
, DomainAuthInfo
*info
, AuthRecord
* record
)
5088 LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info
->domain
.c
, record
->namestorage
.c
);
5090 if (record
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
5092 mStatus err
= mDNS_Deregister_internal(m
, record
, mDNS_Dereg_normal
);
5095 record
->resrec
.RecordType
= kDNSRecordTypeUnregistered
;
5096 LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err
, info
->domain
.c
, record
->namestorage
.c
);
5099 else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
5101 else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record
->resrec
.RecordType
);
5106 // Caller must hold the lock
5107 mDNSlocal
void DeregisterAutoTunnelHostRecord(mDNS
*m
, DomainAuthInfo
*info
)
5109 if (!DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnelHostRecord
))
5111 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
5112 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
5116 // Caller must hold the lock
5117 mDNSlocal
void UpdateAutoTunnelHostRecord(mDNS
*m
, DomainAuthInfo
*info
)
5120 mDNSBool NATProblem
= mDNSIPPortIsZero(m
->AutoTunnelNAT
.ExternalPort
) || m
->AutoTunnelNAT
.Result
;
5124 if (!info
->AutoTunnelServiceStarted
|| info
->deltime
|| m
->ShutdownTime
|| mDNSIPv6AddressIsZero(info
->AutoTunnelInnerAddress
) || (m
->SleepState
!= SleepState_Awake
&& NATProblem
))
5126 LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
5127 info
->domain
.c
, info
->AutoTunnelServiceStarted
, info
->deltime
, &info
->AutoTunnelInnerAddress
, m
->SleepState
);
5128 DeregisterAutoTunnelHostRecord(m
, info
);
5130 else if (info
->AutoTunnelHostRecord
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
5132 mDNS_SetupResourceRecord(&info
->AutoTunnelHostRecord
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
,
5133 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
5134 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
5135 AppendDomainLabel(&info
->AutoTunnelHostRecord
.namestorage
, &m
->hostlabel
);
5136 AppendDomainName (&info
->AutoTunnelHostRecord
.namestorage
, &info
->domain
);
5137 info
->AutoTunnelHostRecord
.resrec
.rdata
->u
.ipv6
= info
->AutoTunnelInnerAddress
;
5138 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
5140 err
= mDNS_Register_internal(m
, &info
->AutoTunnelHostRecord
);
5141 if (err
) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
5144 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
5145 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
5146 LogInfo("UpdateAutoTunnelHostRecord registering %##s", info
->AutoTunnelHostRecord
.namestorage
.c
);
5149 else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info
->AutoTunnelHostRecord
.resrec
.RecordType
);
5152 // Caller must hold the lock
5153 mDNSlocal
void DeregisterAutoTunnelServiceRecords(mDNS
*m
, DomainAuthInfo
*info
)
5155 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info
->domain
.c
);
5157 DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnelTarget
);
5158 DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnelService
);
5159 UpdateAutoTunnelHostRecord(m
, info
);
5162 // Caller must hold the lock
5163 mDNSlocal
void UpdateAutoTunnelServiceRecords(mDNS
*m
, DomainAuthInfo
*info
)
5167 if (!info
->AutoTunnelServiceStarted
|| info
->deltime
|| m
->ShutdownTime
|| mDNSIPPortIsZero(m
->AutoTunnelNAT
.ExternalPort
) || m
->AutoTunnelNAT
.Result
)
5169 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
);
5170 DeregisterAutoTunnelServiceRecords(m
, info
);
5174 if (info
->AutoTunnelTarget
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
5176 // 1. Set up our address record for the external tunnel address
5177 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
5178 mDNS_SetupResourceRecord(&info
->AutoTunnelTarget
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, kHostNameTTL
,
5179 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
5180 AssignDomainName (&info
->AutoTunnelTarget
.namestorage
, (const domainname
*) "\x0B" "_autotunnel");
5181 AppendDomainLabel(&info
->AutoTunnelTarget
.namestorage
, &m
->hostlabel
);
5182 AppendDomainName (&info
->AutoTunnelTarget
.namestorage
, &info
->domain
);
5183 info
->AutoTunnelTarget
.resrec
.rdata
->u
.ipv4
= m
->AutoTunnelNAT
.ExternalAddress
;
5184 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
5186 mStatus err
= mDNS_Register_internal(m
, &info
->AutoTunnelTarget
);
5187 if (err
) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err
, info
->AutoTunnelTarget
.namestorage
.c
);
5188 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info
->AutoTunnelTarget
.namestorage
.c
);
5190 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info
->AutoTunnelTarget
.resrec
.RecordType
);
5192 if (info
->AutoTunnelService
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
5194 // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
5195 mDNS_SetupResourceRecord(&info
->AutoTunnelService
, mDNSNULL
, mDNSInterface_Any
, kDNSType_SRV
, kHostNameTTL
,
5196 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
5197 AssignDomainName (&info
->AutoTunnelService
.namestorage
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
5198 AppendDomainLabel(&info
->AutoTunnelService
.namestorage
, &m
->hostlabel
);
5199 AppendDomainName (&info
->AutoTunnelService
.namestorage
, &info
->domain
);
5200 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.priority
= 0;
5201 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.weight
= 0;
5202 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.port
= m
->AutoTunnelNAT
.ExternalPort
;
5203 AssignDomainName(&info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.target
, &info
->AutoTunnelTarget
.namestorage
);
5204 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
5206 mStatus err
= mDNS_Register_internal(m
, &info
->AutoTunnelService
);
5207 if (err
) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
5208 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info
->AutoTunnelService
.namestorage
.c
);
5210 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info
->AutoTunnelService
.resrec
.RecordType
);
5212 UpdateAutoTunnelHostRecord(m
, info
);
5214 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
5215 info
->AutoTunnelTarget
.namestorage
.c
, &m
->AdvertisedV4
.ip
.v4
, mDNSVal16(m
->AutoTunnelNAT
.IntPort
),
5216 info
->AutoTunnelHostRecord
.namestorage
.c
, &info
->AutoTunnelInnerAddress
);
5221 // Caller must hold the lock
5222 mDNSlocal
void DeregisterAutoTunnelDeviceInfoRecord(mDNS
*m
, DomainAuthInfo
*info
)
5224 DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnelDeviceInfo
);
5227 // Caller must hold the lock
5228 mDNSlocal
void UpdateAutoTunnelDeviceInfoRecord(mDNS
*m
, DomainAuthInfo
*info
)
5232 if (!info
->AutoTunnelServiceStarted
|| info
->deltime
|| m
->ShutdownTime
)
5233 DeregisterAutoTunnelDeviceInfoRecord(m
, info
);
5234 else if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
5236 mDNS_SetupResourceRecord(&info
->AutoTunnelDeviceInfo
, mDNSNULL
, mDNSInterface_Any
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
5237 ConstructServiceName(&info
->AutoTunnelDeviceInfo
.namestorage
, &m
->nicelabel
, &DeviceInfoName
, &info
->domain
);
5239 info
->AutoTunnelDeviceInfo
.resrec
.rdlength
= initializeDeviceInfoTXT(m
, info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
);
5240 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
5242 mStatus err
= mDNS_Register_internal(m
, &info
->AutoTunnelDeviceInfo
);
5243 if (err
) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
5244 else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info
->AutoTunnelDeviceInfo
.namestorage
.c
);
5247 LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info
->AutoTunnelDeviceInfo
.resrec
.RecordType
);
5250 // Caller must hold the lock
5251 mDNSlocal
void DeregisterAutoTunnel6Record(mDNS
*m
, DomainAuthInfo
*info
)
5253 LogInfo("DeregisterAutoTunnel6Record %##s", info
->domain
.c
);
5255 DeregisterAutoTunnelRecord(m
, info
, &info
->AutoTunnel6Record
);
5256 UpdateAutoTunnelHostRecord(m
, info
);
5257 UpdateAutoTunnelDomainStatus(m
, info
);
5260 // Caller must hold the lock
5261 mDNSlocal
void UpdateAutoTunnel6Record(mDNS
*m
, DomainAuthInfo
*info
)
5265 if (!info
->AutoTunnelServiceStarted
|| info
->deltime
|| m
->ShutdownTime
|| mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
) || m
->SleepState
!= SleepState_Awake
)
5266 DeregisterAutoTunnel6Record(m
, info
);
5267 else if (info
->AutoTunnel6Record
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
5269 mDNS_SetupResourceRecord(&info
->AutoTunnel6Record
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
,
5270 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
5271 AssignDomainName (&info
->AutoTunnel6Record
.namestorage
, (const domainname
*) "\x0C" "_autotunnel6");
5272 AppendDomainLabel(&info
->AutoTunnel6Record
.namestorage
, &m
->hostlabel
);
5273 AppendDomainName (&info
->AutoTunnel6Record
.namestorage
, &info
->domain
);
5274 info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
= m
->AutoTunnelRelayAddr
;
5275 info
->AutoTunnel6Record
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
5277 mStatus err
= mDNS_Register_internal(m
, &info
->AutoTunnel6Record
);
5278 if (err
) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err
, info
->AutoTunnel6Record
.namestorage
.c
);
5279 else LogInfo("UpdateAutoTunnel6Record registering %##s", info
->AutoTunnel6Record
.namestorage
.c
);
5281 UpdateAutoTunnelHostRecord(m
, info
);
5283 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
5284 info
->AutoTunnel6Record
.namestorage
.c
, &m
->AutoTunnelRelayAddr
,
5285 info
->AutoTunnelHostRecord
.namestorage
.c
, &info
->AutoTunnelInnerAddress
);
5288 else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info
->AutoTunnel6Record
.resrec
.RecordType
);
5291 mDNSlocal
void AutoTunnelRecordCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
5293 DomainAuthInfo
*info
= (DomainAuthInfo
*)rr
->RecordContext
;
5294 if (result
== mStatus_MemFree
)
5296 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m
, rr
));
5300 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
5301 if (rr
== &info
->AutoTunnelHostRecord
)
5303 rr
->namestorage
.c
[0] = 0;
5304 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
5305 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m
->NextSRVUpdate
- m
->timenow
, m
->timenow
);
5307 if (m
->ShutdownTime
)
5309 LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
5313 if (rr
== &info
->AutoTunnelHostRecord
)
5315 LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
5316 UpdateAutoTunnelHostRecord(m
,info
);
5318 else if (rr
== &info
->AutoTunnelDeviceInfo
)
5320 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
5321 UpdateAutoTunnelDeviceInfoRecord(m
,info
);
5323 else if (rr
== &info
->AutoTunnelService
|| rr
== &info
->AutoTunnelTarget
)
5325 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
5326 UpdateAutoTunnelServiceRecords(m
,info
);
5328 else if (rr
== &info
->AutoTunnel6Record
)
5330 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
5331 UpdateAutoTunnel6Record(m
,info
);
5338 mDNSlocal
void AutoTunnelNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
5340 DomainAuthInfo
*info
;
5342 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
5343 n
->Result
, &n
->ExternalAddress
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->ExternalPort
));
5347 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
5348 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m
->NextSRVUpdate
- m
->timenow
, m
->timenow
);
5350 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
5351 if (info
->AutoTunnel
)
5352 UpdateAutoTunnelServiceRecords(m
, info
);
5354 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
5356 UpdateAutoTunnelDomainStatuses(m
);
5361 mDNSlocal
void AutoTunnelHostNameChanged(mDNS
*m
, DomainAuthInfo
*info
)
5363 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m
->hostlabel
.c
, info
->domain
.c
);
5366 // We forcibly deregister the records that are based on the hostname.
5367 // When deregistration of each completes, the MemFree callback will make the
5368 // appropriate Update* call to use the new name to reregister.
5369 DeregisterAutoTunnelHostRecord(m
, info
);
5370 DeregisterAutoTunnelDeviceInfoRecord(m
, info
);
5371 DeregisterAutoTunnelServiceRecords(m
, info
);
5372 DeregisterAutoTunnel6Record(m
, info
);
5373 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
5377 // Must be called with the lock held
5378 mDNSexport
void StartServerTunnel(mDNS
*const m
, DomainAuthInfo
*const info
)
5380 if (info
->deltime
) return;
5382 if (info
->AutoTunnelServiceStarted
)
5384 // On wake from sleep, this function will be called when determining SRV targets,
5385 // and needs to re-register the host record for the target to be set correctly
5386 UpdateAutoTunnelHostRecord(m
, info
);
5390 info
->AutoTunnelServiceStarted
= mDNStrue
;
5392 // Now that we have a service in this domain, we need to try to register the
5393 // AutoTunnel records, because the relay connection & NAT-T may have already been
5394 // started for another domain. If the relay connection is not up or the NAT-T has not
5395 // yet succeeded, the Update* functions are smart enough to not register the records.
5396 // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
5397 // decide whether to register the AutoTunnel records in the calls below.
5398 UpdateAutoTunnelServiceRecords(m
, info
);
5399 UpdateAutoTunnel6Record(m
, info
);
5400 UpdateAutoTunnelDeviceInfoRecord(m
, info
);
5401 UpdateAutoTunnelHostRecord(m
, info
);
5403 // If the global AutoTunnel NAT-T is not yet started, start it.
5404 if (!m
->AutoTunnelNAT
.clientContext
)
5406 m
->AutoTunnelNAT
.clientCallback
= AutoTunnelNATCallback
;
5407 m
->AutoTunnelNAT
.clientContext
= (void*)1; // Means AutoTunnelNAT Traversal is active;
5408 m
->AutoTunnelNAT
.Protocol
= NATOp_MapUDP
;
5409 m
->AutoTunnelNAT
.IntPort
= IPSECPort
;
5410 m
->AutoTunnelNAT
.RequestedPort
= IPSECPort
;
5411 m
->AutoTunnelNAT
.NATLease
= 0;
5412 mStatus err
= mDNS_StartNATOperation_internal(m
, &m
->AutoTunnelNAT
);
5413 if (err
) LogMsg("StartServerTunnel: error %d starting NAT mapping", err
);
5417 mDNSlocal mStatus
AutoTunnelSetKeys(ClientTunnel
*tun
, mDNSBool AddNew
)
5419 mDNSv6Addr loc_outer6
;
5420 mDNSv6Addr rmt_outer6
;
5422 // When we are tunneling over IPv6 Relay address, the port number is zero
5423 if (mDNSIPPortIsZero(tun
->rmt_outer_port
))
5425 loc_outer6
= tun
->loc_outer6
;
5426 rmt_outer6
= tun
->rmt_outer6
;
5430 loc_outer6
= zerov6Addr
;
5431 loc_outer6
.b
[0] = tun
->loc_outer
.b
[0];
5432 loc_outer6
.b
[1] = tun
->loc_outer
.b
[1];
5433 loc_outer6
.b
[2] = tun
->loc_outer
.b
[2];
5434 loc_outer6
.b
[3] = tun
->loc_outer
.b
[3];
5436 rmt_outer6
= zerov6Addr
;
5437 rmt_outer6
.b
[0] = tun
->rmt_outer
.b
[0];
5438 rmt_outer6
.b
[1] = tun
->rmt_outer
.b
[1];
5439 rmt_outer6
.b
[2] = tun
->rmt_outer
.b
[2];
5440 rmt_outer6
.b
[3] = tun
->rmt_outer
.b
[3];
5443 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)));
5446 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
5447 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
5449 mDNSlocal
void ReissueBlockedQuestionWithType(mDNS
*const m
, domainname
*d
, mDNSBool success
, mDNSu16 qtype
)
5451 DNSQuestion
*q
= m
->Questions
;
5454 if (q
->NoAnswer
== NoAnswer_Suspended
&& q
->qtype
== qtype
&& q
->AuthInfo
&& q
->AuthInfo
->AutoTunnel
&& SameDomainName(&q
->qname
, d
))
5456 LogInfo("Restart %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
5457 mDNSQuestionCallback
*tmp
= q
->QuestionCallback
;
5458 q
->QuestionCallback
= AutoTunnelCallback
; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
5459 mDNS_StopQuery(m
, q
);
5460 mDNS_StartQuery(m
, q
);
5461 q
->QuestionCallback
= tmp
; // Restore QuestionCallback back to the real value
5462 if (!success
) q
->NoAnswer
= NoAnswer_Fail
;
5463 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
5464 // In general we have to assume that the question list might have changed in arbitrary ways.
5465 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
5466 // already in use. The safest solution is just to go back to the start of the list and start again.
5467 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
5468 // just one suspended question, so it's really a 2n algorithm.
5476 mDNSlocal
void ReissueBlockedQuestions(mDNS
*const m
, domainname
*d
, mDNSBool success
)
5478 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
5479 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
5480 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
5481 // 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.
5482 // 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.
5483 ReissueBlockedQuestionWithType(m
, d
, success
, kDNSType_AAAA
);
5484 ReissueBlockedQuestionWithType(m
, d
, mDNStrue
, kDNSType_A
);
5487 mDNSlocal
void UnlinkAndReissueBlockedQuestions(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool success
)
5489 ClientTunnel
**p
= &m
->TunnelClients
;
5490 while (*p
!= tun
&& *p
) p
= &(*p
)->next
;
5491 if (*p
) *p
= tun
->next
;
5492 ReissueBlockedQuestions(m
, &tun
->dstname
, success
);
5493 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun
);
5494 freeL("ClientTunnel", tun
);
5497 mDNSlocal mDNSBool
TunnelClientDeleteMatching(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool v6Tunnel
)
5500 mDNSBool needSetKeys
= mDNStrue
;
5505 // Is this a tunnel to the same host that we are trying to setup now?
5506 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
5509 ClientTunnel
*old
= *p
;
5512 if (!mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue; }
5513 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
5514 if (old
->q
.ThisQInterval
>= 0)
5516 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
5517 mDNS_StopQuery(m
, &old
->q
);
5519 else if (!mDNSSameIPv6Address((*p
)->rmt_inner
, tun
->rmt_inner
) ||
5520 !mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
5521 !mDNSSameIPv6Address(old
->loc_outer6
, tun
->loc_outer6
) ||
5522 !mDNSSameIPv6Address(old
->rmt_outer6
, tun
->rmt_outer6
))
5524 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
5525 // the other parameters of the tunnel are different
5526 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
5527 AutoTunnelSetKeys(old
, mDNSfalse
);
5531 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
5532 // as "tun" and "old" are identical
5533 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
,
5535 needSetKeys
= mDNSfalse
;
5540 if (mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue; }
5541 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
5542 if (old
->q
.ThisQInterval
>= 0)
5544 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
5545 mDNS_StopQuery(m
, &old
->q
);
5547 else if (!mDNSSameIPv6Address((*p
)->rmt_inner
, tun
->rmt_inner
) ||
5548 !mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
5549 !mDNSSameIPv4Address(old
->loc_outer
, tun
->loc_outer
) ||
5550 !mDNSSameIPv4Address(old
->rmt_outer
, tun
->rmt_outer
) ||
5551 !mDNSSameIPPort(old
->rmt_outer_port
, tun
->rmt_outer_port
))
5553 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
5554 // the other parameters of the tunnel are different
5555 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
5556 AutoTunnelSetKeys(old
, mDNSfalse
);
5560 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
5561 // as "tun" and "old" are identical
5562 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
,
5564 needSetKeys
= mDNSfalse
;
5569 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old
);
5570 freeL("ClientTunnel", old
);
5576 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
5577 // tunnel will be deleted
5578 mDNSlocal
void TunnelClientDeleteAny(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool v6Tunnel
)
5585 // If there is more than one client tunnel to the same host, delete all of them.
5586 // We do this by just checking against the EUI64 rather than the full address
5587 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
5590 ClientTunnel
*old
= *p
;
5593 if (!mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue;}
5594 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
5598 if (mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue;}
5599 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
5601 if (old
->q
.ThisQInterval
>= 0)
5603 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
5604 mDNS_StopQuery(m
, &old
->q
);
5608 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
5609 AutoTunnelSetKeys(old
, mDNSfalse
);
5612 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old
);
5613 freeL("ClientTunnel", old
);
5618 mDNSlocal
void TunnelClientFinish(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
)
5620 mDNSBool needSetKeys
= mDNStrue
;
5621 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
5622 mDNSBool v6Tunnel
= mDNSfalse
;
5623 DomainAuthInfo
*info
;
5625 // If the port is zero, then we have a relay address of the peer
5626 if (mDNSIPPortIsZero(tun
->rmt_outer_port
))
5627 v6Tunnel
= mDNStrue
;
5631 LogInfo("TunnelClientFinish: Relay address %.16a", &answer
->rdata
->u
.ipv6
);
5632 tun
->rmt_outer6
= answer
->rdata
->u
.ipv6
;
5633 tun
->loc_outer6
= m
->AutoTunnelRelayAddr
;
5637 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer
->rdata
->u
.ipv4
);
5638 tun
->rmt_outer
= answer
->rdata
->u
.ipv4
;
5639 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
5640 tmpDst
.ip
.v4
= tun
->rmt_outer
;
5641 mDNSAddr tmpSrc
= zeroAddr
;
5642 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
5643 if (tmpSrc
.type
== mDNSAddrType_IPv4
) tun
->loc_outer
= tmpSrc
.ip
.v4
;
5644 else tun
->loc_outer
= m
->AdvertisedV4
.ip
.v4
;
5647 question
->ThisQInterval
= -1; // So we know this tunnel setup has completed
5649 info
= GetAuthInfoForName(m
, &tun
->dstname
);
5652 LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun
->dstname
.c
);
5653 ReissueBlockedQuestions(m
, &tun
->dstname
, mDNSfalse
);
5657 tun
->loc_inner
= info
->AutoTunnelInnerAddress
;
5659 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
5660 // look for existing tunnels to see whether they have the same information for our peer.
5661 // If not, delete them and need to create a new tunnel. If they are same, just use the
5662 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
5663 TunnelClientDeleteAny(m
, tun
, !v6Tunnel
);
5664 needSetKeys
= TunnelClientDeleteMatching(m
, tun
, v6Tunnel
);
5666 if (needSetKeys
) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel
? "IPv6" : "IPv4"), tun
->dstname
.c
, &tun
->rmt_inner
);
5667 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel
? "IPv6" : "IPv4"), tun
->dstname
.c
, &tun
->rmt_inner
);
5669 mStatus result
= needSetKeys
? AutoTunnelSetKeys(tun
, mDNStrue
) : mStatus_NoError
;
5670 static char msgbuf
[32];
5671 mDNS_snprintf(msgbuf
, sizeof(msgbuf
), "Tunnel setup - %d", result
);
5672 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.config", result
? "failure" : "success", msgbuf
, "");
5673 // Kick off any questions that were held pending this tunnel setup
5674 ReissueBlockedQuestions(m
, &tun
->dstname
, (result
== mStatus_NoError
) ? mDNStrue
: mDNSfalse
);
5677 mDNSexport
void AutoTunnelCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
5679 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
5680 DomainAuthInfo
*info
;
5682 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun
, AddRecord
, answer
->rdlength
, question
->qtype
);
5684 if (!AddRecord
) return;
5685 mDNS_StopQuery(m
, question
);
5687 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
5688 // The code below will look for _autotunnel._udp SRV record followed by A record
5689 if (tun
->tc_state
!= TC_STATE_AAAA_PEER_RELAY
&& !answer
->rdlength
)
5691 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
5692 static char msgbuf
[16];
5693 mDNS_snprintf(msgbuf
, sizeof(msgbuf
), "%s lookup", DNSTypeName(question
->qtype
));
5694 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.config", "failure", msgbuf
, "");
5695 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNSfalse
);
5699 switch (tun
->tc_state
)
5701 case TC_STATE_AAAA_PEER
:
5702 if (question
->qtype
!= kDNSType_AAAA
)
5704 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question
->qtype
);
5706 info
= GetAuthInfoForName(m
, &tun
->dstname
);
5709 LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun
->dstname
.c
);
5710 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNStrue
);
5713 if (mDNSSameIPv6Address(answer
->rdata
->u
.ipv6
, info
->AutoTunnelInnerAddress
))
5715 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer
->rdata
->u
.ipv6
);
5716 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNStrue
);
5719 if (info
&& mDNSSameIPv6NetworkPart(answer
->rdata
->u
.ipv6
, info
->AutoTunnelInnerAddress
))
5721 LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer
->rdata
->u
.ipv6
);
5722 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNStrue
);
5725 tun
->rmt_inner
= answer
->rdata
->u
.ipv6
;
5726 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun
->rmt_inner
);
5727 if (!mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
))
5729 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
5730 tun
->tc_state
= TC_STATE_AAAA_PEER_RELAY
;
5731 question
->qtype
= kDNSType_AAAA
;
5732 AssignDomainName(&question
->qname
, (const domainname
*) "\x0C" "_autotunnel6");
5736 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
5737 tun
->tc_state
= TC_STATE_SRV_PEER
;
5738 question
->qtype
= kDNSType_SRV
;
5739 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
5741 AppendDomainName(&question
->qname
, &tun
->dstname
);
5742 mDNS_StartQuery(m
, &tun
->q
);
5744 case TC_STATE_AAAA_PEER_RELAY
:
5745 if (question
->qtype
!= kDNSType_AAAA
)
5747 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question
->qtype
);
5749 // If it failed, look for the SRV record.
5750 if (!answer
->rdlength
)
5752 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
5753 tun
->tc_state
= TC_STATE_SRV_PEER
;
5754 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
5755 AppendDomainName(&question
->qname
, &tun
->dstname
);
5756 question
->qtype
= kDNSType_SRV
;
5757 mDNS_StartQuery(m
, &tun
->q
);
5760 TunnelClientFinish(m
, question
, answer
);
5762 case TC_STATE_SRV_PEER
:
5763 if (question
->qtype
!= kDNSType_SRV
)
5765 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question
->qtype
);
5767 LogInfo("AutoTunnelCallback: SRV target name %##s", answer
->rdata
->u
.srv
.target
.c
);
5768 tun
->tc_state
= TC_STATE_ADDR_PEER
;
5769 AssignDomainName(&tun
->q
.qname
, &answer
->rdata
->u
.srv
.target
);
5770 tun
->rmt_outer_port
= answer
->rdata
->u
.srv
.port
;
5771 question
->qtype
= kDNSType_A
;
5772 mDNS_StartQuery(m
, &tun
->q
);
5774 case TC_STATE_ADDR_PEER
:
5775 if (question
->qtype
!= kDNSType_A
)
5777 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question
->qtype
);
5779 TunnelClientFinish(m
, question
, answer
);
5782 LogMsg("AutoTunnelCallback: Unknown question %p", question
);
5786 // Must be called with the lock held
5787 mDNSexport
void AddNewClientTunnel(mDNS
*const m
, DNSQuestion
*const q
)
5789 ClientTunnel
*p
= mallocL("ClientTunnel", sizeof(ClientTunnel
));
5791 AssignDomainName(&p
->dstname
, &q
->qname
);
5792 p
->MarkedForDeletion
= mDNSfalse
;
5793 p
->loc_inner
= zerov6Addr
;
5794 p
->loc_outer
= zerov4Addr
;
5795 p
->loc_outer6
= zerov6Addr
;
5796 p
->rmt_inner
= zerov6Addr
;
5797 p
->rmt_outer
= zerov4Addr
;
5798 p
->rmt_outer6
= zerov6Addr
;
5799 p
->rmt_outer_port
= zeroIPPort
;
5800 p
->tc_state
= TC_STATE_AAAA_PEER
;
5801 p
->next
= m
->TunnelClients
;
5802 m
->TunnelClients
= p
; // We intentionally build list in reverse order
5804 p
->q
.InterfaceID
= mDNSInterface_Any
;
5806 p
->q
.Target
= zeroAddr
;
5807 AssignDomainName(&p
->q
.qname
, &q
->qname
);
5808 p
->q
.qtype
= kDNSType_AAAA
;
5809 p
->q
.qclass
= kDNSClass_IN
;
5810 p
->q
.LongLived
= mDNSfalse
;
5811 p
->q
.ExpectUnique
= mDNStrue
;
5812 p
->q
.ForceMCast
= mDNSfalse
;
5813 p
->q
.ReturnIntermed
= mDNStrue
;
5814 p
->q
.SuppressUnusable
= mDNSfalse
;
5815 p
->q
.SearchListIndex
= 0;
5816 p
->q
.AppendSearchDomains
= 0;
5817 p
->q
.RetryWithSearchDomains
= mDNSfalse
;
5818 p
->q
.TimeoutQuestion
= 0;
5819 p
->q
.WakeOnResolve
= 0;
5820 p
->q
.UseBackgroundTrafficClass
= mDNSfalse
;
5821 p
->q
.ValidationRequired
= 0;
5822 p
->q
.ValidatingResponse
= 0;
5823 p
->q
.ProxyQuestion
= 0;
5824 p
->q
.qnameOrig
= mDNSNULL
;
5825 p
->q
.AnonInfo
= mDNSNULL
;
5826 p
->q
.pid
= mDNSPlatformGetPID();
5828 p
->q
.QuestionCallback
= AutoTunnelCallback
;
5829 p
->q
.QuestionContext
= p
;
5831 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p
, &q
->qname
.c
, DNSTypeName(q
->qtype
), q
->LongLived
? " LongLived" : "");
5832 mDNS_StartQuery_internal(m
, &p
->q
);
5835 #endif // APPLE_OSX_mDNSResponder
5837 #if COMPILER_LIKES_PRAGMA_MARK
5839 #pragma mark - Power State & Configuration Change Management
5842 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
, mDNSs32 utc
)
5844 mDNSBool foundav4
= mDNSfalse
;
5845 mDNSBool foundav6
= mDNSfalse
;
5846 struct ifaddrs
*ifa
= myGetIfAddrs(0);
5847 struct ifaddrs
*v4Loopback
= NULL
;
5848 struct ifaddrs
*v6Loopback
= NULL
;
5849 char defaultname
[64];
5850 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
5851 if (InfoSocket
< 3 && errno
!= EAFNOSUPPORT
)
5852 LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
5854 if (m
->SleepState
== SleepState_Sleeping
) ifa
= NULL
;
5858 #if LIST_ALL_INTERFACES
5859 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
5860 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
5861 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5862 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
5863 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
5864 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5865 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
5866 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
5867 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5868 if (!(ifa
->ifa_flags
& IFF_UP
))
5869 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
5870 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5871 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
5872 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
5873 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5874 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
5875 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
5876 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5877 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
5878 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
5879 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5882 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
5884 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
5885 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(m
->PrimaryMAC
) && mDNSSameEthAddress(&m
->PrimaryMAC
, &zeroEthAddr
))
5886 mDNSPlatformMemCopy(m
->PrimaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6);
5889 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
)
5890 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
5892 if (!ifa
->ifa_netmask
)
5895 SetupAddr(&ip
, ifa
->ifa_addr
);
5896 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
5897 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
5899 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
5900 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5901 else if (ifa
->ifa_netmask
->sa_family
!= ifa
->ifa_addr
->sa_family
&& ifa
->ifa_netmask
->sa_family
!= 0)
5904 SetupAddr(&ip
, ifa
->ifa_addr
);
5905 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
5906 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
5908 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
5909 else if ((int)if_nametoindex(ifa
->ifa_name
) <= 0)
5911 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
));
5915 // Make sure ifa_netmask->sa_family is set correctly
5916 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5917 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
;
5918 int ifru_flags6
= 0;
5920 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
5921 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
5923 struct in6_ifreq ifr6
;
5924 mDNSPlatformMemZero((char *)&ifr6
, sizeof(ifr6
));
5925 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
5926 ifr6
.ifr_addr
= *sin6
;
5927 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
5928 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
5929 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
5932 if (!(ifru_flags6
& (IN6_IFF_TENTATIVE
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
5934 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
5936 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
5938 else if (sin6
->sin6_addr
.s6_addr
[0] != 0xFD)
5943 NetworkInterfaceInfoOSX
*i
= AddInterfaceToList(m
, ifa
, utc
);
5944 if (i
&& MulticastInterface(i
) && i
->ifinfo
.Advertise
)
5946 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
5947 foundav4
= mDNStrue
;
5949 foundav6
= mDNStrue
;
5955 ifa
= ifa
->ifa_next
;
5958 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
5959 if (!foundav4
&& v4Loopback
) AddInterfaceToList(m
, v4Loopback
, utc
);
5960 if (!foundav6
&& v6Loopback
) AddInterfaceToList(m
, v6Loopback
, utc
);
5962 // Now the list is complete, set the McastTxRx setting for each interface.
5963 NetworkInterfaceInfoOSX
*i
;
5964 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
5967 mDNSBool txrx
= MulticastInterface(i
);
5968 if (i
->ifinfo
.McastTxRx
!= txrx
)
5970 i
->ifinfo
.McastTxRx
= txrx
;
5971 i
->Exists
= 2; // State change; need to deregister and reregister this interface
5975 if (InfoSocket
>= 0)
5978 mDNS_snprintf(defaultname
, sizeof(defaultname
), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen
, HINFO_HWstring
,
5979 m
->PrimaryMAC
.b
[0], m
->PrimaryMAC
.b
[1], m
->PrimaryMAC
.b
[2], m
->PrimaryMAC
.b
[3], m
->PrimaryMAC
.b
[4], m
->PrimaryMAC
.b
[5]);
5981 // Set up the nice label
5982 domainlabel nicelabel
;
5984 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
5985 if (nicelabel
.c
[0] == 0)
5987 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname
);
5988 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
5991 // Set up the RFC 1034-compliant label
5992 domainlabel hostlabel
;
5994 GetUserSpecifiedLocalHostName(&hostlabel
);
5995 if (hostlabel
.c
[0] == 0)
5997 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname
);
5998 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
6001 mDNSBool namechange
= mDNSfalse
;
6003 // We use a case-sensitive comparison here because even though changing the capitalization
6004 // of the name alone is not significant to DNS, it's still a change from the user's point of view
6005 if (SameDomainLabelCS(m
->p
->usernicelabel
.c
, nicelabel
.c
))
6006 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
6009 if (m
->p
->usernicelabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
6010 LogMsg("User updated Computer Name from “%#s” to “%#s”", m
->p
->usernicelabel
.c
, nicelabel
.c
);
6011 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
6012 namechange
= mDNStrue
;
6015 if (SameDomainLabelCS(m
->p
->userhostlabel
.c
, hostlabel
.c
))
6016 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
6019 if (m
->p
->userhostlabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
6020 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m
->p
->userhostlabel
.c
, hostlabel
.c
);
6021 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
6023 namechange
= mDNStrue
;
6026 if (namechange
) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
6028 #if APPLE_OSX_mDNSResponder
6029 DomainAuthInfo
*info
;
6030 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
6031 if (info
->AutoTunnel
) AutoTunnelHostNameChanged(m
, info
);
6032 #endif // APPLE_OSX_mDNSResponder
6035 return(mStatus_NoError
);
6038 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
6039 // Returns -1 if all the one-bits are not contiguous
6040 mDNSlocal
int CountMaskBits(mDNSAddr
*mask
)
6042 int i
= 0, bits
= 0;
6043 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
6046 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
6047 while (b
& 0x80) { bits
++; b
<<= 1; }
6050 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
6054 // Returns count of non-link local V4 addresses registered (why? -- SC)
6055 mDNSlocal
int SetupActiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
6057 NetworkInterfaceInfoOSX
*i
;
6060 // Recalculate SuppressProbes time based on the current set of active interfaces.
6061 m
->SuppressProbes
= 0;
6062 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
6065 NetworkInterfaceInfo
*const n
= &i
->ifinfo
;
6066 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AF_UNSPEC
);
6067 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifinfo
.ifname
);
6069 if (i
->Registered
&& i
->Registered
!= primary
) // Sanity check
6071 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i
->Registered
, primary
);
6072 i
->Registered
= mDNSNULL
;
6077 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
6078 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
6079 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it.
6080 i
->Registered
= primary
;
6082 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
6083 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
6084 // 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.
6085 i
->Occulting
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->LastSeen
> 0 && utc
- i
->LastSeen
< 60);
6087 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
6088 // every time it creates a new interface. We think it is a duplicate and hence consider it
6089 // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
6090 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
6091 // logs a warning message to system.log noting frequent interface transitions.
6092 // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
6093 if ((strncmp(i
->ifinfo
.ifname
, "p2p", 3) == 0) || i
->ifinfo
.DirectLink
)
6095 LogInfo("SetupActiveInterfaces: %s interface registering %s %s", i
->ifinfo
.ifname
,
6096 i
->Flashing
? " (Flashing)" : "",
6097 i
->Occulting
? " (Occulting)" : "");
6098 mDNS_RegisterInterface(m
, n
, 0);
6102 mDNS_RegisterInterface(m
, n
, i
->Flashing
&& i
->Occulting
);
6105 if (!mDNSAddressIsLinkLocal(&n
->ip
)) count
++;
6106 LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
6107 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
, primary
, &n
->ip
, CountMaskBits(&n
->mask
),
6108 i
->Flashing
? " (Flashing)" : "",
6109 i
->Occulting
? " (Occulting)" : "",
6110 n
->InterfaceActive
? " (Primary)" : "");
6114 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
);
6115 #if TARGET_OS_EMBEDDED
6116 // We join the Bonjour multicast group on Apple embedded platforms ONLY when a client request is active,
6117 // so we leave the multicast group here to clear any residual group membership.
6118 if (i
->sa_family
== AF_INET
)
6121 primary
->ifa_v4addr
.s_addr
= n
->ip
.ip
.v4
.NotAnInteger
;
6122 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
6123 imr
.imr_interface
= primary
->ifa_v4addr
;
6125 if (SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AF_INET
) == i
)
6127 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IP_DROP_MEMBERSHIP for %.4a on %.4a", i
->ifinfo
.ifname
, i
->scope_id
, &imr
.imr_multiaddr
, &imr
.imr_interface
);
6128 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, &imr
, sizeof(imr
));
6129 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
6130 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err
, errno
, strerror(errno
));
6133 if (i
->sa_family
== AF_INET6
)
6135 struct ipv6_mreq i6mr
;
6136 i6mr
.ipv6mr_interface
= primary
->scope_id
;
6137 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroup_v6
.ip
.v6
;
6139 if (SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AF_INET6
) == i
)
6141 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IPV6_LEAVE_GROUP for %.16a on %u", i
->ifinfo
.ifname
, i
->scope_id
, &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
6142 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
6143 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
6144 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
6147 #endif // TARGET_OS_EMBEDDED
6151 if (i
->sa_family
== AF_INET
)
6154 primary
->ifa_v4addr
.s_addr
= n
->ip
.ip
.v4
.NotAnInteger
;
6155 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
6156 imr
.imr_interface
= primary
->ifa_v4addr
;
6158 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
6159 // before trying to join the group, to clear out stale kernel state which may be lingering.
6160 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
6161 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
6162 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
6163 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
6164 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
6165 // because by the time we get the configuration change notification, the interface is already gone,
6166 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
6167 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
6168 if (SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AF_INET
) == i
)
6170 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
);
6171 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, &imr
, sizeof(imr
));
6172 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
6173 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err
, errno
, strerror(errno
));
6176 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i
->ifinfo
.ifname
, i
->scope_id
, &imr
.imr_multiaddr
, &imr
.imr_interface
);
6177 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
6178 // Joining same group twice can give "Address already in use" error -- no need to report that
6179 if (err
< 0 && (errno
!= EADDRINUSE
))
6180 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err
, errno
, strerror(errno
), &imr
.imr_multiaddr
, &imr
.imr_interface
);
6182 if (i
->sa_family
== AF_INET6
)
6184 struct ipv6_mreq i6mr
;
6185 i6mr
.ipv6mr_interface
= primary
->scope_id
;
6186 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroup_v6
.ip
.v6
;
6188 if (SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AF_INET6
) == i
)
6190 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
);
6191 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
6192 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
6193 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
6196 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i
->ifinfo
.ifname
, i
->scope_id
, &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
6197 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
6198 // Joining same group twice can give "Address already in use" error -- no need to report that
6199 if (err
< 0 && (errno
!= EADDRINUSE
))
6200 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
6209 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
, mDNSs32 utc
)
6211 NetworkInterfaceInfoOSX
*i
;
6212 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
6214 if (i
->Exists
) i
->LastSeen
= utc
;
6215 i
->Exists
= mDNSfalse
;
6219 // Returns count of non-link local V4 addresses deregistered (why? -- SC)
6220 mDNSlocal
int ClearInactiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
6223 // If an interface is going away, then deregister this from the mDNSCore.
6224 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
6225 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
6226 // it refers to has gone away we'll crash.
6227 NetworkInterfaceInfoOSX
*i
;
6229 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
6231 // If this interface is no longer active, or its InterfaceID is changing, deregister it
6232 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AF_UNSPEC
);
6234 if (i
->Exists
== 0 || i
->Exists
== 2 || i
->Registered
!= primary
)
6236 i
->Flashing
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->AppearanceTime
< 60);
6237 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
6238 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
, primary
,
6239 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
),
6240 i
->Flashing
? " (Flashing)" : "",
6241 i
->Occulting
? " (Occulting)" : "",
6242 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
6244 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
6245 // every time it creates a new interface. We think it is a duplicate and hence consider it
6246 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
6247 // stale data returned to the application even after the interface is removed. The application
6248 // then starts to send data but the new interface is not yet created.
6249 // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
6250 if ((strncmp(i
->ifinfo
.ifname
, "p2p", 3) == 0) || i
->ifinfo
.DirectLink
)
6252 LogInfo("ClearInactiveInterfaces: %s interface deregistering %s %s", i
->ifinfo
.ifname
,
6253 i
->Flashing
? " (Flashing)" : "",
6254 i
->Occulting
? " (Occulting)" : "");
6255 mDNS_DeregisterInterface(m
, &i
->ifinfo
, 0);
6259 mDNS_DeregisterInterface(m
, &i
->ifinfo
, i
->Flashing
&& i
->Occulting
);
6261 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
6262 i
->Registered
= mDNSNULL
;
6263 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
6264 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
6265 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
6267 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
6268 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
6273 // Now that everything that's going to deregister has done so, we can clean up and free the memory
6274 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
6278 // If no longer active, delete interface from list and free memory
6281 if (i
->LastSeen
== utc
) i
->LastSeen
= utc
- 1;
6282 mDNSBool
delete = (NumCacheRecordsForInterfaceID(m
, i
->ifinfo
.InterfaceID
) == 0) && (utc
- i
->LastSeen
>= 60);
6283 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
6284 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
,
6285 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), utc
- i
->LastSeen
,
6286 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
6287 #if APPLE_OSX_mDNSResponder
6288 if (i
->BPF_fd
>= 0) CloseBPF(i
);
6289 #endif // APPLE_OSX_mDNSResponder
6293 freeL("NetworkInterfaceInfoOSX", i
);
6294 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
6302 mDNSlocal
void AppendDNameListElem(DNameListElem
***List
, mDNSu32 uid
, domainname
*name
)
6304 DNameListElem
*dnle
= (DNameListElem
*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem
));
6305 if (!dnle
) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
6308 dnle
->next
= mDNSNULL
;
6310 AssignDomainName(&dnle
->name
, name
);
6312 *List
= &dnle
->next
;
6316 mDNSlocal
int compare_dns_configs(const void *aa
, const void *bb
)
6318 dns_resolver_t
*a
= *(dns_resolver_t
**)aa
;
6319 dns_resolver_t
*b
= *(dns_resolver_t
**)bb
;
6321 return (a
->search_order
< b
->search_order
) ? -1 : (a
->search_order
== b
->search_order
) ? 0 : 1;
6324 mDNSlocal
void UpdateSearchDomainHash(mDNS
*const m
, MD5_CTX
*sdc
, char *domain
, mDNSInterfaceID InterfaceID
)
6327 mDNSu32 scopeid
= 0;
6333 // Hash the search domain name followed by the InterfaceID.
6334 // As we have scoped search domains, we also included InterfaceID. If either of them change,
6335 // we will detect it. Even if the order of them change, we will detect it.
6337 // Note: We have to handle a few of these tricky cases.
6339 // 1) Current: com, apple.com Changing to: comapple.com
6340 // 2) Current: a.com,b.com Changing to a.comb.com
6341 // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
6342 // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
6344 // There are more variants of the above. The key thing is if we include the null in each case
6345 // at the end of name and the InterfaceID, it will prevent a new name (which can't include
6346 // NULL as part of the name) to be mistakenly thought of as a old name.
6348 scopeid
= mDNSPlatformInterfaceIndexfromInterfaceID(m
, InterfaceID
, mDNStrue
);
6349 // mDNS_snprintf always null terminates
6350 if (mDNS_snprintf(ifid_buf
, sizeof(ifid_buf
), "%u", scopeid
) >= sizeof(ifid_buf
))
6351 LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid
);
6353 LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf
, ifid_buf
);
6354 MD5_Update(sdc
, buf
, strlen(buf
) + 1);
6355 MD5_Update(sdc
, ifid_buf
, strlen(ifid_buf
) + 1);
6358 mDNSlocal
void FinalizeSearchDomainHash(mDNS
*const m
, MD5_CTX
*sdc
)
6360 mDNSu8 md5_hash
[MD5_LEN
];
6362 MD5_Final(md5_hash
, sdc
);
6364 if (memcmp(md5_hash
, m
->SearchDomainsHash
, MD5_LEN
))
6366 // If the hash is different, either the search domains have changed or
6367 // the ordering between them has changed. Restart the questions that
6368 // would be affected by this.
6369 LogInfo("FinalizeSearchDomains: The hash is different");
6370 memcpy(m
->SearchDomainsHash
, md5_hash
, MD5_LEN
);
6371 RetrySearchDomainQuestions(m
);
6373 else { LogInfo("FinalizeSearchDomains: The hash is same"); }
6376 mDNSexport
const char *DNSScopeToString(mDNSu32 scope
)
6382 case kScopeInterfaceID
:
6383 return "InterfaceScoped";
6384 case kScopeServiceID
:
6385 return "ServiceScoped";
6391 mDNSlocal
void ConfigSearchDomains(mDNS
*const m
, dns_resolver_t
*resolver
, mDNSInterfaceID interfaceId
, mDNSu32 scope
, MD5_CTX
*sdc
, uint64_t generation
)
6393 const char *scopeString
= DNSScopeToString(scope
);
6397 if (scope
== kScopeNone
)
6398 interfaceId
= mDNSInterface_Any
;
6400 if (scope
== kScopeNone
|| scope
== kScopeInterfaceID
)
6402 for (j
= 0; j
< resolver
->n_search
; j
++)
6404 if (MakeDomainNameFromDNSNameString(&d
, resolver
->search
[j
]) != NULL
)
6406 static char interface_buf
[32];
6407 mDNS_snprintf(interface_buf
, sizeof(interface_buf
), "for interface %s", InterfaceNameForID(m
, interfaceId
));
6408 LogInfo("ConfigSearchDomains: (%s) configuring search domain %s %s (generation= %llu)", scopeString
,
6409 resolver
->search
[j
], (interfaceId
== mDNSInterface_Any
) ? "" : interface_buf
, generation
);
6410 UpdateSearchDomainHash(m
, sdc
, resolver
->search
[j
], interfaceId
);
6411 mDNS_AddSearchDomain_CString(resolver
->search
[j
], interfaceId
);
6415 LogInfo("ConfigSearchDomains: An invalid search domain was detected for %s domain %s n_nameserver %d, (generation= %llu)",
6416 DNSScopeToString(scope
), resolver
->domain
, resolver
->n_nameserver
, generation
);
6422 LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString
, InterfaceNameForID(m
,interfaceId
));
6426 mDNSlocal mDNSInterfaceID
ConfigParseInterfaceID(mDNS
*const m
, mDNSu32 ifindex
)
6428 NetworkInterfaceInfoOSX
*ni
;
6429 mDNSInterfaceID interface
;
6431 for (ni
= m
->p
->InterfaceList
; ni
; ni
= ni
->next
)
6433 if (ni
->ifinfo
.InterfaceID
&& ni
->scope_id
== ifindex
)
6438 interface
= ni
->ifinfo
.InterfaceID
;
6442 // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
6443 // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
6444 // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
6445 // As the caller is going to ack the configuration always, we have to add all the DNS servers
6446 // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
6448 LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex
);
6450 // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
6451 interface
= (mDNSInterfaceID
)(unsigned long)ifindex
;
6456 mDNSlocal
void ConfigNonUnicastResolver(mDNS
*const m
, dns_resolver_t
*r
)
6458 char *opt
= r
->options
;
6461 if (opt
&& !strncmp(opt
, "mdns", strlen(opt
)))
6463 if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
))
6465 LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r
->domain
);
6468 mDNS_AddMcastResolver(m
, &d
, mDNSInterface_Any
, r
->timeout
);
6472 mDNSlocal
void ConfigDNSServers(mDNS
*const m
, dns_resolver_t
*r
, mDNSInterfaceID interface
, mDNSu32 scope
, mDNSu16 resGroupID
)
6477 mDNSBool cellIntf
= mDNSfalse
;
6478 mDNSBool reqA
, reqAAAA
;
6480 if (!r
->domain
|| !*r
->domain
)
6484 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
))
6486 LogMsg("ConfigDNSServers: bad domain %s", r
->domain
);
6489 // Parse the resolver specific attributes that affects all the DNS servers.
6490 if (scope
== kScopeServiceID
)
6492 serviceID
= r
->service_identifier
;
6495 #if TARGET_OS_IPHONE
6496 cellIntf
= (r
->reach_flags
& kSCNetworkReachabilityFlagsIsWWAN
) ? mDNStrue
: mDNSfalse
;
6498 reqA
= (r
->flags
& DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
? mDNStrue
: mDNSfalse
);
6499 reqAAAA
= (r
->flags
& DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
? mDNStrue
: mDNSfalse
);
6501 for (n
= 0; n
< r
->n_nameserver
; n
++)
6506 if (r
->nameserver
[n
]->sa_family
!= AF_INET
&& r
->nameserver
[n
]->sa_family
!= AF_INET6
)
6509 if (SetupAddr(&saddr
, r
->nameserver
[n
]))
6511 LogMsg("ConfigDNSServers: Bad address");
6515 // The timeout value is for all the DNS servers in a given resolver, hence we pass
6516 // the timeout value only for the first DNSServer. If we don't have a value in the
6517 // resolver, then use the core's default value
6519 // Note: this assumes that when the core picks a list of DNSServers for a question,
6520 // it takes the sum of all the timeout values for all DNS servers. By doing this, it
6521 // tries all the DNS servers in a specified timeout
6522 s
= mDNS_AddDNSServer(m
, &d
, interface
, serviceID
, &saddr
, r
->port
? mDNSOpaque16fromIntVal(r
->port
) : UnicastDNSPort
, scope
,
6523 (n
== 0 ? (r
->timeout
? r
->timeout
: DEFAULT_UDNS_TIMEOUT
) : 0), cellIntf
, resGroupID
, reqA
, reqAAAA
, mDNStrue
);
6526 LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope
), &s
->addr
, mDNSVal16(s
->port
), d
.c
);
6531 // ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
6532 // Service scope resolvers. This is indicated by the scope argument.
6534 // "resolver" has entries that should only be used for unscoped questions.
6536 // "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
6537 // interface index (q->InterfaceID)
6539 // "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
6540 // a service identifier (q->ServiceID)
6542 mDNSlocal
void ConfigResolvers(mDNS
*const m
, dns_config_t
*config
, mDNSu32 scope
, mDNSBool setsearch
, mDNSBool setservers
, MD5_CTX
*sdc
, mDNSu16 resGroupID
)
6545 dns_resolver_t
**resolver
;
6547 const char *scopeString
= DNSScopeToString(scope
);
6548 mDNSInterfaceID interface
;
6553 resolver
= config
->resolver
;
6554 nresolvers
= config
->n_resolver
;
6556 case kScopeInterfaceID
:
6557 resolver
= config
->scoped_resolver
;
6558 nresolvers
= config
->n_scoped_resolver
;
6560 case kScopeServiceID
:
6561 resolver
= config
->service_specific_resolver
;
6562 nresolvers
= config
->n_service_specific_resolver
;
6567 qsort(resolver
, nresolvers
, sizeof(dns_resolver_t
*), compare_dns_configs
);
6569 for (i
= 0; i
< nresolvers
; i
++)
6571 dns_resolver_t
*r
= resolver
[i
];
6573 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString
, i
, r
->domain
, r
->n_nameserver
);
6575 interface
= mDNSInterface_Any
;
6577 // Parse the interface index
6578 if (r
->if_index
!= 0)
6580 interface
= ConfigParseInterfaceID(m
, r
->if_index
);
6585 ConfigSearchDomains(m
, resolver
[i
], interface
, scope
, sdc
, config
->generation
);
6587 // Parse other scoped resolvers for search lists
6592 if (r
->port
== 5353 || r
->n_nameserver
== 0)
6594 ConfigNonUnicastResolver(m
, r
);
6598 // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the
6599 // scoped resolver are not used by other non-scoped or scoped resolvers.
6600 if (scope
!= kScopeNone
)
6603 ConfigDNSServers(m
, r
, interface
, scope
, resGroupID
);
6608 #if APPLE_OSX_mDNSResponder
6609 mDNSlocal mDNSBool
QuestionValidForDNSTrigger(DNSQuestion
*q
)
6611 if (QuerySuppressed(q
))
6613 debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
6616 if (mDNSOpaque16IsZero(q
->TargetQID
))
6618 debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
6621 // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
6623 if (q
->LOAddressAnswers
)
6625 debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
6632 // This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
6633 // We set our state appropriately so that if we start receiving answers, trigger the
6634 // upper layer to retry DNS questions.
6635 #if APPLE_OSX_mDNSResponder
6636 mDNSexport
void mDNSPlatformUpdateDNSStatus(mDNS
*const m
, DNSQuestion
*q
)
6638 if (!QuestionValidForDNSTrigger(q
))
6641 // Ignore applications that start and stop queries for no reason before we ever talk
6642 // to any DNS server.
6643 if (!q
->triedAllServersOnce
)
6645 LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q
->qname
.c
, DNSTypeName(q
->qtype
));
6648 if (q
->qtype
== kDNSType_A
)
6649 m
->p
->v4answers
= 0;
6650 if (q
->qtype
== kDNSType_AAAA
)
6651 m
->p
->v6answers
= 0;
6652 if (!m
->p
->v4answers
|| !m
->p
->v6answers
)
6654 LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, quesiton %##s (%s)", m
->p
->v4answers
, m
->p
->v6answers
, q
->qname
.c
,
6655 DNSTypeName(q
->qtype
));
6660 mDNSlocal
void AckConfigd(mDNS
*const m
, dns_config_t
*config
)
6664 // Acking the configuration triggers configd to reissue the reachability queries
6665 m
->p
->DNSTrigger
= NonZeroTime(m
->timenow
);
6666 _dns_configuration_ack(config
, "com.apple.mDNSResponder");
6669 // If v4q is non-NULL, it means we have received some answers for "A" type questions
6670 // If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
6671 #if APPLE_OSX_mDNSResponder
6672 mDNSexport
void mDNSPlatformTriggerDNSRetry(mDNS
*const m
, DNSQuestion
*v4q
, DNSQuestion
*v6q
)
6674 mDNSBool trigger
= mDNSfalse
;
6677 // Don't send triggers too often.
6678 // If we have started delivering answers to questions, we should send a trigger
6679 // if the time permits. If we are delivering answers, we should set the state
6680 // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know
6681 // whether the answers that are being delivered currently is for configd or some
6682 // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
6683 // then we won't deliver the trigger later when it is okay to send one as the
6684 // "answers" are already set to 1. Hence, don't affect the state of v4answers and
6685 // v6answers if we are not delivering triggers.
6687 timenow
= m
->timenow
;
6688 if (m
->p
->DNSTrigger
&& (timenow
- m
->p
->DNSTrigger
) < DNS_TRIGGER_INTERVAL
)
6690 if (!m
->p
->v4answers
|| !m
->p
->v6answers
)
6692 debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
6693 (timenow
- m
->p
->DNSTrigger
), m
->p
->v4answers
, m
->p
->v6answers
);
6699 if (v4q
!= NULL
&& QuestionValidForDNSTrigger(v4q
))
6701 int old
= m
->p
->v4answers
;
6703 m
->p
->v4answers
= 1;
6705 // If there are IPv4 answers now and previously we did not have
6706 // any answers, trigger a DNS change so that reachability
6707 // can retry the queries again.
6710 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow
- m
->p
->DNSTrigger
),
6711 v4q
->qname
.c
, DNSTypeName(v4q
->qtype
));
6715 if (v6q
!= NULL
&& QuestionValidForDNSTrigger(v6q
))
6717 int old
= m
->p
->v6answers
;
6719 m
->p
->v6answers
= 1;
6720 // If there are IPv6 answers now and previously we did not have
6721 // any answers, trigger a DNS change so that reachability
6722 // can retry the queries again.
6725 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow
- m
->p
->DNSTrigger
),
6726 v6q
->qname
.c
, DNSTypeName(v6q
->qtype
));
6732 dns_config_t
*config
= dns_configuration_copy();
6736 AckConfigd(m
, config
);
6738 dns_configuration_free(config
);
6742 LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
6747 mDNSlocal
void SetupActiveDirectoryDomain(dns_config_t
*config
)
6749 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
6750 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
6751 if (config
->n_resolver
&& config
->resolver
[0]->domain
&& config
->resolver
[0]->n_nameserver
&&
6752 config
->resolver
[0]->nameserver
[0])
6754 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain
, config
->resolver
[0]->domain
);
6758 ActiveDirectoryPrimaryDomain
.c
[0] = 0;
6761 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
6762 ActiveDirectoryPrimaryDomainLabelCount
= CountLabels(&ActiveDirectoryPrimaryDomain
);
6763 if (config
->n_resolver
&& config
->resolver
[0]->n_nameserver
&&
6764 SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain
, ActiveDirectoryPrimaryDomainLabelCount
- 1), &localdomain
))
6766 SetupAddr(&ActiveDirectoryPrimaryDomainServer
, config
->resolver
[0]->nameserver
[0]);
6770 AssignDomainName(&ActiveDirectoryPrimaryDomain
, (const domainname
*)"");
6771 ActiveDirectoryPrimaryDomainLabelCount
= 0;
6772 ActiveDirectoryPrimaryDomainServer
= zeroAddr
;
6777 mDNSlocal
void SetupDDNSDomains(domainname
*const fqdn
, DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
)
6780 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NULL
6783 CFDictionaryRef ddnsdict
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_DynamicDNS
);
6788 CFArrayRef fqdnArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("HostNames"));
6789 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
6791 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
6792 CFDictionaryRef fqdnDict
= CFArrayGetValueAtIndex(fqdnArray
, 0);
6793 if (fqdnDict
&& DictionaryIsEnabled(fqdnDict
))
6795 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
6798 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
6799 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
6800 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
6802 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
6809 CFArrayRef regArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("RegistrationDomains"));
6810 if (regArray
&& CFArrayGetCount(regArray
) > 0)
6812 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
6813 if (regDict
&& DictionaryIsEnabled(regDict
))
6815 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
6818 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
6819 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
6820 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
6823 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf
);
6824 AppendDNameListElem(&RegDomains
, 0, &d
);
6832 CFArrayRef browseArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("BrowseDomains"));
6835 for (i
= 0; i
< CFArrayGetCount(browseArray
); i
++)
6837 CFDictionaryRef browseDict
= CFArrayGetValueAtIndex(browseArray
, i
);
6838 if (browseDict
&& DictionaryIsEnabled(browseDict
))
6840 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
6843 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
6844 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
6845 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf
[0] ? buf
: "(unknown)");
6848 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf
);
6849 AppendDNameListElem(&BrowseDomains
, 0, &d
);
6856 CFRelease(ddnsdict
);
6860 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_BackToMyMac
);
6863 CFIndex size
= CFDictionaryGetCount(btmm
);
6864 const void *key
[size
];
6865 const void *val
[size
];
6866 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
6867 for (i
= 0; i
< size
; i
++)
6869 LogInfo("BackToMyMac %d", i
);
6870 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
6871 LogMsg("Can't read BackToMyMac %d key %s", i
, buf
);
6874 mDNSu32 uid
= atoi(buf
);
6875 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
6876 LogMsg("Can't read BackToMyMac %d val %s", i
, buf
);
6877 else if (MakeDomainNameFromDNSNameString(&d
, buf
) && d
.c
[0])
6879 LogInfo("BackToMyMac %d %d %##s", i
, uid
, d
.c
);
6880 AppendDNameListElem(&RegDomains
, uid
, &d
);
6890 // Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
6891 mDNSexport mDNSBool
mDNSPlatformSetDNSConfig(mDNS
*const m
, mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
,
6892 DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
, mDNSBool ackConfig
)
6894 MD5_CTX sdc
; // search domain context
6895 static mDNSu16 resolverGroupID
= 0;
6897 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
6898 if (fqdn
) fqdn
->c
[0] = 0;
6899 if (RegDomains
) *RegDomains
= NULL
;
6900 if (BrowseDomains
) *BrowseDomains
= NULL
;
6902 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
6903 setservers
? " setservers" : "",
6904 setsearch
? " setsearch" : "",
6905 fqdn
? " fqdn" : "",
6906 RegDomains
? " RegDomains" : "",
6907 BrowseDomains
? " BrowseDomains" : "");
6909 if (setsearch
) MD5_Init(&sdc
);
6911 // Add the inferred address-based configuration discovery domains
6912 // (should really be in core code I think, not platform-specific)
6915 struct ifaddrs
*ifa
= mDNSNULL
;
6916 struct sockaddr_in saddr
;
6917 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
6918 saddr
.sin_len
= sizeof(saddr
);
6919 saddr
.sin_family
= AF_INET
;
6921 saddr
.sin_addr
.s_addr
= *(in_addr_t
*)&m
->Router
.ip
.v4
;
6923 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
6924 if (!AddrRequiresPPPConnection((struct sockaddr
*)&saddr
)) ifa
= myGetIfAddrs(1);
6931 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
6933 !(ifa
->ifa_flags
& IFF_LOOPBACK
) &&
6934 !SetupAddr(&a
, ifa
->ifa_addr
) &&
6935 !mDNSv4AddressIsLinkLocal(&a
.ip
.v4
) )
6937 // 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
6938 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
6939 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
; // Make sure ifa_netmask->sa_family is set correctly
6940 SetupAddr(&n
, ifa
->ifa_netmask
);
6941 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
6942 mDNS_snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d.in-addr.arpa.", a
.ip
.v4
.b
[3] & n
.ip
.v4
.b
[3],
6943 a
.ip
.v4
.b
[2] & n
.ip
.v4
.b
[2],
6944 a
.ip
.v4
.b
[1] & n
.ip
.v4
.b
[1],
6945 a
.ip
.v4
.b
[0] & n
.ip
.v4
.b
[0]);
6946 UpdateSearchDomainHash(m
, &sdc
, buf
, NULL
);
6947 mDNS_AddSearchDomain_CString(buf
, mDNSNULL
);
6949 ifa
= ifa
->ifa_next
;
6953 #ifndef MDNS_NO_DNSINFO
6954 if (setservers
|| setsearch
)
6956 dns_config_t
*config
= dns_configuration_copy();
6959 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
6960 // Apparently this is expected behaviour -- "not a bug".
6961 // Accordingly, we suppress syslog messages for the first three minutes after boot.
6962 // If we are still getting failures after three minutes, then we log them.
6963 if ((mDNSu32
)mDNSPlatformRawTime() > (mDNSu32
)(mDNSPlatformOneSecond
* 180))
6964 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
6968 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config
->n_resolver
, config
->generation
, m
->p
->LastConfigGeneration
);
6969 if (m
->p
->LastConfigGeneration
== config
->generation
)
6971 LogInfo("mDNSPlatformSetDNSConfig: generation number %llu same, not processing", config
->generation
);
6972 dns_configuration_free(config
);
6973 SetupDDNSDomains(fqdn
, RegDomains
, BrowseDomains
);
6976 #if APPLE_OSX_mDNSResponder
6977 SetupActiveDirectoryDomain(config
);
6980 // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry
6981 // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need
6982 // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between
6983 // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the
6984 // same resolverGroupID.
6986 // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally.
6987 ConfigResolvers(m
, config
, kScopeNone
, setsearch
, setservers
, &sdc
, ++resolverGroupID
);
6988 resolverGroupID
+= config
->n_resolver
;
6990 ConfigResolvers(m
, config
, kScopeInterfaceID
, setsearch
, setservers
, &sdc
, resolverGroupID
);
6991 resolverGroupID
+= config
->n_scoped_resolver
;
6993 ConfigResolvers(m
, config
, kScopeServiceID
, setsearch
, setservers
, &sdc
, resolverGroupID
);
6995 // Acking provides a hint that we processed this current configuration and
6996 // we will use that from now on, assuming we don't get another one immediately
6997 // after we return from here.
7000 // Note: We have to set the generation number here when we are acking.
7001 // For every DNS configuration change, we do the following:
7003 // 1) Copy dns configuration, handle search domains change
7004 // 2) Copy dns configuration, handle dns server change
7006 // If we update the generation number at step (1), we won't process the
7007 // DNS servers the second time because generation number would be the same.
7008 // As we ack only when we process dns servers, we set the generation number
7010 m
->p
->LastConfigGeneration
= config
->generation
;
7011 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers
, setsearch
);
7012 AckConfigd(m
, config
);
7014 dns_configuration_free(config
);
7015 if (setsearch
) FinalizeSearchDomainHash(m
, &sdc
);
7018 #endif // MDNS_NO_DNSINFO
7019 SetupDDNSDomains(fqdn
, RegDomains
, BrowseDomains
);
7024 mDNSexport mStatus
mDNSPlatformGetPrimaryInterface(mDNS
*const m
, mDNSAddr
*v4
, mDNSAddr
*v6
, mDNSAddr
*r
)
7029 CFDictionaryRef dict
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_IPv4
);
7032 r
->type
= mDNSAddrType_IPv4
;
7033 r
->ip
.v4
= zerov4Addr
;
7034 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
7037 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
7038 LogMsg("Could not convert router to CString");
7041 struct sockaddr_in saddr
;
7042 saddr
.sin_len
= sizeof(saddr
);
7043 saddr
.sin_family
= AF_INET
;
7045 inet_aton(buf
, &saddr
.sin_addr
);
7046 *(in_addr_t
*)&r
->ip
.v4
= saddr
.sin_addr
.s_addr
;
7049 string
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
7052 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
7053 struct ifaddrs
*ifa
= myGetIfAddrs(1);
7054 *v4
= *v6
= zeroAddr
;
7056 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
7058 LogMsg("Could not convert router to CString");
7061 // find primary interface in list
7062 while (ifa
&& (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
) || !HavePrimaryGlobalv6
))
7064 mDNSAddr tmp6
= zeroAddr
;
7065 if (!strcmp(buf
, ifa
->ifa_name
))
7067 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
7069 if (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
))
7070 SetupAddr(v4
, ifa
->ifa_addr
);
7072 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
7074 SetupAddr(&tmp6
, ifa
->ifa_addr
);
7075 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
7077 HavePrimaryGlobalv6
= mDNStrue
;
7084 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
7085 if (!HavePrimaryGlobalv6
&& ifa
->ifa_addr
->sa_family
== AF_INET6
&& !v6
->ip
.v6
.b
[0])
7087 SetupAddr(&tmp6
, ifa
->ifa_addr
);
7088 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1)
7092 ifa
= ifa
->ifa_next
;
7094 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
7095 // V4 to communicate w/ our DNS server
7101 return mStatus_NoError
;
7104 mDNSexport
void mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
7106 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status
, dname
->c
);
7107 char uname
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
7108 ConvertDomainNameToCString(dname
, uname
);
7114 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
7118 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
7119 // That single entity is a CFDictionary with name "HostNames".
7120 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
7121 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
7122 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
7123 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
7124 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
7126 const CFStringRef StateKeys
[1] = { CFSTR("HostNames") };
7127 const CFStringRef HostKeys
[1] = { CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
) };
7128 const CFStringRef StatusKeys
[1] = { CFSTR("Status") };
7129 if (!HostKeys
[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname
);
7132 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
7133 if (!StatusVals
[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status
);
7136 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
7139 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
7142 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
7145 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig
, mDNSNULL
, StateDict
);
7146 CFRelease(StateDict
);
7148 CFRelease(StateVals
[0]);
7150 CFRelease(HostVals
[0]);
7152 CFRelease(StatusVals
[0]);
7154 CFRelease(HostKeys
[0]);
7158 #if APPLE_OSX_mDNSResponder
7161 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
7162 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
7164 mDNSlocal mDNSBool
IsBTMMDomain(domainname
*d
)
7166 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:IsBTMMDomain"), NULL
, NULL
);
7169 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
7172 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BackToMyMac
);
7175 CFIndex size
= CFDictionaryGetCount(btmm
);
7176 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
7177 const void *key
[size
];
7178 const void *val
[size
];
7181 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
7182 for (i
= 0; i
< size
; i
++)
7184 LogInfo("BackToMyMac %d", i
);
7185 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
7186 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i
, buf
);
7189 mDNSu32 uid
= atoi(buf
);
7190 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
7191 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i
, buf
);
7192 else if (MakeDomainNameFromDNSNameString(&dom
, buf
) && dom
.c
[0])
7194 if (SameDomainName(&dom
, d
))
7196 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d
->c
, uid
);
7207 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d
->c
);
7211 // Appends data to the buffer
7212 mDNSlocal
int AddOneItem(char *buf
, int bufsz
, char *data
, int *currlen
)
7216 len
= strlcpy(buf
+ *currlen
, data
, bufsz
- *currlen
);
7217 if (len
>= (bufsz
- *currlen
))
7219 // if we have exceeded the space in buf, it has already been NULL terminated
7220 // and we have nothing more to do. Set currlen to the last byte so that the caller
7221 // knows to do the right thing
7222 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen
, len
);
7223 *currlen
= bufsz
- 1;
7226 else { (*currlen
) += len
; }
7228 buf
[*currlen
] = ',';
7229 if (*currlen
>= bufsz
)
7231 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen
);
7232 *currlen
= bufsz
- 1;
7236 // if we have filled up the buffer exactly, then there is no more work to do
7237 if (*currlen
== bufsz
- 1) { buf
[*currlen
] = 0; return -1; }
7242 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
7243 // BTMM domains, then bring down the connection to the relay.
7244 mDNSlocal
void UpdateBTMMRelayConnection(mDNS
*const m
)
7246 DomainAuthInfo
*BTMMDomain
= mDNSNULL
;
7247 DomainAuthInfo
*FoundInList
;
7248 static mDNSBool AWACSDConnected
= mDNSfalse
;
7249 char AllUsers
[1024]; // maximum size of mach message
7250 char AllPass
[1024]; // maximum size of mach message
7251 char username
[MAX_DOMAIN_LABEL
+ 1];
7255 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
7256 // we may not be able to send the dns queries over the relay connection which may be needed
7257 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
7258 // need to make sure that we send the disconnect before attempting the next connect as the
7259 // awacs connections are redirected based on usernames.
7261 // For now we send a disconnect immediately. When we start sending dns queries over the relay
7262 // connection, we will need to fix this.
7264 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
7265 if (!FoundInList
->deltime
&& FoundInList
->AutoTunnel
&& IsBTMMDomain(&FoundInList
->domain
))
7267 // We need the passwd from the first domain.
7268 BTMMDomain
= FoundInList
;
7269 ConvertDomainLabelToCString_unescaped((domainlabel
*)BTMMDomain
->domain
.c
, username
);
7270 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username
, BTMMDomain
->domain
.c
);
7271 if (AddOneItem(AllUsers
, sizeof(AllUsers
), username
, &currulen
) == -1) break;
7272 if (AddOneItem(AllPass
, sizeof(AllPass
), BTMMDomain
->b64keydata
, &currplen
) == -1) break;
7277 // In the normal case (where we neither exceed the buffer size nor write bytes that
7278 // fit exactly into the buffer), currulen/currplen should be a different size than
7279 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
7281 if (currulen
!= (int)(sizeof(AllUsers
) - 1)) AllUsers
[currulen
- 1] = 0;
7282 if (currplen
!= (int)(sizeof(AllPass
) - 1)) AllPass
[currplen
- 1] = 0;
7284 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers
);
7285 AWACS_Connect(AllUsers
, AllPass
, "hello.connectivity.me.com");
7286 AWACSDConnected
= mDNStrue
;
7290 // Disconnect only if we connected previously
7291 if (AWACSDConnected
)
7293 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
7295 AWACSDConnected
= mDNSfalse
;
7297 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
7300 #elif !TARGET_OS_EMBEDDED
7301 mDNSlocal
void UpdateBTMMRelayConnection(mDNS
*const m
)
7304 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
7306 #endif // ! NO_AWACS
7308 #if !TARGET_OS_EMBEDDED
7309 mDNSlocal
void ProcessConndConfigChanges(mDNS
*const m
);
7312 #endif // APPLE_OSX_mDNSResponder
7314 // MUST be called holding the lock
7315 mDNSlocal
void SetDomainSecrets_internal(mDNS
*m
)
7317 #ifdef NO_SECURITYFRAMEWORK
7319 LogMsg("Note: SetDomainSecrets: no keychain support");
7321 mDNSBool haveAutoTunnels
= mDNSfalse
;
7323 LogInfo("SetDomainSecrets");
7325 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
7326 // In the case where the user simultaneously removes their DDNS host name and the key
7327 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
7328 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
7329 // address records behind that we no longer have permission to delete.
7330 DomainAuthInfo
*ptr
;
7331 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
7332 ptr
->deltime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
*10);
7334 #if APPLE_OSX_mDNSResponder
7336 // Mark all TunnelClients for deletion
7337 ClientTunnel
*client
;
7338 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
7340 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client
->dstname
.c
);
7341 client
->MarkedForDeletion
= mDNStrue
;
7344 #endif // APPLE_OSX_mDNSResponder
7346 // String Array used to write list of private domains to Dynamic Store
7347 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
7348 if (!sa
) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
7350 CFDataRef data
= NULL
;
7351 const int itemsPerEntry
= 4; // domain name, key name, key value, Name value
7352 CFArrayRef secrets
= NULL
;
7353 int err
= mDNSKeychainGetSecrets(&secrets
);
7354 if (err
|| !secrets
)
7355 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err
, secrets
);
7358 CFIndex ArrayCount
= CFArrayGetCount(secrets
);
7359 // Iterate through the secrets
7360 for (i
= 0; i
< ArrayCount
; ++i
)
7362 mDNSBool AutoTunnel
;
7364 CFArrayRef entry
= CFArrayGetValueAtIndex(secrets
, i
);
7365 if (CFArrayGetTypeID() != CFGetTypeID(entry
) || itemsPerEntry
!= CFArrayGetCount(entry
))
7366 { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i
, itemsPerEntry
); continue; }
7367 for (j
= 0; j
< CFArrayGetCount(entry
); ++j
)
7368 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry
, j
)))
7369 { LogMsg("SetDomainSecrets: malformed entry item %d", j
); continue; }
7371 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
7373 // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
7374 // Get DNS domain this key is for (kmDNSKcWhere)
7375 char stringbuf
[MAX_ESCAPED_DOMAIN_NAME
+ sizeof(btmmprefix
)];
7376 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcWhere
);
7377 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
7378 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data
)); continue; }
7379 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
7380 stringbuf
[CFDataGetLength(data
)] = '\0';
7382 AutoTunnel
= mDNSfalse
;
7384 if (!strncmp(stringbuf
, dnsprefix
, strlen(dnsprefix
)))
7385 offset
= strlen(dnsprefix
);
7386 else if (!strncmp(stringbuf
, btmmprefix
, strlen(btmmprefix
)))
7388 AutoTunnel
= mDNStrue
;
7389 offset
= strlen(btmmprefix
);
7392 if (!MakeDomainNameFromDNSNameString(&domain
, stringbuf
+ offset
)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf
); continue; }
7394 // Get key name (kmDNSKcAccount)
7395 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcAccount
);
7396 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
7397 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data
)); continue; }
7398 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)stringbuf
);
7399 stringbuf
[CFDataGetLength(data
)] = '\0';
7402 if (!MakeDomainNameFromDNSNameString(&keyname
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf
); continue; }
7404 // Get key data (kmDNSKcKey)
7405 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcKey
);
7406 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
7408 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data
));
7411 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
7412 stringbuf
[CFDataGetLength(data
)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
7414 // Get the Name of the keychain entry (kmDNSKcName) host or host:port
7415 // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
7416 char hostbuf
[MAX_ESCAPED_DOMAIN_NAME
+ 6]; // Max legal domainname as C-string, including terminating NUL
7417 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcName
);
7418 if (CFDataGetLength(data
) >= (int)sizeof(hostbuf
))
7420 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data
));
7423 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)hostbuf
);
7424 hostbuf
[CFDataGetLength(data
)] = '\0';
7426 domainname hostname
;
7429 hptr
= strchr(hostbuf
, ':');
7431 port
.NotAnInteger
= 0;
7438 while(hptr
&& *hptr
!= 0)
7440 if (*hptr
< '0' || *hptr
> '9')
7441 { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr
, val
); val
= 0; break;}
7442 val
= val
* 10 + *hptr
- '0';
7447 port
.NotAnInteger
= p
[0] << 8 | p
[1];
7449 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
7450 hptr
= strchr(hostbuf
, '@');
7455 if (!MakeDomainNameFromDNSNameString(&hostname
, hptr
)) { LogMsg("SetDomainSecrets: bad host name %s", hptr
); continue; }
7457 DomainAuthInfo
*FoundInList
;
7458 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
7459 if (SameDomainName(&FoundInList
->domain
, &domain
)) break;
7461 #if APPLE_OSX_mDNSResponder
7464 // If any client tunnel destination is in this domain, set deletion flag to false
7465 ClientTunnel
*client
;
7466 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
7467 if (FoundInList
== GetAuthInfoForName_internal(m
, &client
->dstname
))
7469 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client
->dstname
.c
);
7470 client
->MarkedForDeletion
= mDNSfalse
;
7474 #endif // APPLE_OSX_mDNSResponder
7476 // Uncomment the line below to view the keys as they're read out of the system keychain
7477 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
7478 //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]));
7479 LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain
.c
, &keyname
.c
, hostname
.c
, (port
.b
[0] << 8 | port
.b
[1]));
7481 // If didn't find desired domain in the list, make a new entry
7483 if (FoundInList
&& FoundInList
->AutoTunnel
&& haveAutoTunnels
== mDNSfalse
) haveAutoTunnels
= mDNStrue
;
7486 ptr
= (DomainAuthInfo
*)mallocL("DomainAuthInfo", sizeof(*ptr
));
7487 if (!ptr
) { LogMsg("SetDomainSecrets: No memory"); continue; }
7490 //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
7492 // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
7493 if (mDNS_SetSecretForDomain(m
, ptr
, &domain
, &keyname
, stringbuf
, &hostname
, &port
, AutoTunnel
) == mStatus_BadParamErr
)
7495 if (!FoundInList
) mDNSPlatformMemFree(ptr
); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
7499 ConvertDomainNameToCString(&domain
, stringbuf
);
7500 CFStringRef cfs
= CFStringCreateWithCString(NULL
, stringbuf
, kCFStringEncodingUTF8
);
7501 if (cfs
) { CFArrayAppendValue(sa
, cfs
); CFRelease(cfs
); }
7506 if (!privateDnsArray
|| !CFEqual(privateDnsArray
, sa
))
7508 if (privateDnsArray
)
7509 CFRelease(privateDnsArray
);
7511 privateDnsArray
= sa
;
7512 CFRetain(privateDnsArray
);
7513 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, mDNSNULL
, privateDnsArray
);
7517 #if APPLE_OSX_mDNSResponder
7519 // clean up ClientTunnels
7520 ClientTunnel
**pp
= &m
->TunnelClients
;
7523 if ((*pp
)->MarkedForDeletion
)
7525 ClientTunnel
*cur
= *pp
;
7526 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur
, cur
->dstname
.c
);
7527 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
7528 AutoTunnelSetKeys(cur
, mDNSfalse
);
7530 freeL("ClientTunnel", cur
);
7536 mDNSBool needAutoTunnelNAT
= mDNSfalse
;
7537 DomainAuthInfo
*info
;
7538 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
7540 if (info
->AutoTunnel
)
7542 UpdateAutoTunnelDeviceInfoRecord(m
, info
);
7543 UpdateAutoTunnelHostRecord(m
, info
);
7544 UpdateAutoTunnelServiceRecords(m
, info
);
7545 UpdateAutoTunnel6Record(m
, info
);
7548 if (info
->AutoTunnelServiceStarted
) info
->AutoTunnelServiceStarted
= mDNSfalse
;
7550 else if (info
->AutoTunnelServiceStarted
)
7551 needAutoTunnelNAT
= true;
7553 UpdateAutoTunnelDomainStatus(m
, info
);
7557 // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
7558 if (!needAutoTunnelNAT
&& m
->AutoTunnelNAT
.clientContext
)
7560 // stop the NAT operation, reset port, cleanup state
7561 mDNS_StopNATOperation_internal(m
, &m
->AutoTunnelNAT
);
7562 m
->AutoTunnelNAT
.ExternalAddress
= zerov4Addr
;
7563 m
->AutoTunnelNAT
.NewAddress
= zerov4Addr
;
7564 m
->AutoTunnelNAT
.ExternalPort
= zeroIPPort
;
7565 m
->AutoTunnelNAT
.RequestedPort
= zeroIPPort
;
7566 m
->AutoTunnelNAT
.Lifetime
= 0;
7567 m
->AutoTunnelNAT
.Result
= mStatus_NoError
;
7568 m
->AutoTunnelNAT
.clientContext
= mDNSNULL
;
7571 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
7572 ProcessConndConfigChanges(m
); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
7574 #endif // APPLE_OSX_mDNSResponder
7576 CheckSuppressUnusableQuestions(m
);
7578 #endif /* NO_SECURITYFRAMEWORK */
7581 mDNSexport
void SetDomainSecrets(mDNS
*m
)
7584 // Don't get secrets for BTMM if running in debug mode
7585 if (!IsDebugSocketInUse())
7587 SetDomainSecrets_internal(m
);
7590 mDNSlocal
void SetLocalDomains(void)
7592 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
7593 if (!sa
) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
7595 CFArrayAppendValue(sa
, CFSTR("local"));
7596 CFArrayAppendValue(sa
, CFSTR("254.169.in-addr.arpa"));
7597 CFArrayAppendValue(sa
, CFSTR("8.e.f.ip6.arpa"));
7598 CFArrayAppendValue(sa
, CFSTR("9.e.f.ip6.arpa"));
7599 CFArrayAppendValue(sa
, CFSTR("a.e.f.ip6.arpa"));
7600 CFArrayAppendValue(sa
, CFSTR("b.e.f.ip6.arpa"));
7602 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig
, mDNSNULL
, sa
);
7606 mDNSlocal
void GetCurrentPMSetting(const CFStringRef name
, mDNSs32
*val
)
7609 CFDictionaryRef dict
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_PowerSettings
);
7612 LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
7616 CFNumberRef number
= CFDictionaryGetValue(dict
, name
);
7617 if (!number
|| CFGetTypeID(number
) != CFNumberGetTypeID() || !CFNumberGetValue(number
, kCFNumberSInt32Type
, val
))
7624 #if APPLE_OSX_mDNSResponder
7626 static CFMutableDictionaryRef spsStatusDict
= NULL
;
7627 static const CFStringRef kMetricRef
= CFSTR("Metric");
7629 mDNSlocal
void SPSStatusPutNumber(CFMutableDictionaryRef dict
, const mDNSu8
* const ptr
, CFStringRef key
)
7631 mDNSu8 tmp
= (ptr
[0] - '0') * 10 + ptr
[1] - '0';
7632 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt8Type
, &tmp
);
7634 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
7637 CFDictionarySetValue(dict
, key
, num
);
7642 mDNSlocal CFMutableDictionaryRef
SPSCreateDict(const mDNSu8
* const ptr
)
7644 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
7645 if (!dict
) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict
; }
7648 buffer
[mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", ptr
) - 1] = 0;
7649 CFStringRef spsname
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
7650 if (!spsname
) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict
); return NULL
; }
7651 CFDictionarySetValue(dict
, CFSTR("FullName"), spsname
);
7654 if (ptr
[0] >= 2) SPSStatusPutNumber(dict
, ptr
+ 1, CFSTR("Type"));
7655 if (ptr
[0] >= 5) SPSStatusPutNumber(dict
, ptr
+ 4, CFSTR("Portability"));
7656 if (ptr
[0] >= 8) SPSStatusPutNumber(dict
, ptr
+ 7, CFSTR("MarginalPower"));
7657 if (ptr
[0] >= 11) SPSStatusPutNumber(dict
, ptr
+10, CFSTR("TotalPower"));
7659 mDNSu32 tmp
= SPSMetric(ptr
);
7660 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tmp
);
7662 LogMsg("SPSCreateDict: Could not create CFNumber");
7665 CFDictionarySetValue(dict
, kMetricRef
, num
);
7671 memcpy(buffer
, ptr
+ 13, ptr
[0] - 12);
7672 buffer
[ptr
[0] - 12] = 0;
7673 spsname
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
7674 if (!spsname
) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict
); return NULL
; }
7677 CFDictionarySetValue(dict
, CFSTR("PrettyName"), spsname
);
7685 mDNSlocal CFComparisonResult
CompareSPSEntries(const void *val1
, const void *val2
, void *context
)
7688 return CFNumberCompare((CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val1
, kMetricRef
),
7689 (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val2
, kMetricRef
),
7693 mDNSlocal
void UpdateSPSStatus(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
7695 NetworkInterfaceInfo
* info
= (NetworkInterfaceInfo
*)question
->QuestionContext
;
7696 debugf("UpdateSPSStatus: %s %##s %s %s", info
->ifname
, question
->qname
.c
, AddRecord
? "Add" : "Rmv", answer
? RRDisplayString(m
, answer
) : "<null>");
7699 mDNS_UpdateAllowSleep(m
);
7702 if (answer
&& SPSMetric(answer
->rdata
->u
.name
.c
) > 999999) return; // Ignore instances with invalid names
7706 spsStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
7707 if (!spsStatusDict
) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
7710 CFStringRef ifname
= CFStringCreateWithCString(NULL
, info
->ifname
, kCFStringEncodingUTF8
);
7711 if (!ifname
) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
7713 CFMutableArrayRef array
= NULL
;
7715 if (!CFDictionaryGetValueIfPresent(spsStatusDict
, ifname
, (const void**) &array
))
7717 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
7718 if (!array
) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname
); return; }
7719 CFDictionarySetValue(spsStatusDict
, ifname
, array
);
7720 CFRelease(array
); // let go of our reference, now that the dict has one
7723 if (!array
) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info
->ifname
); CFRelease(ifname
); return; }
7725 if (!answer
) // special call that means the question has been stopped (because the interface is going away)
7726 CFArrayRemoveAllValues(array
);
7729 CFMutableDictionaryRef dict
= SPSCreateDict(answer
->rdata
->u
.name
.c
);
7730 if (!dict
) { CFRelease(ifname
); return; }
7734 if (!CFArrayContainsValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), dict
))
7737 for (i
=0; i
<CFArrayGetCount(array
); i
++)
7738 if (CompareSPSEntries(CFArrayGetValueAtIndex(array
, i
), dict
, NULL
) != kCFCompareLessThan
)
7740 CFArrayInsertValueAtIndex(array
, i
, dict
);
7742 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info
->ifname
, answer
->rdata
->u
.name
.c
);
7746 CFIndex i
= CFArrayGetFirstIndexOfValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), dict
);
7747 if (i
!= -1) CFArrayRemoveValueAtIndex(array
, i
);
7748 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info
->ifname
, answer
->rdata
->u
.name
.c
);
7754 if (!m
->ShutdownTime
) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState
, info
->ifname
, array
);
7759 #if !TARGET_OS_EMBEDDED
7760 mDNSlocal mDNSs32
GetSystemSleepTimerSetting(void)
7763 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL
, NULL
);
7765 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
7768 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_PowerSettings
);
7771 CFNumberRef number
= CFDictionaryGetValue(dict
, CFSTR("System Sleep Timer"));
7772 if (number
) CFNumberGetValue(number
, kCFNumberSInt32Type
, &val
);
7780 mDNSlocal
void SetSPS(mDNS
*const m
)
7783 // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
7784 mDNSu8 sps
= (OfferSleepProxyService
&& GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware
: 0;
7786 // For devices that are not running NAT, but are set to never sleep, we may choose to act
7787 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
7788 //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
7790 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
7792 // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
7793 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
7794 // We rate such a device as metric 70 ("Incidentally Available Hardware")
7795 if (SPMetricMarginalPower
<= 60 && !sps
) sps
= mDNSSleepProxyMetric_IncidentalHardware
;
7797 // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
7798 // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
7799 if (sps
&& OfferSleepProxyService
&& OfferSleepProxyService
< 100) sps
= OfferSleepProxyService
;
7801 #ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI
7802 // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active.
7805 NetworkInterfaceInfo
*intf
= mDNSNULL
;
7806 mDNSEthAddr bssid
= zeroEthAddr
;
7807 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
7809 bssid
= GetBSSID(intf
->ifname
);
7810 if (!mDNSSameEthAddress(&bssid
, &zeroEthAddr
))
7812 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
7818 #endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI
7820 mDNSCoreBeSleepProxyServer(m
, sps
, SPMetricPortability
, SPMetricMarginalPower
, SPMetricTotalPower
, SPMetricFeatures
);
7822 #endif // !TARGET_OS_EMBEDDED
7824 // The definitions below should eventually come from some externally-supplied header file.
7825 // However, since these definitions can't really be changed without breaking binary compatibility,
7826 // they should never change, so in practice it should not be a big problem to have them defined here.
7829 { // commands from the daemon to the driver
7830 cmd_mDNSOffloadRR
= 21, // give the mdns update buffer to the driver
7833 typedef union { void *ptr
; mDNSOpaque64 sixtyfourbits
; } FatPtr
;
7836 { // cmd_mDNSOffloadRR structure
7837 uint32_t command
; // set to OffloadRR
7838 uint32_t rrBufferSize
; // number of bytes of RR records
7839 uint32_t numUDPPorts
; // number of SRV UDP ports
7840 uint32_t numTCPPorts
; // number of SRV TCP ports
7841 uint32_t numRRRecords
; // number of RR records
7842 uint32_t compression
; // rrRecords - compression is base for compressed strings
7843 FatPtr rrRecords
; // address of array of pointers to the rr records
7844 FatPtr udpPorts
; // address of udp port list (SRV)
7845 FatPtr tcpPorts
; // address of tcp port list (SRV)
7848 #include <IOKit/IOKitLib.h>
7849 #include <dns_util.h>
7851 mDNSlocal mDNSu16
GetPortArray(mDNS
*const m
, int trans
, mDNSIPPort
*portarray
)
7853 const domainlabel
*const tp
= (trans
== mDNSTransport_UDP
) ? (const domainlabel
*)"\x4_udp" : (const domainlabel
*)"\x4_tcp";
7857 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
7859 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainLabel(ThirdLabel(rr
->resrec
.name
)->c
, tp
->c
))
7866 for (i
= 0; i
< count
; i
++)
7867 if (mDNSSameIPPort(portarray
[i
], rr
->resrec
.rdata
->u
.srv
.port
))
7870 // Add it into the port list only if it not already present in the list
7872 portarray
[count
++] = rr
->resrec
.rdata
->u
.srv
.port
;
7877 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
7878 if (trans
== mDNSTransport_UDP
&& m
->AutoTunnelNAT
.clientContext
)
7880 LogSPS("GetPortArray Back to My Mac at %d", count
);
7881 if (portarray
) portarray
[count
] = IPSECPort
;
7887 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7888 mDNSlocal mDNSBool
SupportsTCPKeepAlive()
7890 IOReturn ret
= kIOReturnSuccess
;
7891 CFTypeRef obj
= NULL
;
7892 mDNSBool supports
= mDNSfalse
;
7894 ret
= IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj
);
7895 if ((kIOReturnSuccess
== ret
) && (obj
!= NULL
))
7897 supports
= (obj
== kCFBooleanTrue
)? mDNStrue
: mDNSfalse
;
7900 LogSPS("%s: The hardware %s TCP Keep Alive", __func__
, (supports
? "supports" : "does not support"));
7904 mDNSlocal mDNSBool
OnBattery(void)
7906 CFTypeRef powerInfo
= IOPSCopyPowerSourcesInfo();
7907 CFTypeRef powerSrc
= IOPSGetProvidingPowerSourceType(powerInfo
);
7908 mDNSBool result
= mDNSfalse
;
7910 if (powerInfo
!= NULL
)
7912 result
= CFEqual(CFSTR(kIOPSBatteryPowerValue
), powerSrc
);
7913 CFRelease(powerInfo
);
7915 LogSPS("%s: The system is on %s", __func__
, (result
)? "Battery" : "AC Power");
7919 #endif // !TARGET_OS_EMBEDDED
7921 #define TfrRecordToNIC(RR) \
7922 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
7924 mDNSlocal mDNSu32
CountProxyRecords(mDNS
*const m
, uint32_t *const numbytes
, NetworkInterfaceInfo
*const intf
, mDNSBool TCPKAOnly
, mDNSBool supportsTCPKA
)
7931 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
7933 if (!(rr
->AuthFlags
& AuthFlagsWakeOnly
) && rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
7935 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7936 mDNSBool isKeepAliveRecord
= mDNS_KeepaliveRecord(&rr
->resrec
);
7937 // Skip over all other records if we are registering TCP KeepAlive records only
7938 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
7939 if ((TCPKAOnly
&& !isKeepAliveRecord
) || (isKeepAliveRecord
&& !supportsTCPKA
))
7942 // Update the record before calculating the number of bytes required
7943 // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
7944 // attempt to update the record again.
7945 if (isKeepAliveRecord
&& (UpdateKeepaliveRData(m
, rr
, intf
, mDNSfalse
, mDNSNULL
) != mStatus_NoError
))
7946 LogSPS("CountProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m
, rr
));
7948 // Offload only Valid Keepalive records
7949 if (isKeepAliveRecord
&& !mDNSValidKeepAliveRecord(rr
))
7952 (void) TCPKAOnly
; // unused
7953 (void) supportsTCPKA
; // unused
7954 (void) intf
; // unused
7955 #endif // APPLE_OSX_mDNSResponder
7956 if (TfrRecordToNIC(rr
))
7958 *numbytes
+= DomainNameLength(rr
->resrec
.name
) + 10 + rr
->resrec
.rdestimate
;
7959 LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
7960 count
, DomainNameLength(rr
->resrec
.name
) + 10 + rr
->resrec
.rdestimate
, *numbytes
, ARDisplayString(m
,rr
));
7968 mDNSlocal
void GetProxyRecords(mDNS
*const m
, DNSMessage
*const msg
, uint32_t *const numbytes
, FatPtr
*const records
, mDNSBool TCPKAOnly
, mDNSBool supportsTCPKA
)
7970 mDNSu8
*p
= msg
->data
;
7971 const mDNSu8
*const limit
= p
+ *numbytes
;
7972 InitializeDNSMessage(&msg
->h
, zeroID
, zeroID
);
7977 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
7979 if (!(rr
->AuthFlags
& AuthFlagsWakeOnly
) && rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
7981 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7982 mDNSBool isKeepAliveRecord
= mDNS_KeepaliveRecord(&rr
->resrec
);
7984 // Skip over all other records if we are registering TCP KeepAlive records only
7985 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
7986 if ((TCPKAOnly
&& !isKeepAliveRecord
) || (isKeepAliveRecord
&& !supportsTCPKA
))
7989 // Offload only Valid Keepalive records
7990 if (isKeepAliveRecord
&& !mDNSValidKeepAliveRecord(rr
))
7993 (void) TCPKAOnly
; // unused
7994 (void) supportsTCPKA
; // unused
7995 #endif // APPLE_OSX_mDNSResponder
7997 if (TfrRecordToNIC(rr
))
7999 records
[count
].sixtyfourbits
= zeroOpaque64
;
8000 records
[count
].ptr
= p
;
8001 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
8002 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the 'unique' bit so PutResourceRecord will set it
8003 p
= PutResourceRecordTTLWithLimit(msg
, p
, &msg
->h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
, limit
);
8004 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear 'unique' bit back to normal state
8005 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
8006 count
, records
[count
].ptr
, p
, p
- (mDNSu8
*)records
[count
].ptr
, p
- msg
->data
, ARDisplayString(m
,rr
));
8011 *numbytes
= p
- msg
->data
;
8014 mDNSexport mDNSBool
SupportsInNICProxy(NetworkInterfaceInfo
*const intf
)
8016 if(!UseInternalSleepProxy
)
8018 LogMsg("SupportsInNICProxy: Internal Sleep Proxy is disabled");
8021 return CheckInterfaceSupport(intf
, mDNS_IOREG_KEY
);
8024 mDNSexport mStatus
ActivateLocalProxy(mDNS
*const m
, NetworkInterfaceInfo
*const intf
, mDNSBool
*keepaliveOnly
) // Called with the lock held
8026 mStatus result
= mStatus_UnknownErr
;
8027 mDNSBool TCPKAOnly
= mDNSfalse
;
8028 mDNSBool supportsTCPKA
= mDNSfalse
;
8029 mDNSBool onbattery
= mDNSfalse
;
8030 io_service_t service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOBSDNameMatching(kIOMasterPortDefault
, 0, intf
->ifname
));
8032 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
8033 onbattery
= OnBattery();
8034 // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
8035 supportsTCPKA
= (InterfaceSupportsKeepAlive(intf
) && SupportsTCPKeepAlive());
8037 // Only TCP Keepalive records are to be offloaded if
8038 // - The system is on battery
8039 // - OR wake for network access is not set but powernap is enabled
8040 TCPKAOnly
= supportsTCPKA
&& ((m
->SystemWakeOnLANEnabled
== mDNS_WakeOnBattery
) || onbattery
);
8042 (void) onbattery
; // unused;
8044 if (!service
) { LogMsg("ActivateLocalProxy: No service for interface %s", intf
->ifname
); return(mStatus_UnknownErr
); }
8047 IOObjectGetClass(service
, n1
);
8049 kern_return_t kr
= IORegistryEntryGetParentEntry(service
, kIOServicePlane
, &parent
);
8050 if (kr
!= KERN_SUCCESS
) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf
->ifname
, n1
, kr
);
8053 IOObjectGetClass(parent
, n2
);
8054 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf
->ifname
, n1
, n2
);
8055 const CFTypeRef ref
= IORegistryEntryCreateCFProperty(parent
, CFSTR(mDNS_IOREG_KEY
), kCFAllocatorDefault
, mDNSNULL
);
8056 if (!ref
) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", intf
->ifname
, n1
, n2
);
8059 if (CFGetTypeID(ref
) != CFStringGetTypeID() || !CFEqual(ref
, CFSTR(mDNS_IOREG_VALUE
)))
8060 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
8061 intf
->ifname
, n1
, n2
, CFStringGetCStringPtr(ref
, mDNSNULL
), mDNS_IOREG_VALUE
);
8062 else if (!UseInternalSleepProxy
)
8063 LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf
->ifname
);
8066 io_connect_t conObj
;
8067 kr
= IOServiceOpen(parent
, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE
, &conObj
);
8068 if (kr
!= KERN_SUCCESS
) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf
->ifname
, n1
, n2
, kr
);
8072 mDNSPlatformMemZero(&cmd
, sizeof(cmd
)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
8073 cmd
.command
= cmd_mDNSOffloadRR
;
8074 cmd
.numUDPPorts
= GetPortArray(m
, mDNSTransport_UDP
, mDNSNULL
);
8075 cmd
.numTCPPorts
= GetPortArray(m
, mDNSTransport_TCP
, mDNSNULL
);
8076 cmd
.numRRRecords
= CountProxyRecords(m
, &cmd
.rrBufferSize
, intf
, TCPKAOnly
, supportsTCPKA
);
8077 cmd
.compression
= sizeof(DNSMessageHeader
);
8079 DNSMessage
*msg
= (DNSMessage
*)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader
) + cmd
.rrBufferSize
);
8080 cmd
.rrRecords
.ptr
= cmd
.numRRRecords
? mallocL("mDNSOffloadCmd rrRecords", cmd
.numRRRecords
* sizeof(FatPtr
)) : NULL
;
8081 cmd
.udpPorts
.ptr
= cmd
.numUDPPorts
? mallocL("mDNSOffloadCmd udpPorts" , cmd
.numUDPPorts
* sizeof(mDNSIPPort
)) : NULL
;
8082 cmd
.tcpPorts
.ptr
= cmd
.numTCPPorts
? mallocL("mDNSOffloadCmd tcpPorts" , cmd
.numTCPPorts
* sizeof(mDNSIPPort
)) : NULL
;
8084 LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
8085 msg
, cmd
.rrBufferSize
,
8086 cmd
.rrRecords
.ptr
, cmd
.numRRRecords
,
8087 cmd
.udpPorts
.ptr
, cmd
.numUDPPorts
,
8088 cmd
.tcpPorts
.ptr
, cmd
.numTCPPorts
);
8090 if (msg
&& cmd
.rrRecords
.ptr
) GetProxyRecords(m
, msg
, &cmd
.rrBufferSize
, cmd
.rrRecords
.ptr
, TCPKAOnly
, supportsTCPKA
);
8091 if (cmd
.udpPorts
.ptr
) cmd
.numUDPPorts
= GetPortArray(m
, mDNSTransport_UDP
, cmd
.udpPorts
.ptr
);
8092 if (cmd
.tcpPorts
.ptr
) cmd
.numTCPPorts
= GetPortArray(m
, mDNSTransport_TCP
, cmd
.tcpPorts
.ptr
);
8095 size_t outputDataSize
= sizeof(outputData
);
8096 kr
= IOConnectCallStructMethod(conObj
, 0, &cmd
, sizeof(cmd
), outputData
, &outputDataSize
);
8097 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf
->ifname
, n1
, n2
, kr
);
8098 if (kr
== KERN_SUCCESS
) result
= mStatus_NoError
;
8100 if (cmd
.tcpPorts
.ptr
) freeL("mDNSOffloadCmd udpPorts", cmd
.tcpPorts
.ptr
);
8101 if (cmd
.udpPorts
.ptr
) freeL("mDNSOffloadCmd tcpPorts", cmd
.udpPorts
.ptr
);
8102 if (cmd
.rrRecords
.ptr
) freeL("mDNSOffloadCmd rrRecords", cmd
.rrRecords
.ptr
);
8103 if (msg
) freeL("mDNSOffloadCmd msg", msg
);
8104 IOServiceClose(conObj
);
8109 IOObjectRelease(parent
);
8111 IOObjectRelease(service
);
8112 *keepaliveOnly
= TCPKAOnly
;
8116 #endif // APPLE_OSX_mDNSResponder
8118 mDNSlocal mDNSu8
SystemWakeForNetworkAccess(void)
8121 mDNSu8 ret
= (mDNSu8
)mDNS_NoWake
;
8123 if (DisableSleepProxyClient
)
8125 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
8129 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val
);
8131 ret
= (mDNSu8
)(val
!= 0) ? mDNS_WakeOnAC
: mDNS_NoWake
;
8133 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
8134 // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
8135 // Further policy decisions on whether to offload the records is handled during sleep processing.
8136 if ((ret
== mDNS_NoWake
) && SupportsTCPKeepAlive())
8137 ret
= (mDNSu8
)mDNS_WakeOnBattery
;
8138 #endif // APPLE_OSX_mDNSResponder
8140 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret
);
8144 mDNSlocal mDNSBool
SystemSleepOnlyIfWakeOnLAN(void)
8147 // PrioritizeNetworkReachabilityOverSleep has been deprecated.
8148 // GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
8149 // Statically set the PrioritizeNetworkReachabilityOverSleep value to 1 for AppleTV
8152 return val
!= 0 ? mDNStrue
: mDNSfalse
;
8156 #if APPLE_OSX_mDNSResponder
8157 // When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
8158 // gets deregistered, so that older peers are forced to connect over direct UDP instead of
8161 // When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
8162 // service records are deregistered, so they do not appear in peers' Finder sidebars.
8163 // We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
8164 // depend on their associated SRV record and therefore will be deregistered together in a
8165 // single update with the SRV record.
8167 // Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
8168 // its presence shouldn't delay sleep.
8170 // Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
8171 // relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
8173 // Also note that returning false here will not delay sleep past the maximum of 10 seconds.
8174 mDNSexport mDNSBool
RecordReadyForSleep(mDNS
*const m
, AuthRecord
*rr
)
8176 if (!AuthRecord_uDNS(rr
)) return mDNStrue
;
8178 if ((rr
->resrec
.rrtype
== kDNSType_AAAA
) && SameDomainLabel(rr
->namestorage
.c
, (const mDNSu8
*)"\x0c_autotunnel6"))
8180 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m
, rr
));
8184 if ((mDNSIPPortIsZero(m
->AutoTunnelNAT
.ExternalPort
) || m
->AutoTunnelNAT
.Result
))
8186 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& rr
->state
!= regState_NoTarget
&& rr
->zone
8187 && !SameDomainLabel(rr
->namestorage
.c
, (const mDNSu8
*)"\x0b_autotunnel"))
8189 DomainAuthInfo
*info
= GetAuthInfoForName_internal(m
, rr
->zone
);
8190 if (info
&& info
->AutoTunnel
)
8192 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m
, rr
));
8201 // Caller must hold the lock
8202 mDNSexport
void RemoveAutoTunnel6Record(mDNS
*const m
)
8204 DomainAuthInfo
*info
;
8205 // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
8206 // deregister the record, and the MemFree callback won't re-register.
8207 m
->AutoTunnelRelayAddr
= zerov6Addr
;
8208 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
8209 if (info
->AutoTunnel
)
8210 UpdateAutoTunnel6Record(m
, info
);
8213 #if !TARGET_OS_EMBEDDED
8214 mDNSlocal mDNSBool
IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr
, char *ifname
)
8216 struct ifaddrs
*ifa
;
8217 struct ifaddrs
*ifaddrs
;
8220 if (if_nametoindex(ifname
) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname
); return mDNSfalse
;}
8222 if (getifaddrs(&ifaddrs
) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse
;}
8224 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
8226 if (strncmp(ifa
->ifa_name
, ifname
, IFNAMSIZ
) != 0)
8228 if ((ifa
->ifa_flags
& IFF_UP
) == 0 || !ifa
->ifa_addr
|| ifa
->ifa_addr
->sa_family
!= AF_INET6
)
8230 if (SetupAddr(&addr
, ifa
->ifa_addr
) != mStatus_NoError
)
8232 LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
8235 if (mDNSSameIPv6Address(ipv6Addr
, *(mDNSv6Addr
*)&addr
.ip
.v6
))
8237 LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr
);
8241 freeifaddrs(ifaddrs
);
8245 mDNSlocal mDNSv6Addr
IPv6AddressFromString(char* buf
)
8248 struct addrinfo hints
;
8249 struct addrinfo
*res0
;
8251 memset(&hints
, 0, sizeof(hints
));
8252 hints
.ai_family
= AF_INET6
;
8253 hints
.ai_flags
= AI_NUMERICHOST
;
8255 int err
= getaddrinfo(buf
, NULL
, &hints
, &res0
);
8259 retVal
= *(mDNSv6Addr
*)&((struct sockaddr_in6
*)res0
->ai_addr
)->sin6_addr
;
8266 mDNSlocal CFDictionaryRef
CopyConnectivityBackToMyMacDict()
8268 CFDictionaryRef connd
= NULL
;
8269 CFDictionaryRef BTMMDict
= NULL
;
8271 connd
= SCDynamicStoreCopyValue(NULL
, NetworkChangedKey_BTMMConnectivity
);
8274 LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
8278 BTMMDict
= CFDictionaryGetValue(connd
, CFSTR("BackToMyMac"));
8281 LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
8285 // Non-dictionary is treated as non-existent dictionary
8286 if (CFGetTypeID(BTMMDict
) != CFDictionaryGetTypeID())
8289 LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
8296 if (connd
) CFRelease(connd
);
8301 #define MAX_IPV6_TEXTUAL 40
8303 mDNSlocal mDNSv6Addr
ParseBackToMyMacAddr(CFDictionaryRef BTMMDict
, CFStringRef ifKey
, CFStringRef addrKey
)
8305 mDNSv6Addr retVal
= zerov6Addr
;
8306 CFTypeRef string
= NULL
;
8307 char ifname
[IFNAMSIZ
];
8308 char address
[MAX_IPV6_TEXTUAL
];
8313 if (!CFDictionaryGetValueIfPresent(BTMMDict
, ifKey
, &string
))
8315 LogInfo("ParseBackToMyMacAddr: interface key does not exist");
8319 if (!CFStringGetCString(string
, ifname
, IFNAMSIZ
, kCFStringEncodingUTF8
))
8321 LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
8325 if (!CFDictionaryGetValueIfPresent(BTMMDict
, addrKey
, &string
))
8327 LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
8331 if (!CFStringGetCString(string
, address
, sizeof(address
), kCFStringEncodingUTF8
))
8333 LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
8337 retVal
= IPv6AddressFromString(address
);
8338 LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname
, address
, &retVal
);
8340 if (mDNSIPv6AddressIsZero(retVal
))
8343 if (!IPv6AddressIsOnInterface(retVal
, ifname
))
8345 LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal
, ifname
);
8352 mDNSlocal CFDictionaryRef
GetBackToMyMacZones(CFDictionaryRef BTMMDict
)
8354 CFTypeRef zones
= NULL
;
8359 if (!CFDictionaryGetValueIfPresent(BTMMDict
, CFSTR("Zones"), &zones
))
8361 LogInfo("CopyBTMMZones: Zones key does not exist");
8368 mDNSlocal mDNSv6Addr
ParseBackToMyMacZone(CFDictionaryRef zones
, DomainAuthInfo
* info
)
8370 mDNSv6Addr addr
= zerov6Addr
;
8371 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
8372 CFStringRef domain
= NULL
;
8373 CFTypeRef theZone
= NULL
;
8378 ConvertDomainNameToCString(&info
->domain
, buffer
);
8379 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
8383 if (CFDictionaryGetValueIfPresent(zones
, domain
, &theZone
))
8384 addr
= ParseBackToMyMacAddr(theZone
, CFSTR("Interface"), CFSTR("Address"));
8391 mDNSlocal
void SetupBackToMyMacInnerAddresses(mDNS
*const m
, CFDictionaryRef BTMMDict
)
8393 DomainAuthInfo
* info
;
8394 CFDictionaryRef zones
= GetBackToMyMacZones(BTMMDict
);
8397 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
8399 if (!info
->AutoTunnel
)
8402 newAddr
= ParseBackToMyMacZone(zones
, info
);
8404 if (mDNSSameIPv6Address(newAddr
, info
->AutoTunnelInnerAddress
))
8407 info
->AutoTunnelInnerAddress
= newAddr
;
8408 DeregisterAutoTunnelHostRecord(m
, info
);
8409 UpdateAutoTunnelHostRecord(m
, info
);
8410 UpdateAutoTunnelDomainStatus(m
, info
);
8414 // MUST be called holding the lock
8415 mDNSlocal
void ProcessConndConfigChanges(mDNS
*const m
)
8417 CFDictionaryRef dict
= CopyConnectivityBackToMyMacDict();
8419 LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
8420 mDNSv6Addr relayAddr
= ParseBackToMyMacAddr(dict
, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
8422 LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr
);
8424 SetupBackToMyMacInnerAddresses(m
, dict
);
8426 if (dict
) CFRelease(dict
);
8428 if (!mDNSSameIPv6Address(relayAddr
, m
->AutoTunnelRelayAddr
))
8430 m
->AutoTunnelRelayAddr
= relayAddr
;
8432 DomainAuthInfo
* info
;
8433 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
8434 if (info
->AutoTunnel
)
8436 DeregisterAutoTunnel6Record(m
, info
);
8437 UpdateAutoTunnel6Record(m
, info
);
8438 UpdateAutoTunnelDomainStatus(m
, info
);
8441 // Determine whether we need racoon to accept incoming connections
8442 UpdateAnonymousRacoonConfig(m
);
8445 // If awacsd crashes or exits for some reason, restart it
8446 UpdateBTMMRelayConnection(m
);
8448 #endif // !TARGET_OS_EMBEDDED
8449 #endif /* APPLE_OSX_mDNSResponder */
8451 mDNSlocal mDNSBool
IsAppleNetwork(mDNS
*const m
)
8454 // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
8455 for (s
= m
->DNSServers
; s
; s
= s
->next
)
8457 if (s
->addr
.ip
.v4
.b
[0] == 17)
8459 LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s
->domain
.c
, &s
->addr
);
8466 // Called with KQueueLock & mDNS lock
8467 // SetNetworkChanged is allowed to shorten (but not extend) the pause while we wait for configuration changes to settle
8468 mDNSlocal
void SetNetworkChanged(mDNS
*const m
, mDNSs32 delay
)
8471 if (!m
->NetworkChanged
|| m
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) > 0)
8473 m
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
8474 LogInfo("SetNetworkChanged: Scheduling in %d ticks", delay
);
8477 LogInfo("SetNetworkChanged: *NOT* increasing delay from %d to %d", m
->NetworkChanged
- m
->timenow
, delay
);
8480 // Called with KQueueLock & mDNS lock
8481 mDNSlocal
void SetKeyChainTimer(mDNS
*const m
, mDNSs32 delay
)
8483 // If it's not set or it needs to happen sooner than when it's currently set
8484 if (!m
->p
->KeyChainTimer
|| m
->p
->KeyChainTimer
- NonZeroTime(m
->timenow
+ delay
) > 0)
8486 m
->p
->KeyChainTimer
= NonZeroTime(m
->timenow
+ delay
);
8487 LogInfo("SetKeyChainTimer: %d", delay
);
8491 mDNSexport
void mDNSMacOSXNetworkChanged(mDNS
*const m
)
8493 LogInfo("*** Network Configuration Change *** %d ticks late%s",
8494 m
->NetworkChanged
? mDNS_TimeNow(m
) - m
->NetworkChanged
: 0,
8495 m
->NetworkChanged
? "" : " (no scheduled configuration change)");
8496 m
->NetworkChanged
= 0; // If we received a network change event and deferred processing, we're now dealing with it
8498 // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring
8499 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
8502 mDNSBool tentative
= mDNSfalse
;
8503 struct ifaddrs
*ifa
= myGetIfAddrs(1);
8506 if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
8508 struct in6_ifreq ifr6
;
8509 mDNSPlatformMemZero((char *)&ifr6
, sizeof(ifr6
));
8510 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
8511 ifr6
.ifr_addr
= *(struct sockaddr_in6
*)ifa
->ifa_addr
;
8512 // We need to check for IN6_IFF_TENTATIVE here, not IN6_IFF_NOTREADY, because
8513 // IN6_IFF_NOTREADY includes both IN6_IFF_TENTATIVE and IN6_IFF_DUPLICATED addresses.
8514 // We can expect that an IN6_IFF_TENTATIVE address will shortly become ready,
8515 // but an IN6_IFF_DUPLICATED address may not.
8516 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
8518 if (ifr6
.ifr_ifru
.ifru_flags6
& IN6_IFF_TENTATIVE
)
8520 LogInfo("*** Network Configuration Change *** IPv6 address %.16a TENTATIVE, will retry", &ifr6
.ifr_addr
.sin6_addr
);
8521 tentative
= mDNStrue
;
8522 // no need to check other interfaces if we already found out that one interface is TENTATIVE
8527 ifa
= ifa
->ifa_next
;
8533 SetNetworkChanged(m
, mDNSPlatformOneSecond
/ 2);
8537 LogInfo("*** Network Configuration Change *** No IPv6 address TENTATIVE, will continue");
8540 mDNSs32 utc
= mDNSPlatformUTC();
8541 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
8542 m
->SystemSleepOnlyIfWakeOnLAN
= SystemSleepOnlyIfWakeOnLAN();
8543 MarkAllInterfacesInactive(m
, utc
);
8544 UpdateInterfaceList(m
, utc
);
8545 ClearInactiveInterfaces(m
, utc
);
8546 SetupActiveInterfaces(m
, utc
);
8548 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
8551 ProcessConndConfigChanges(m
);
8554 // Scan to find client tunnels whose questions have completed,
8555 // but whose local inner/outer addresses have changed since the tunnel was set up
8557 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
8558 if (p
->q
.ThisQInterval
< 0)
8560 DomainAuthInfo
* info
= GetAuthInfoForName(m
, &p
->dstname
);
8563 LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p
->dstname
.c
);
8564 AutoTunnelSetKeys(p
, mDNSfalse
);
8568 mDNSv6Addr inner
= info
->AutoTunnelInnerAddress
;
8570 if (!mDNSIPPortIsZero(p
->rmt_outer_port
))
8572 mDNSAddr tmpSrc
= zeroAddr
;
8573 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
8574 tmpDst
.ip
.v4
= p
->rmt_outer
;
8575 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
8576 if (!mDNSSameIPv6Address(p
->loc_inner
, inner
) ||
8577 !mDNSSameIPv4Address(p
->loc_outer
, tmpSrc
.ip
.v4
))
8579 AutoTunnelSetKeys(p
, mDNSfalse
);
8580 p
->loc_inner
= inner
;
8581 p
->loc_outer
= tmpSrc
.ip
.v4
;
8582 AutoTunnelSetKeys(p
, mDNStrue
);
8587 if (!mDNSSameIPv6Address(p
->loc_inner
, inner
) ||
8588 !mDNSSameIPv6Address(p
->loc_outer6
, m
->AutoTunnelRelayAddr
))
8590 AutoTunnelSetKeys(p
, mDNSfalse
);
8591 p
->loc_inner
= inner
;
8592 p
->loc_outer6
= m
->AutoTunnelRelayAddr
;
8593 AutoTunnelSetKeys(p
, mDNStrue
);
8601 NetworkInterfaceInfoOSX
*i
;
8602 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
8604 if (!m
->SPSSocket
) // Not being Sleep Proxy Server; close any open BPF fds
8606 if (i
->BPF_fd
>= 0 && CountProxyTargets(m
, i
, mDNSNULL
, mDNSNULL
) == 0)
8609 else // else, we're Sleep Proxy Server; open BPF fds
8611 if (i
->Exists
&& (i
->Registered
== i
) && SPSInterface(i
) && i
->BPF_fd
== -1)
8613 LogMsg("%s mDNSMacOSXNetworkChanged: requesting BPF", i
->ifinfo
.ifname
);
8620 #endif // APPLE_OSX_mDNSResponder
8622 uDNS_SetupDNSConfig(m
);
8623 mDNS_ConfigChanged(m
);
8625 if (IsAppleNetwork(m
) != mDNS_McastTracingEnabled
)
8627 mDNS_McastTracingEnabled
= mDNS_McastTracingEnabled
? mDNSfalse
: mDNStrue
;
8628 LogInfo("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled
? "Enabled" : "Disabled");
8634 // Copy the fourth slash-delimited element from either:
8635 // State:/Network/Interface/<bsdname>/IPv4
8637 // Setup:/Network/Service/<servicename>/Interface
8638 mDNSlocal CFStringRef
CopyNameFromKey(CFStringRef key
)
8641 CFStringRef name
= NULL
;
8643 a
= CFStringCreateArrayBySeparatingStrings(NULL
, key
, CFSTR("/"));
8644 if (a
&& CFArrayGetCount(a
) == 5) name
= CFRetain(CFArrayGetValueAtIndex(a
, 3));
8645 if (a
!= NULL
) CFRelease(a
);
8650 // Whether a key from a network change notification corresponds to
8651 // an IP service that is explicitly configured for IPv4 Link Local
8652 mDNSlocal
int ChangedKeysHaveIPv4LL(CFArrayRef inkeys
)
8654 CFDictionaryRef dict
= NULL
;
8655 CFMutableArrayRef a
;
8656 const void **keys
= NULL
, **vals
= NULL
;
8657 CFStringRef pattern
= NULL
;
8661 jc
= CFArrayGetCount(inkeys
);
8664 a
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
8665 if (a
== NULL
) goto done
;
8667 // Setup:/Network/Service/[^/]+/Interface
8668 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetInterface
);
8669 if (pattern
== NULL
) goto done
;
8670 CFArrayAppendValue(a
, pattern
);
8673 // Setup:/Network/Service/[^/]+/IPv4
8674 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetIPv4
);
8675 if (pattern
== NULL
) goto done
;
8676 CFArrayAppendValue(a
, pattern
);
8679 dict
= SCDynamicStoreCopyMultiple(NULL
, NULL
, a
);
8684 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
8688 ic
= CFDictionaryGetCount(dict
);
8689 vals
= mDNSPlatformMemAllocate(sizeof (void *) * ic
);
8690 keys
= mDNSPlatformMemAllocate(sizeof (void *) * ic
);
8691 CFDictionaryGetKeysAndValues(dict
, keys
, vals
);
8693 // For each key we were given...
8694 for (j
= 0; j
< jc
; j
++)
8696 CFStringRef key
= CFArrayGetValueAtIndex(inkeys
, j
);
8697 CFStringRef ifname
= NULL
;
8701 // It would be nice to use a regex here
8702 if (!CFStringHasPrefix(key
, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key
, kSCEntNetIPv4
)) continue;
8704 if ((ifname
= CopyNameFromKey(key
)) == NULL
) continue;
8705 if (mDNS_LoggingEnabled
)
8707 if (!CFStringGetCString(ifname
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
8708 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf
);
8711 // Loop over the interfaces to find matching the ifname, and see if that one has kSCValNetIPv4ConfigMethodLinkLocal
8712 for (i
= 0; i
< ic
; i
++)
8714 CFDictionaryRef ipv4dict
;
8716 CFStringRef serviceid
;
8717 CFStringRef configmethod
;
8719 if (!CFStringHasSuffix(keys
[i
], kSCEntNetInterface
)) continue;
8721 if (CFDictionaryGetTypeID() != CFGetTypeID(vals
[i
])) continue;
8723 if ((name
= CFDictionaryGetValue(vals
[i
], kSCPropNetInterfaceDeviceName
)) == NULL
) continue;
8725 if (!CFEqual(ifname
, name
)) continue;
8727 if ((serviceid
= CopyNameFromKey(keys
[i
])) == NULL
) continue;
8728 if (mDNS_LoggingEnabled
)
8730 if (!CFStringGetCString(serviceid
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
8731 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf
);
8734 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceid
, kSCEntNetIPv4
);
8735 CFRelease(serviceid
);
8736 if (pattern
== NULL
) continue;
8738 ipv4dict
= CFDictionaryGetValue(dict
, pattern
);
8740 if (!ipv4dict
|| CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict
)) continue;
8742 configmethod
= CFDictionaryGetValue(ipv4dict
, kSCPropNetIPv4ConfigMethod
);
8743 if (!configmethod
) continue;
8745 if (mDNS_LoggingEnabled
)
8747 if (!CFStringGetCString(configmethod
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
8748 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf
);
8751 if (CFEqual(configmethod
, kSCValNetIPv4ConfigMethodLinkLocal
)) { found
++; break; }
8758 if (vals
!= NULL
) mDNSPlatformMemFree(vals
);
8759 if (keys
!= NULL
) mDNSPlatformMemFree(keys
);
8760 if (dict
!= NULL
) CFRelease(dict
);
8765 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
8767 (void)store
; // Parameter not used
8768 mDNS
*const m
= (mDNS
*const)context
;
8772 //mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
8773 const mDNSs32 delay
= (mDNSPlatformOneSecond
+ 39) / 40; // 25 ms delay
8775 int c
= CFArrayGetCount(changedKeys
); // Count changes
8776 CFRange range
= { 0, c
};
8777 int c_host
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Hostnames
) != 0);
8778 int c_comp
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Computername
) != 0);
8779 int c_udns
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DNS
) != 0);
8780 int c_ddns
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DynamicDNS
) != 0);
8781 int c_btmm
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_BackToMyMac
) != 0);
8782 int c_v4ll
= ChangedKeysHaveIPv4LL(changedKeys
);
8785 // Do immediate network changed processing for "p2p*" interfaces and
8786 // for interfaces with the IFEF_DIRECTLINK flag set or association with a CarPlay
8791 for (int i
= 0; i
< c
; i
++)
8793 CFStringRef key
= CFArrayGetValueAtIndex(changedKeys
, i
);
8795 // Only look at keys with prefix "State:/Network/Interface/"
8796 if (!CFStringHasPrefix(key
, NetworkChangedKey_StateInterfacePrefix
))
8799 // And suffix "IPv6" or "IPv4".
8800 if (!CFStringHasSuffix(key
, kSCEntNetIPv6
) && !CFStringHasSuffix(key
, kSCEntNetIPv4
))
8803 labels
= CFStringCreateArrayBySeparatingStrings(NULL
, key
, CFSTR("/"));
8806 n
= CFArrayGetCount(labels
);
8808 // Interface changes will have keys of the form:
8809 // State:/Network/Interface/<interfaceName>/IPv6
8810 // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
8815 // The 4th label (index = 3) should be the interface name.
8816 if (CFStringGetCString(CFArrayGetValueAtIndex(labels
, 3), buf
, sizeof(buf
), kCFStringEncodingUTF8
)
8817 && (strstr(buf
, "p2p") || (getExtendedFlags(buf
) & IFEF_DIRECTLINK
) || IsCarPlaySSID(buf
)))
8819 LogInfo("NetworkChanged: interface %s qualifies for reduced change handling delay", buf
);
8829 //if (c && c - c_host - c_comp - c_udns - c_ddns - c_btmm - c_v4ll - c_fast == 0)
8830 // delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
8832 if (mDNS_LoggingEnabled
)
8838 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys
, i
), buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
8839 LogInfo("*** Network Configuration Change *** SC key: %s", buf
);
8841 LogInfo("*** Network Configuration Change *** %d change%s %s%s%s%s%s%s%sdelay %d%s",
8843 c_host
? "(Local Hostname) " : "",
8844 c_comp
? "(Computer Name) " : "",
8845 c_udns
? "(DNS) " : "",
8846 c_ddns
? "(DynamicDNS) " : "",
8847 c_btmm
? "(BTMM) " : "",
8848 c_v4ll
? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
8849 c_fast
? "(P2P/IFEF_DIRECTLINK/IsCarPlaySSID) " : "",
8851 (c_ddns
|| c_btmm
) ? " + SetKeyChainTimer" : "");
8854 SetNetworkChanged(m
, delay
);
8856 // Other software might pick up these changes to register or browse in WAB or BTMM domains,
8857 // so in order for secure updates to be made to the server, make sure to read the keychain and
8858 // setup the DomainAuthInfo before handing the network change.
8859 // If we don't, then we will first try to register services in the clear, then later setup the
8860 // DomainAuthInfo, which is incorrect.
8861 if (c_ddns
|| c_btmm
)
8862 SetKeyChainTimer(m
, delay
);
8864 // Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
8867 KQueueUnlock(m
, "NetworkChanged");
8870 #if APPLE_OSX_mDNSResponder
8871 mDNSlocal
void RefreshSPSStatus(const void *key
, const void *value
, void *context
)
8876 CFStringRef ifnameStr
= (CFStringRef
)key
;
8877 CFArrayRef array
= (CFArrayRef
)value
;
8878 if (!CFStringGetCString(ifnameStr
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
8881 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf
, CFArrayGetCount(array
));
8882 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState
, buf
, value
);
8886 mDNSlocal
void DynamicStoreReconnected(SCDynamicStoreRef store
, void *info
)
8888 mDNS
*const m
= (mDNS
*const)info
;
8891 KQueueLock(m
); // serialize with KQueueLoop()
8893 LogInfo("DynamicStoreReconnected: Reconnected");
8895 // State:/Network/MulticastDNS
8898 // State:/Network/DynamicDNS
8900 mDNSPlatformDynDNSHostNameStatusChanged(&m
->FQDN
, 1);
8902 // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
8903 // as we receive network change notifications and thus not necessary. But we leave it here
8904 // so that if things are done differently in the future, this code still works.
8906 // State:/Network/PrivateDNS
8907 if (privateDnsArray
)
8908 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, mDNSNULL
, privateDnsArray
);
8910 #if APPLE_OSX_mDNSResponder
8911 // State:/Network/BackToMyMac
8912 UpdateAutoTunnelDomainStatuses(m
);
8914 // State:/Network/Interface/en0/SleepProxyServers
8916 CFDictionaryApplyFunction(spsStatusDict
, RefreshSPSStatus
, NULL
);
8918 KQueueUnlock(m
, "DynamicStoreReconnected");
8921 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
8924 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
8925 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
8926 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
8927 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
8928 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
8929 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
8931 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
8932 if (!keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
8934 CFArrayAppendValue(keys
, NetworkChangedKey_IPv4
);
8935 CFArrayAppendValue(keys
, NetworkChangedKey_IPv6
);
8936 CFArrayAppendValue(keys
, NetworkChangedKey_Hostnames
);
8937 CFArrayAppendValue(keys
, NetworkChangedKey_Computername
);
8938 CFArrayAppendValue(keys
, NetworkChangedKey_DNS
);
8939 CFArrayAppendValue(keys
, NetworkChangedKey_DynamicDNS
);
8940 CFArrayAppendValue(keys
, NetworkChangedKey_BackToMyMac
);
8941 CFArrayAppendValue(keys
, NetworkChangedKey_PowerSettings
);
8942 CFArrayAppendValue(keys
, NetworkChangedKey_BTMMConnectivity
);
8943 CFArrayAppendValue(patterns
, pattern1
);
8944 CFArrayAppendValue(patterns
, pattern2
);
8945 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
8946 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
8947 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
8949 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8950 if (!SCDynamicStoreSetDispatchQueue(store
, dispatch_get_main_queue()))
8951 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
8953 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
8954 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
8955 CFRunLoopAddSource(CFRunLoopGetMain(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
8957 SCDynamicStoreSetDisconnectCallBack(store
, DynamicStoreReconnected
);
8958 m
->p
->Store
= store
;
8963 if (store
) CFRelease(store
);
8966 if (patterns
) CFRelease(patterns
);
8967 if (pattern2
) CFRelease(pattern2
);
8968 if (pattern1
) CFRelease(pattern1
);
8969 if (keys
) CFRelease(keys
);
8974 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8976 mDNSlocal
void mDNSSetPacketFilterRules(mDNS
*const m
, char * ifname
, const ResourceRecord
*const excludeRecord
)
8979 pfArray_t portArray
;
8980 pfArray_t protocolArray
;
8983 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
8985 if ((rr
->resrec
.rrtype
== kDNSServiceType_SRV
)
8986 && ((rr
->ARType
== AuthRecordAnyIncludeP2P
) || (rr
->ARType
== AuthRecordAnyIncludeAWDLandP2P
)))
8990 if (count
>= PFPortArraySize
)
8992 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize
, ARDisplayString(m
, rr
));
8996 if (excludeRecord
&& IdenticalResourceRecord(&rr
->resrec
, excludeRecord
))
8998 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m
, rr
));
9002 LogMsg("mDNSSetPacketFilterRules: found %s", ARDisplayString(m
, rr
));
9004 portArray
[count
] = rr
->resrec
.rdata
->u
.srv
.port
.NotAnInteger
;
9006 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
9007 p
= rr
->resrec
.name
->c
;
9009 // Skip to App Protocol
9013 // Skip to Transport Protocol
9017 if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_tcp"))
9019 protocolArray
[count
] = IPPROTO_TCP
;
9021 else if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_udp"))
9023 protocolArray
[count
] = IPPROTO_UDP
;
9027 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
9028 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m
, rr
));
9034 mDNSPacketFilterControl(PF_SET_RULES
, ifname
, count
, portArray
, protocolArray
);
9037 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
9038 mDNSexport
void mDNSUpdatePacketFilter(const ResourceRecord
*const excludeRecord
)
9040 mDNS
*const m
= &mDNSStorage
;
9042 NetworkInterfaceInfo
*intf
= GetFirstActiveInterface(m
->HostInterfaces
);
9045 if (strncmp(intf
->ifname
, "p2p", 3) == 0)
9047 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf
->ifname
);
9048 mDNSSetPacketFilterRules(m
, intf
->ifname
, excludeRecord
);
9051 intf
= GetFirstActiveInterface(intf
->next
);
9055 #else // !TARGET_OS_EMBEDDED
9057 // Currently no packet filter setup required on embedded platforms.
9058 mDNSexport
void mDNSUpdatePacketFilter(const ResourceRecord
*const excludeRecord
)
9060 (void) excludeRecord
; // unused
9063 #endif // !TARGET_OS_EMBEDDED
9065 // Handle AWDL KEV_DL_MASTER_ELECTED event by restarting queries and advertisements
9066 // marked to include the AWDL interface.
9067 mDNSlocal
void newMasterElected(mDNS
*const m
, struct net_event_data
* ptr
)
9069 char ifname
[IFNAMSIZ
];
9070 mDNSu32 interfaceIndex
;
9073 NetworkInterfaceInfoOSX
*infoOSX
;
9074 mDNSInterfaceID InterfaceID
;
9076 snprintf(ifname
, IFNAMSIZ
, "%s%d", ptr
->if_name
, ptr
->if_unit
);
9077 interfaceIndex
= if_nametoindex(ifname
);
9079 if (!interfaceIndex
)
9081 LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname
);
9085 LogInfo("newMasterElected: ifname = %s, interfaceIndex = %d", ifname
, interfaceIndex
);
9086 infoOSX
= IfindexToInterfaceInfoOSX(m
, (mDNSInterfaceID
)(uintptr_t)interfaceIndex
);
9089 LogInfo("newMasterElected: interface %s not yet active", ifname
);
9092 InterfaceID
= infoOSX
->ifinfo
.InterfaceID
;
9094 for (q
= m
->Questions
; q
; q
=q
->next
)
9096 if ((!q
->InterfaceID
&& (q
->flags
& kDNSServiceFlagsIncludeAWDL
))
9097 || q
->InterfaceID
== InterfaceID
)
9099 LogInfo("newMasterElected: restarting %s query for %##s", DNSTypeName(q
->qtype
), q
->qname
.c
);
9100 mDNSCoreRestartQuestion(m
, q
);
9104 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
9106 if ((!rr
->resrec
.InterfaceID
9107 && ((rr
->ARType
== AuthRecordAnyIncludeAWDL
) || ((rr
->ARType
== AuthRecordAnyIncludeAWDLandP2P
))))
9108 || rr
->resrec
.InterfaceID
== InterfaceID
)
9110 LogInfo("newMasterElected: restarting %s announcements for %##s", DNSTypeName(rr
->resrec
.rrtype
), rr
->namestorage
.c
);
9111 mDNSCoreRestartRegistration(m
, rr
, -1);
9116 // An ssth array of all zeroes indicates the peer has no services registered.
9117 mDNSlocal mDNSBool
allZeroSSTH(struct opaque_presence_indication
*op
)
9120 int *intp
= (int *) op
->ssth
;
9122 // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
9123 // it's not, print an error message and return false so that
9124 // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
9126 if (MAX_SSTH_SIZE
% sizeof(int))
9128 LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE
);
9132 for (i
= 0; i
< (int)(MAX_SSTH_SIZE
/ sizeof(int)); i
++, intp
++)
9140 // Mark records from this peer for deletion from the cache.
9141 mDNSlocal
void removeCachedPeerRecords(mDNS
*const m
, mDNSu32 ifindex
, mDNSAddr
*ap
, bool purgeNow
)
9146 NetworkInterfaceInfoOSX
*infoOSX
;
9147 mDNSInterfaceID InterfaceID
;
9149 // Using mDNSPlatformInterfaceIDfromInterfaceIndex() would lead to recursive
9150 // locking issues, see: <rdar://problem/21332983>
9151 infoOSX
= IfindexToInterfaceInfoOSX(m
, (mDNSInterfaceID
)(uintptr_t)ifindex
);
9154 LogInfo("removeCachedPeerRecords: interface %d not yet active", ifindex
);
9157 InterfaceID
= infoOSX
->ifinfo
.InterfaceID
;
9159 FORALL_CACHERECORDS(slot
, cg
, cr
)
9161 if ((InterfaceID
== cr
->resrec
.InterfaceID
) && mDNSSameAddress(ap
, & cr
->sourceAddress
))
9163 LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
9164 DNSTypeName(cr
->resrec
.rrtype
), cr
->resrec
.name
->c
);
9167 mDNS_PurgeCacheResourceRecord(m
, cr
);
9169 mDNS_Reconfirm_internal(m
, cr
, 0); // use default minimum reconfirm time
9174 // Handle KEV_DL_NODE_PRESENCE event.
9175 mDNSlocal
void nodePresence(mDNS
*const m
, struct kev_dl_node_presence
* p
)
9177 char buf
[INET6_ADDRSTRLEN
];
9178 struct opaque_presence_indication
*op
= (struct opaque_presence_indication
*) p
->node_service_info
;
9180 if (inet_ntop(AF_INET6
, & p
->sin6_node_address
.sin6_addr
, buf
, sizeof(buf
)))
9181 LogInfo("nodePresence: IPv6 address: %s, SUI %d", buf
, op
->SUI
);
9183 LogInfo("nodePresence: inet_ntop() error");
9185 // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
9186 // all zeroes when a node is present and has no services registered.
9187 if (allZeroSSTH(op
))
9191 peerAddr
.type
= mDNSAddrType_IPv6
;
9192 peerAddr
.ip
.v6
= *(mDNSv6Addr
*)&p
->sin6_node_address
.sin6_addr
;
9194 LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer");
9195 removeCachedPeerRecords(m
, p
->sdl_node_address
.sdl_index
, & peerAddr
, false);
9199 // Handle KEV_DL_NODE_ABSENCE event.
9200 mDNSlocal
void nodeAbsence(mDNS
*const m
, struct kev_dl_node_absence
* p
)
9203 char buf
[INET6_ADDRSTRLEN
];
9205 if (inet_ntop(AF_INET6
, & p
->sin6_node_address
.sin6_addr
, buf
, sizeof(buf
)))
9206 LogInfo("nodeAbsence: IPv6 address: %s", buf
);
9208 LogInfo("nodeAbsence: inet_ntop() error");
9210 peerAddr
.type
= mDNSAddrType_IPv6
;
9211 peerAddr
.ip
.v6
= *(mDNSv6Addr
*)&p
->sin6_node_address
.sin6_addr
;
9213 LogInfo("nodeAbsence: immediately purge cached records from this peer");
9214 removeCachedPeerRecords(m
, p
->sdl_node_address
.sdl_index
, & peerAddr
, true);
9217 mDNSlocal
void SysEventCallBack(int s1
, short __unused filter
, void *context
)
9219 mDNS
*const m
= (mDNS
*const)context
;
9223 struct { struct kern_event_msg k
; char extra
[256]; } msg
;
9224 int bytes
= recv(s1
, &msg
, sizeof(msg
), 0);
9226 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes
, errno
, strerror(errno
));
9229 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
9230 bytes
, msg
.k
.total_size
,
9231 msg
.k
.vendor_code
, msg
.k
.vendor_code
== KEV_VENDOR_APPLE
? "KEV_VENDOR_APPLE" : "?",
9232 msg
.k
.kev_class
, msg
.k
.kev_class
== KEV_NETWORK_CLASS
? "KEV_NETWORK_CLASS" : "?",
9233 msg
.k
.kev_subclass
, msg
.k
.kev_subclass
== KEV_DL_SUBCLASS
? "KEV_DL_SUBCLASS" : "?",
9234 msg
.k
.id
, msg
.k
.event_code
,
9235 msg
.k
.event_code
== KEV_DL_SIFFLAGS
? "KEV_DL_SIFFLAGS" :
9236 msg
.k
.event_code
== KEV_DL_SIFMETRICS
? "KEV_DL_SIFMETRICS" :
9237 msg
.k
.event_code
== KEV_DL_SIFMTU
? "KEV_DL_SIFMTU" :
9238 msg
.k
.event_code
== KEV_DL_SIFPHYS
? "KEV_DL_SIFPHYS" :
9239 msg
.k
.event_code
== KEV_DL_SIFMEDIA
? "KEV_DL_SIFMEDIA" :
9240 msg
.k
.event_code
== KEV_DL_SIFGENERIC
? "KEV_DL_SIFGENERIC" :
9241 msg
.k
.event_code
== KEV_DL_ADDMULTI
? "KEV_DL_ADDMULTI" :
9242 msg
.k
.event_code
== KEV_DL_DELMULTI
? "KEV_DL_DELMULTI" :
9243 msg
.k
.event_code
== KEV_DL_IF_ATTACHED
? "KEV_DL_IF_ATTACHED" :
9244 msg
.k
.event_code
== KEV_DL_IF_DETACHING
? "KEV_DL_IF_DETACHING" :
9245 msg
.k
.event_code
== KEV_DL_IF_DETACHED
? "KEV_DL_IF_DETACHED" :
9246 msg
.k
.event_code
== KEV_DL_LINK_OFF
? "KEV_DL_LINK_OFF" :
9247 msg
.k
.event_code
== KEV_DL_LINK_ON
? "KEV_DL_LINK_ON" :
9248 msg
.k
.event_code
== KEV_DL_PROTO_ATTACHED
? "KEV_DL_PROTO_ATTACHED" :
9249 msg
.k
.event_code
== KEV_DL_PROTO_DETACHED
? "KEV_DL_PROTO_DETACHED" :
9250 msg
.k
.event_code
== KEV_DL_LINK_ADDRESS_CHANGED
? "KEV_DL_LINK_ADDRESS_CHANGED" :
9251 msg
.k
.event_code
== KEV_DL_WAKEFLAGS_CHANGED
? "KEV_DL_WAKEFLAGS_CHANGED" :
9252 msg
.k
.event_code
== KEV_DL_IF_IDLE_ROUTE_REFCNT
? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
9253 msg
.k
.event_code
== KEV_DL_IFCAP_CHANGED
? "KEV_DL_IFCAP_CHANGED" :
9254 msg
.k
.event_code
== KEV_DL_LINK_QUALITY_METRIC_CHANGED
? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" :
9255 msg
.k
.event_code
== KEV_DL_NODE_PRESENCE
? "KEV_DL_NODE_PRESENCE" :
9256 msg
.k
.event_code
== KEV_DL_NODE_ABSENCE
? "KEV_DL_NODE_ABSENCE" :
9257 msg
.k
.event_code
== KEV_DL_MASTER_ELECTED
? "KEV_DL_MASTER_ELECTED" :
9260 if (msg
.k
.event_code
== KEV_DL_NODE_PRESENCE
)
9261 nodePresence(m
, (struct kev_dl_node_presence
*) &msg
.k
.event_data
);
9263 if (msg
.k
.event_code
== KEV_DL_NODE_ABSENCE
)
9264 nodeAbsence(m
, (struct kev_dl_node_absence
*) &msg
.k
.event_data
);
9266 if (msg
.k
.event_code
== KEV_DL_MASTER_ELECTED
)
9267 newMasterElected(m
, (struct net_event_data
*) &msg
.k
.event_data
);
9269 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
9270 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
9271 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
9272 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
9273 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
9275 if (msg
.k
.event_code
== KEV_DL_WAKEFLAGS_CHANGED
|| msg
.k
.event_code
== KEV_DL_LINK_ON
)
9276 SetNetworkChanged(m
, mDNSPlatformOneSecond
* 2);
9278 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
9280 // For p2p interfaces, need to open the advertised service port in the firewall.
9281 if (msg
.k
.event_code
== KEV_DL_IF_ATTACHED
)
9283 struct net_event_data
* p
;
9284 p
= (struct net_event_data
*) &msg
.k
.event_data
;
9286 if (strncmp(p
->if_name
, "p2p", 3) == 0)
9288 char ifname
[IFNAMSIZ
];
9289 snprintf(ifname
, IFNAMSIZ
, "%s%d", p
->if_name
, p
->if_unit
);
9291 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p
->if_family
, p
->if_unit
, p
->if_name
);
9293 mDNSSetPacketFilterRules(m
, ifname
, NULL
);
9297 // For p2p interfaces, need to clear the firewall rules on interface detach
9298 if (msg
.k
.event_code
== KEV_DL_IF_DETACHED
)
9300 struct net_event_data
* p
;
9301 p
= (struct net_event_data
*) &msg
.k
.event_data
;
9303 if (strncmp(p
->if_name
, "p2p", 3) == 0)
9305 pfArray_t portArray
, protocolArray
; // not initialized since count is 0 for PF_CLEAR_RULES
9306 char ifname
[IFNAMSIZ
];
9307 snprintf(ifname
, IFNAMSIZ
, "%s%d", p
->if_name
, p
->if_unit
);
9309 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p
->if_family
, p
->if_unit
, p
->if_name
);
9311 mDNSPacketFilterControl(PF_CLEAR_RULES
, ifname
, 0, portArray
, protocolArray
);
9314 #endif // !TARGET_OS_EMBEDDED
9321 mDNSlocal mStatus
WatchForSysEvents(mDNS
*const m
)
9323 m
->p
->SysEventNotifier
= socket(PF_SYSTEM
, SOCK_RAW
, SYSPROTO_EVENT
);
9324 if (m
->p
->SysEventNotifier
< 0)
9325 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m
->p
->SysEventNotifier
, errno
, strerror(errno
)); return(mStatus_NoMemoryErr
); }
9327 struct kev_request kev_req
= { KEV_VENDOR_APPLE
, KEV_NETWORK_CLASS
, KEV_DL_SUBCLASS
};
9328 int err
= ioctl(m
->p
->SysEventNotifier
, SIOCSKEVFILT
, &kev_req
);
9331 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err
, errno
, strerror(errno
));
9332 close(m
->p
->SysEventNotifier
);
9333 m
->p
->SysEventNotifier
= -1;
9334 return(mStatus_UnknownErr
);
9337 m
->p
->SysEventKQueue
.KQcallback
= SysEventCallBack
;
9338 m
->p
->SysEventKQueue
.KQcontext
= m
;
9339 m
->p
->SysEventKQueue
.KQtask
= "System Event Notifier";
9340 KQueueSet(m
->p
->SysEventNotifier
, EV_ADD
, EVFILT_READ
, &m
->p
->SysEventKQueue
);
9342 return(mStatus_NoError
);
9345 #ifndef NO_SECURITYFRAMEWORK
9346 mDNSlocal OSStatus
KeychainChanged(SecKeychainEvent keychainEvent
, SecKeychainCallbackInfo
*info
, void *context
)
9348 LogInfo("*** Keychain Changed ***");
9349 mDNS
*const m
= (mDNS
*const)context
;
9351 OSStatus err
= SecKeychainCopyDefault(&skc
);
9354 if (info
->keychain
== skc
)
9356 // 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
9357 mDNSBool relevant
= (keychainEvent
== kSecDeleteEvent
);
9360 UInt32 tags
[3] = { kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
};
9361 SecKeychainAttributeInfo attrInfo
= { 3, tags
, NULL
}; // Count, array of tags, array of formats
9362 SecKeychainAttributeList
*a
= NULL
;
9363 err
= SecKeychainItemCopyAttributesAndData(info
->item
, &attrInfo
, NULL
, &a
, NULL
, NULL
);
9366 relevant
= ((a
->attr
[0].length
== 4 && (!strncasecmp(a
->attr
[0].data
, "ddns", 4) || !strncasecmp(a
->attr
[0].data
, "sndd", 4))) ||
9367 (a
->attr
[1].length
>= mDNSPlatformStrLen(dnsprefix
) && (!strncasecmp(a
->attr
[1].data
, dnsprefix
, mDNSPlatformStrLen(dnsprefix
)))) ||
9368 (a
->attr
[1].length
>= mDNSPlatformStrLen(btmmprefix
) && (!strncasecmp(a
->attr
[1].data
, btmmprefix
, mDNSPlatformStrLen(btmmprefix
)))));
9369 SecKeychainItemFreeAttributesAndData(a
, NULL
);
9374 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
9376 keychainEvent
== kSecAddEvent
? "kSecAddEvent" :
9377 keychainEvent
== kSecDeleteEvent
? "kSecDeleteEvent" :
9378 keychainEvent
== kSecUpdateEvent
? "kSecUpdateEvent" : "<Unknown>");
9379 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
9383 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
9384 // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
9385 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
9387 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
9388 // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
9389 // a one second delay is ok, as we'll still converge to correctness, and there's no race
9390 // condition between the RegistrationDomain and the DomainAuthInfo.
9392 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
9393 // the timer here, as it will not get set by NetworkChanged().
9394 SetKeyChainTimer(m
, mDNSPlatformOneSecond
);
9397 KQueueUnlock(m
, "KeychainChanged");
9407 mDNSlocal
void PowerOn(mDNS
*const m
)
9409 mDNSCoreMachineSleep(m
, false); // Will set m->SleepState = SleepState_Awake;
9411 if (m
->p
->WakeAtUTC
)
9413 long utc
= mDNSPlatformUTC();
9414 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
9415 if (m
->p
->WakeAtUTC
- utc
> 30)
9417 LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m
->p
->WakeAtUTC
- utc
);
9419 else if (utc
- m
->p
->WakeAtUTC
> 30)
9421 LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc
- m
->p
->WakeAtUTC
);
9423 else if (IsAppleTV())
9425 LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc
- m
->p
->WakeAtUTC
);
9429 LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m
->p
->WakeAtUTC
- utc
);
9430 m
->p
->RequestReSleep
= mDNS_TimeNow(m
) + 20 * mDNSPlatformOneSecond
;
9434 // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
9435 // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
9436 // We will clear this assertion as soon as we think the mainenance activities are done.
9437 mDNSPlatformPreventSleep(m
, DARK_WAKE_TIME
, "mDNSResponder:maintenance");
9441 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
9443 mDNS
*const m
= (mDNS
*const)refcon
;
9445 (void)service
; // Parameter not used
9446 debugf("PowerChanged %X %lX", messageType
, messageArgument
);
9448 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
9449 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
9453 case kIOMessageCanSystemPowerOff
: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
9454 case kIOMessageSystemWillPowerOff
: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
9455 mDNSCoreMachineSleep(m
, true);
9456 if (m
->SleepState
== SleepState_Sleeping
) mDNSMacOSXNetworkChanged(m
);
9458 case kIOMessageSystemWillNotPowerOff
: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
9459 case kIOMessageCanSystemSleep
: LogSPS("PowerChanged kIOMessageCanSystemSleep"); break; // E0000270
9460 case kIOMessageSystemWillSleep
: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
9461 mDNSCoreMachineSleep(m
, true);
9463 case kIOMessageSystemWillNotSleep
: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
9464 case kIOMessageSystemHasPoweredOn
: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
9465 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
9468 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m
->SleepState
);
9471 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
9472 // the System Configuration Framework "network changed" event that we expect
9473 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
9475 SetNetworkChanged(m
, mDNSPlatformOneSecond
* 2);
9479 case kIOMessageSystemWillRestart
: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
9480 case kIOMessageSystemWillPowerOn
: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
9482 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
9483 if (m
->SleepState
!= SleepState_Sleeping
)
9485 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m
->SleepState
);
9486 m
->SleepState
= SleepState_Sleeping
;
9487 mDNSMacOSXNetworkChanged(m
);
9491 default: LogSPS("PowerChanged unknown message %X", messageType
); break;
9494 if ((messageType
== kIOMessageSystemWillSleep
) || (messageType
== kIOMessageCanSystemSleep
))
9496 m
->p
->SleepCookie
= (long)messageArgument
;
9497 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
9500 KQueueUnlock(m
, "PowerChanged Sleep/Wake");
9503 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
9504 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
9505 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
9506 mDNSlocal
void SnowLeopardPowerChanged(void *refcon
, IOPMConnection connection
, IOPMConnectionMessageToken token
, IOPMSystemPowerStateCapabilities eventDescriptor
)
9508 mDNS
*const m
= (mDNS
*const)refcon
;
9510 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
9511 connection
, token
, eventDescriptor
,
9512 eventDescriptor
& kIOPMSystemPowerStateCapabilityCPU
? " CPU" : "",
9513 eventDescriptor
& kIOPMSystemPowerStateCapabilityVideo
? " Video" : "",
9514 eventDescriptor
& kIOPMSystemPowerStateCapabilityAudio
? " Audio" : "",
9515 eventDescriptor
& kIOPMSystemPowerStateCapabilityNetwork
? " Network" : "",
9516 eventDescriptor
& kIOPMSystemPowerStateCapabilityDisk
? " Disk" : "");
9518 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
9519 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
9521 if (eventDescriptor
& kIOPMSystemPowerStateCapabilityCPU
)
9523 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
9524 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
9525 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
9526 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
9529 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m
->SleepLimit
, m
->SleepState
);
9530 IOPMConnectionAcknowledgeEvent(connection
, m
->p
->SleepCookie
);
9533 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m
->SleepLimit
, m
->SleepState
);
9534 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
9535 if (m
->SleepState
!= SleepState_Awake
)
9538 // If the network notifications have already come before we got the wakeup, we ignored them and
9539 // in case we get no more, we need to trigger one.
9541 SetNetworkChanged(m
, mDNSPlatformOneSecond
* 2);
9544 IOPMConnectionAcknowledgeEvent(connection
, token
);
9548 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
9549 // we should hear nothing more until we're told that the CPU has started executing again.
9550 if (m
->SleepState
) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor
, m
->SleepState
);
9552 //mDNSMacOSXNetworkChanged(m);
9553 mDNSCoreMachineSleep(m
, true);
9554 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
9555 m
->p
->SleepCookie
= token
;
9558 KQueueUnlock(m
, "SnowLeopardPowerChanged Sleep/Wake");
9562 #if COMPILER_LIKES_PRAGMA_MARK
9564 #pragma mark - /etc/hosts support
9567 // Implementation Notes
9569 // As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
9570 // 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
9571 // them into a hash table. The implementation need to be able to do the following things efficiently
9573 // 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
9574 // 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
9575 // 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
9576 // need to be able set the RRSet of a resource record to the first one in the list and also update when
9577 // one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
9579 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
9581 // CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
9582 // "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
9583 // of the core layer which does all of the above very efficiently
9585 #define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
9587 mDNSexport
void FreeEtcHosts(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
9592 if (result
== mStatus_MemFree
)
9594 LogInfo("FreeEtcHosts: %s", ARDisplayString(m
, rr
));
9595 freeL("etchosts", rr
);
9599 // Returns true on success and false on failure
9600 mDNSlocal mDNSBool
mDNSMacOSXCreateEtcHostsEntry(mDNS
*const m
, const domainname
*domain
, const struct sockaddr
*sa
, const domainname
*cname
, char *ifname
, AuthHash
*auth
)
9606 mDNSInterfaceID InterfaceID
= mDNSInterface_LocalOnly
;
9611 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
9616 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
9620 if (sa
&& sa
->sa_family
!= AF_INET
&& sa
->sa_family
!= AF_INET6
)
9622 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa
->sa_family
);
9629 mDNSu32 ifindex
= if_nametoindex(ifname
);
9632 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain
->c
, ifname
);
9635 InterfaceID
= (mDNSInterfaceID
)(uintptr_t)ifindex
;
9639 rrtype
= (sa
->sa_family
== AF_INET
? kDNSType_A
: kDNSType_AAAA
);
9641 rrtype
= kDNSType_CNAME
;
9643 // Check for duplicates. See whether we parsed an entry before like this ?
9644 slot
= AuthHashSlot(domain
);
9645 namehash
= DomainNameHashValue(domain
);
9646 ag
= AuthGroupForName(auth
, slot
, namehash
, domain
);
9652 if (rr
->resrec
.rrtype
== rrtype
)
9654 if (rrtype
== kDNSType_A
)
9657 ip
.NotAnInteger
= ((struct sockaddr_in
*)sa
)->sin_addr
.s_addr
;
9658 if (mDNSSameIPv4Address(rr
->resrec
.rdata
->u
.ipv4
, ip
))
9660 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain
->c
);
9664 else if (rrtype
== kDNSType_AAAA
)
9667 ip6
.l
[0] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[0];
9668 ip6
.l
[1] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[1];
9669 ip6
.l
[2] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[2];
9670 ip6
.l
[3] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[3];
9671 if (mDNSSameIPv6Address(rr
->resrec
.rdata
->u
.ipv6
, ip6
))
9673 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain
->c
);
9677 else if (rrtype
== kDNSType_CNAME
)
9679 if (SameDomainName(&rr
->resrec
.rdata
->u
.name
, cname
))
9681 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname
->c
, domain
->c
);
9689 rr
= mallocL("etchosts", sizeof(*rr
));
9690 if (rr
== NULL
) return mDNSfalse
;
9691 mDNSPlatformMemZero(rr
, sizeof(*rr
));
9692 mDNS_SetupResourceRecord(rr
, NULL
, InterfaceID
, rrtype
, 1, kDNSRecordTypeKnownUnique
, AuthRecordLocalOnly
, FreeEtcHosts
, NULL
);
9693 AssignDomainName(&rr
->namestorage
, domain
);
9697 rr
->resrec
.rdlength
= sa
->sa_family
== AF_INET
? sizeof(mDNSv4Addr
) : sizeof(mDNSv6Addr
);
9698 if (sa
->sa_family
== AF_INET
)
9699 rr
->resrec
.rdata
->u
.ipv4
.NotAnInteger
= ((struct sockaddr_in
*)sa
)->sin_addr
.s_addr
;
9702 rr
->resrec
.rdata
->u
.ipv6
.l
[0] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[0];
9703 rr
->resrec
.rdata
->u
.ipv6
.l
[1] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[1];
9704 rr
->resrec
.rdata
->u
.ipv6
.l
[2] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[2];
9705 rr
->resrec
.rdata
->u
.ipv6
.l
[3] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[3];
9710 rr
->resrec
.rdlength
= DomainNameLength(cname
);
9711 rr
->resrec
.rdata
->u
.name
.c
[0] = 0;
9712 AssignDomainName(&rr
->resrec
.rdata
->u
.name
, cname
);
9714 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
9715 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
9716 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(m
, rr
));
9717 InsertAuthRecord(m
, auth
, rr
);
9721 mDNSlocal
int EtcHostsParseOneName(int start
, int length
, char *buffer
, char **name
)
9726 for (i
= start
; i
< length
; i
++)
9728 if (buffer
[i
] == '#')
9730 if (buffer
[i
] != ' ' && buffer
[i
] != ',' && buffer
[i
] != '\t')
9734 // Found the start of a name, find the end and null terminate
9735 for (i
++; i
< length
; i
++)
9737 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t')
9749 mDNSlocal
void mDNSMacOSXParseEtcHostsLine(mDNS
*const m
, char *buffer
, ssize_t length
, AuthHash
*auth
)
9753 char *ifname
= NULL
;
9760 //Ignore leading whitespaces and tabs
9761 while (*buffer
== ' ' || *buffer
== '\t')
9767 // Find the end of the address string
9768 for (i
= 0; i
< length
; i
++)
9770 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t' || buffer
[i
] == '%')
9772 if (buffer
[i
] == '%')
9779 // Convert the address string to an address
9780 struct addrinfo hints
;
9781 bzero(&hints
, sizeof(hints
));
9782 hints
.ai_flags
= AI_NUMERICHOST
;
9783 struct addrinfo
*gairesults
= NULL
;
9784 if (getaddrinfo(buffer
, NULL
, &hints
, &gairesults
) != 0)
9786 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
9792 // Parse the interface
9793 ifname
= &buffer
[ifStart
];
9794 for (i
= ifStart
+ 1; i
< length
; i
++)
9796 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t')
9804 i
= EtcHostsParseOneName(i
+ 1, length
, buffer
, &name1
);
9807 // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
9808 if (!MakeDomainNameFromDNSNameString(&name1d
, name1
))
9810 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1
);
9811 freeaddrinfo(gairesults
);
9814 mDNSMacOSXCreateEtcHostsEntry(m
, &name1d
, gairesults
->ai_addr
, mDNSNULL
, ifname
, auth
);
9819 // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
9820 // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
9821 // doing the right thing.
9823 if (!MakeDomainNameFromDNSNameString(&first
, name1
))
9825 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1
);
9826 freeaddrinfo(gairesults
);
9829 mDNSMacOSXCreateEtcHostsEntry(m
, &first
, gairesults
->ai_addr
, mDNSNULL
, ifname
, auth
);
9831 // /etc/hosts alias discussion:
9833 // If the /etc/hosts has an entry like this
9835 // ip_address cname [aliases...]
9836 // 1.2.3.4 sun star bright
9838 // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
9839 // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
9841 // To achieve this, we need to add the entry like this:
9847 // We store the first name we parsed in "first" and add the address (A/AAAA) record.
9848 // Then we parse additional names adding CNAME records till we reach the end.
9853 // Continue to parse additional aliases until we reach end of the line and
9854 // for each "alias" parsed, add a CNAME record where "alias" points to the first "name".
9855 // See also /etc/hosts alias discussion above
9857 i
= EtcHostsParseOneName(i
+ 1, length
, buffer
, &name2
);
9861 if ((aliasIndex
) && (*buffer
== *name2
))
9862 break; // break out of the loop if we wrap around
9864 if (!MakeDomainNameFromDNSNameString(&name2d
, name2
))
9866 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2
);
9867 freeaddrinfo(gairesults
);
9870 // Ignore if it points to itself
9871 if (!SameDomainName(&first
, &name2d
))
9873 if (!mDNSMacOSXCreateEtcHostsEntry(m
, &name2d
, mDNSNULL
, &first
, ifname
, auth
))
9875 freeaddrinfo(gairesults
);
9881 LogInfo("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names first %##s, name2 %##s", first
.c
, name2d
.c
);
9885 else if (!aliasIndex
)
9887 // We have never parsed any aliases. This case happens if there
9888 // is just one name and some extra white spaces at the end.
9889 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first
.c
);
9894 freeaddrinfo(gairesults
);
9897 mDNSlocal
void mDNSMacOSXParseEtcHosts(mDNS
*const m
, int fd
, AuthHash
*auth
)
9900 char buf
[ETCHOSTS_BUFSIZE
];
9904 if (fd
== -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
9906 fp
= fopen("/etc/hosts", "r");
9907 if (!fp
) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
9911 good
= (fgets(buf
, ETCHOSTS_BUFSIZE
, fp
) != NULL
);
9914 // skip comment and empty lines
9915 if (buf
[0] == '#' || buf
[0] == '\r' || buf
[0] == '\n')
9919 if (!len
) break; // sanity check
9920 //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
9921 if (buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
9923 buf
[len
- 1] = '\0';
9926 // fgets always null terminates and hence even if we have no
9927 // newline at the end, it is null terminated. The callee
9928 // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
9929 // buf[length] is zero and hence we decrement len to reflect that.
9932 //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
9933 //here we need to check for just \r but taking extra caution.
9934 if (buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
9936 buf
[len
- 1] = '\0';
9940 if (!len
) //Sanity Check: len should never be zero
9942 LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
9945 mDNSMacOSXParseEtcHostsLine(m
, buf
, len
, auth
);
9950 mDNSlocal
void mDNSMacOSXUpdateEtcHosts(mDNS
*const m
);
9952 mDNSlocal
int mDNSMacOSXGetEtcHostsFD(mDNS
*const m
)
9954 #ifdef __DISPATCH_GROUP__
9955 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9956 static dispatch_queue_t etcq
= 0;
9957 static dispatch_source_t etcsrc
= 0;
9958 static dispatch_source_t hostssrc
= 0;
9960 // First time through? just schedule ourselves on the main queue and we'll do the work later
9963 etcq
= dispatch_get_main_queue();
9966 // Do this work on the queue, not here - solves potential synchronization issues
9967 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
9972 if (hostssrc
) return dispatch_source_get_handle(hostssrc
);
9975 int fd
= open("/etc/hosts", O_RDONLY
);
9977 #ifdef __DISPATCH_GROUP__
9978 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9981 // If the open failed and we're already watching /etc, we're done
9982 if (etcsrc
) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd
; }
9984 // we aren't watching /etc, we should be
9985 fd
= open("/etc", O_RDONLY
);
9986 if (fd
== -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
9987 etcsrc
= dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE
, fd
, DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_WRITE
| DISPATCH_VNODE_RENAME
, etcq
);
9993 dispatch_source_set_event_handler(etcsrc
,
9995 u_int32_t flags
= dispatch_source_get_data(etcsrc
);
9996 LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags
);
9997 if ((flags
& (DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_RENAME
)) != 0)
9999 dispatch_source_cancel(etcsrc
);
10000 dispatch_release(etcsrc
);
10002 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
10005 if ((flags
& DISPATCH_VNODE_WRITE
) != 0 && hostssrc
== NULL
)
10007 mDNSMacOSXUpdateEtcHosts(m
);
10010 dispatch_source_set_cancel_handler(etcsrc
, ^{close(fd
);});
10011 dispatch_resume(etcsrc
);
10013 // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
10014 fd
= open("/etc/hosts", O_RDONLY
| O_EVTONLY
);
10015 if (fd
== -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
10018 // create a dispatch source to watch for changes to hosts file
10019 hostssrc
= dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE
, fd
,
10020 (DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_WRITE
| DISPATCH_VNODE_RENAME
|
10021 DISPATCH_VNODE_ATTRIB
| DISPATCH_VNODE_EXTEND
| DISPATCH_VNODE_LINK
| DISPATCH_VNODE_REVOKE
), etcq
);
10022 if (hostssrc
== NULL
)
10027 dispatch_source_set_event_handler(hostssrc
,
10029 u_int32_t flags
= dispatch_source_get_data(hostssrc
);
10030 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags
);
10031 if ((flags
& (DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_RENAME
)) != 0)
10033 dispatch_source_cancel(hostssrc
);
10034 dispatch_release(hostssrc
);
10036 // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
10037 // the block immediately, we try to open the file and the file may not exist and may
10038 // fail to get a notification in the future. When the file does not exist and
10039 // we start to monitor the directory, on "dispatch_resume" of that source, there
10040 // is no guarantee that the file creation will be notified always because when
10041 // the dispatch_resume returns, the kevent manager may not have registered the
10042 // kevent yet but the file may have been created
10044 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
10047 if ((flags
& DISPATCH_VNODE_WRITE
) != 0)
10049 mDNSMacOSXUpdateEtcHosts(m
);
10052 dispatch_source_set_cancel_handler(hostssrc
, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd
); close(fd
);});
10053 dispatch_resume(hostssrc
);
10055 // Cleanup /etc source, no need to watch it if we already have /etc/hosts
10058 dispatch_source_cancel(etcsrc
);
10059 dispatch_release(etcsrc
);
10063 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
10064 return hostssrc
? (int)dispatch_source_get_handle(hostssrc
) : -1;
10071 // When /etc/hosts is modified, flush all the cache records as there may be local
10072 // authoritative answers now
10073 mDNSlocal
void FlushAllCacheRecords(mDNS
*const m
)
10079 FORALL_CACHERECORDS(slot
, cg
, cr
)
10082 if (cr
->resrec
.InterfaceID
) continue;
10084 // If a resource record can answer A or AAAA, they need to be flushed so that we will
10085 // never used to deliver an ADD or RMV
10086 if (RRTypeAnswersQuestionType(&cr
->resrec
, kDNSType_A
) ||
10087 RRTypeAnswersQuestionType(&cr
->resrec
, kDNSType_AAAA
))
10089 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m
, cr
));
10090 mDNS_PurgeCacheResourceRecord(m
, cr
);
10095 // Add new entries to the core. If justCheck is set, this function does not add, just returns true
10096 mDNSlocal mDNSBool
EtcHostsAddNewEntries(mDNS
*const m
, AuthHash
*newhosts
, mDNSBool justCheck
)
10100 AuthRecord
*rr
, *primary
, *rrnext
;
10101 for (slot
= 0; slot
< AUTH_HASH_SLOTS
; slot
++)
10102 for (ag
= newhosts
->rrauth_hash
[slot
]; ag
; ag
= ag
->next
)
10105 for (rr
= ag
->members
; rr
; rr
= rrnext
)
10110 mDNSBool found
= mDNSfalse
;
10111 ag1
= AuthGroupForRecord(&m
->rrauth
, slot
, &rr
->resrec
);
10112 if (ag1
&& ag1
->members
)
10114 if (!primary
) primary
= ag1
->members
;
10115 rr1
= ag1
->members
;
10118 // We are not using InterfaceID in checking for duplicates. This means,
10119 // if there are two addresses for a given name e.g., fe80::1%en0 and
10120 // fe80::1%en1, we only add the first one. It is not clear whether
10121 // this is a common case. To fix this, we also need to modify
10122 // mDNS_Register_internal in how it handles duplicates. If it becomes a
10123 // common case, we will fix it then.
10124 if (IdenticalResourceRecord(&rr1
->resrec
, &rr
->resrec
))
10126 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m
, rr1
));
10137 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m
, rr
));
10140 RemoveAuthRecord(m
, newhosts
, rr
);
10141 // if there is no primary, point to self
10142 rr
->RRSet
= (primary
? primary
: rr
);
10144 LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m
, rr
));
10145 if (mDNS_Register_internal(m
, rr
) != mStatus_NoError
)
10146 LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m
, rr
));
10153 // Delete entries from the core that are no longer needed. If justCheck is set, this function
10154 // does not delete, just returns true
10155 mDNSlocal mDNSBool
EtcHostsDeleteOldEntries(mDNS
*const m
, AuthHash
*newhosts
, mDNSBool justCheck
)
10159 AuthRecord
*rr
, *rrnext
;
10160 for (slot
= 0; slot
< AUTH_HASH_SLOTS
; slot
++)
10161 for (ag
= m
->rrauth
.rrauth_hash
[slot
]; ag
; ag
= ag
->next
)
10162 for (rr
= ag
->members
; rr
; rr
= rrnext
)
10164 mDNSBool found
= mDNSfalse
;
10168 if (rr
->RecordCallback
!= FreeEtcHosts
) continue;
10169 ag1
= AuthGroupForRecord(newhosts
, slot
, &rr
->resrec
);
10172 rr1
= ag1
->members
;
10175 if (IdenticalResourceRecord(&rr1
->resrec
, &rr
->resrec
))
10177 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m
, rr
));
10184 // there is no corresponding record in newhosts for the same name. This means
10185 // we should delete this from the core.
10190 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m
, rr
));
10193 // if primary is going away, make sure that the rest of the records
10194 // point to the new primary
10195 if (rr
== ag
->members
)
10197 AuthRecord
*new_primary
= rr
->next
;
10198 AuthRecord
*r
= new_primary
;
10201 if (r
->RRSet
== rr
)
10203 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m
, r
));
10204 r
->RRSet
= new_primary
;
10206 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m
, r
), r
->resrec
.name
);
10210 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m
, rr
));
10211 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
10217 mDNSlocal
void UpdateEtcHosts(mDNS
*const m
, void *context
)
10219 AuthHash
*newhosts
= (AuthHash
*)context
;
10223 //Delete old entries from the core if they are not present in the newhosts
10224 EtcHostsDeleteOldEntries(m
, newhosts
, mDNSfalse
);
10225 // Add the new entries to the core if not already present in the core
10226 EtcHostsAddNewEntries(m
, newhosts
, mDNSfalse
);
10229 mDNSlocal
void FreeNewHosts(AuthHash
*newhosts
)
10232 AuthGroup
*ag
, *agnext
;
10233 AuthRecord
*rr
, *rrnext
;
10235 for (slot
= 0; slot
< AUTH_HASH_SLOTS
; slot
++)
10236 for (ag
= newhosts
->rrauth_hash
[slot
]; ag
; ag
= agnext
)
10239 for (rr
= ag
->members
; rr
; rr
= rrnext
)
10242 freeL("etchosts", rr
);
10244 freeL("AuthGroups", ag
);
10248 mDNSlocal
void mDNSMacOSXUpdateEtcHosts(mDNS
*const m
)
10252 // As we will be modifying the core, we can only have one thread running at
10253 // any point in time.
10256 mDNSPlatformMemZero(&newhosts
, sizeof(AuthHash
));
10258 // Get the file desecriptor (will trigger us to start watching for changes)
10259 int fd
= mDNSMacOSXGetEtcHostsFD(m
);
10262 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd
);
10263 mDNSMacOSXParseEtcHosts(m
, fd
, &newhosts
);
10265 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
10267 // Optimization: Detect whether /etc/hosts changed or not.
10269 // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
10270 // newhosts is already registered with core. If we find at least one entry that is not
10271 // registered with core, then it means we have work to do.
10273 // 2. Next, we check to see if any of the entries that are registered with core is not present
10274 // in newhosts. If we find at least one entry that is not present, it means we have work to
10277 // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
10278 // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
10279 // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
10280 // in the future and this code does not have to change.
10282 // Add the new entries to the core if not already present in the core
10283 if (!EtcHostsAddNewEntries(m
, &newhosts
, mDNStrue
))
10285 // No new entries to add, check to see if we need to delete any old entries from the
10286 // core if they are not present in the newhosts
10287 if (!EtcHostsDeleteOldEntries(m
, &newhosts
, mDNStrue
))
10289 LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
10290 FreeNewHosts(&newhosts
);
10292 KQueueUnlock(m
, "/etc/hosts changed");
10297 // This will flush the cache, stop and start the query so that the queries
10298 // can look at the /etc/hosts again
10302 // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
10303 // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
10304 // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
10305 // delivers these events in the right order and then calls us back to delete them.
10307 // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
10308 // is a common function that looks at all local auth records and delivers a RMV including
10309 // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
10310 // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
10311 // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
10312 // is called back where we do the Registration of the record. This results in RMV followed by ADD which
10314 mDNSCoreRestartAddressQueries(m
, mDNSfalse
, FlushAllCacheRecords
, UpdateEtcHosts
, &newhosts
);
10315 FreeNewHosts(&newhosts
);
10317 KQueueUnlock(m
, "/etc/hosts changed");
10320 #if COMPILER_LIKES_PRAGMA_MARK
10322 #pragma mark - Initialization & Teardown
10325 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
10326 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
10327 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
10328 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
10330 // Major version 13 is 10.9.x
10331 mDNSexport
void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
10333 int major
= 0, minor
= 0;
10334 char letter
= 0, prodname
[256]="<Unknown>", prodvers
[256]="<Unknown>", buildver
[256]="<Unknown>";
10335 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
10338 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
10339 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
10340 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
10342 CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
10344 CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
10345 if (cfbuildver
&& CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
))
10346 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
10352 LogMsg("Note: No Major Build Version number found; assuming 13");
10354 if (HINFO_SWstring
)
10355 mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, STRINGIFY(mDNSResponderVersion
));
10356 //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
10358 // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
10359 if ((prodname
[0] & 0xDF) == 'M')
10365 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
10366 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
10367 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
10368 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
10371 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
10373 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
10376 struct sockaddr_in s5353
;
10377 s5353
.sin_family
= AF_INET
;
10378 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
10379 s5353
.sin_addr
.s_addr
= 0;
10380 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
10384 if (err
) LogMsg("No unicast UDP responses");
10385 else debugf("Unicast UDP responses okay");
10389 mDNSlocal
void CreatePTRRecord(mDNS
*const m
, const domainname
*domain
)
10392 const domainname
*pname
= (domainname
*)"\x9" "localhost";
10394 rr
= mallocL("localhosts", sizeof(*rr
));
10395 if (rr
== NULL
) return;
10396 mDNSPlatformMemZero(rr
, sizeof(*rr
));
10398 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, kHostNameTTL
, kDNSRecordTypeKnownUnique
, AuthRecordLocalOnly
, mDNSNULL
, mDNSNULL
);
10399 AssignDomainName(&rr
->namestorage
, domain
);
10401 rr
->resrec
.rdlength
= DomainNameLength(pname
);
10402 rr
->resrec
.rdata
->u
.name
.c
[0] = 0;
10403 AssignDomainName(&rr
->resrec
.rdata
->u
.name
, pname
);
10405 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
10406 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
10407 mDNS_Register(m
, rr
);
10410 // Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
10411 // on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
10412 // fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
10413 // a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
10415 // Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
10416 // intentionally to avoid adding to the complexity of code handling /etc/hosts.
10417 mDNSlocal
void SetupLocalHostRecords(mDNS
*const m
)
10419 char buffer
[MAX_REVERSE_MAPPING_NAME
];
10422 struct in6_addr addr
;
10423 mDNSu8
*ptr
= addr
.__u6_addr
.__u6_addr8
;
10425 if (inet_pton(AF_INET
, "127.0.0.1", &addr
) == 1)
10427 mDNS_snprintf(buffer
, sizeof(buffer
), "%d.%d.%d.%d.in-addr.arpa.",
10428 ptr
[3], ptr
[2], ptr
[1], ptr
[0]);
10429 MakeDomainNameFromDNSNameString(&name
, buffer
);
10430 CreatePTRRecord(m
, &name
);
10432 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET failed");
10434 if (inet_pton(AF_INET6
, "::1", &addr
) == 1)
10436 for (i
= 0; i
< 16; i
++)
10438 static const char hexValues
[] = "0123456789ABCDEF";
10439 buffer
[i
* 4 ] = hexValues
[ptr
[15 - i
] & 0x0F];
10440 buffer
[i
* 4 + 1] = '.';
10441 buffer
[i
* 4 + 2] = hexValues
[ptr
[15 - i
] >> 4];
10442 buffer
[i
* 4 + 3] = '.';
10444 mDNS_snprintf(&buffer
[64], sizeof(buffer
)-64, "ip6.arpa.");
10445 MakeDomainNameFromDNSNameString(&name
, buffer
);
10446 CreatePTRRecord(m
, &name
);
10448 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET6 failed");
10451 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
10452 // 1) query for b._dns-sd._udp.local on LocalOnly interface
10453 // (.local manually generated via explicit callback)
10454 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
10455 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
10456 // 4) result above should generate a callback from question in (1). result added to global list
10457 // 5) global list delivered to client via GetSearchDomainList()
10458 // 6) client calls to enumerate domains now go over LocalOnly interface
10459 // (!!!KRS may add outgoing interface in addition)
10461 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
10465 char HINFO_SWstring
[256] = "";
10466 mDNSMacOSXSystemBuildNumber(HINFO_SWstring
);
10468 err
= mDNSHelperInit();
10472 // Store mDNSResponder Platform
10475 m
->mDNS_plat
= platform_OSX
;
10480 m
->mDNS_plat
= platform_Atv
;
10482 m
->mDNS_plat
= platform_iOS
;
10486 m
->mDNS_plat
= platform_NonApple
;
10489 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
10490 // 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.
10492 for (i
=0; i
<100; i
++)
10494 domainlabel testlabel
;
10495 testlabel
.c
[0] = 0;
10496 GetUserSpecifiedLocalHostName(&testlabel
);
10497 if (testlabel
.c
[0]) break;
10501 m
->hostlabel
.c
[0] = 0;
10503 int get_model
[2] = { CTL_HW
, HW_MODEL
};
10504 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
10506 // Normal Apple model names are of the form "iPhone2,1", and
10507 // internal code names are strings containing no commas, e.g. "N88AP".
10508 // We used to ignore internal code names, but Apple now uses these internal code names
10509 // even in released shipping products, so we no longer ignore strings containing no commas.
10510 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
10511 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
10512 HINFO_HWstring
= HINFO_HWstring_buffer
;
10514 // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
10515 // For names of the form "N88AP" containg no comma, we use the entire string.
10516 HINFO_HWstring_prefixlen
= strchr(HINFO_HWstring_buffer
, ',') ? strcspn(HINFO_HWstring
, "0123456789") : strlen(HINFO_HWstring
);
10518 if (mDNSPlatformInit_CanReceiveUnicast())
10519 m
->CanReceiveUnicastOn5353
= mDNStrue
;
10521 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
10522 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
10523 if (hlen
+ slen
< 254)
10525 m
->HIHardware
.c
[0] = hlen
;
10526 m
->HISoftware
.c
[0] = slen
;
10527 mDNSPlatformMemCopy(&m
->HIHardware
.c
[1], HINFO_HWstring
, hlen
);
10528 mDNSPlatformMemCopy(&m
->HISoftware
.c
[1], HINFO_SWstring
, slen
);
10531 m
->p
->permanentsockets
.port
= MulticastDNSPort
;
10532 m
->p
->permanentsockets
.m
= m
;
10533 m
->p
->permanentsockets
.sktv4
= -1;
10534 m
->p
->permanentsockets
.kqsv4
.KQcallback
= myKQSocketCallBack
;
10535 m
->p
->permanentsockets
.kqsv4
.KQcontext
= &m
->p
->permanentsockets
;
10536 m
->p
->permanentsockets
.kqsv4
.KQtask
= "IPv4 UDP packet reception";
10537 m
->p
->permanentsockets
.sktv6
= -1;
10538 m
->p
->permanentsockets
.kqsv6
.KQcallback
= myKQSocketCallBack
;
10539 m
->p
->permanentsockets
.kqsv6
.KQcontext
= &m
->p
->permanentsockets
;
10540 m
->p
->permanentsockets
.kqsv6
.KQtask
= "IPv6 UDP packet reception";
10542 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET
, mDNSNULL
);
10543 if (err
) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET) failed error %d errno %d (%s)", err
, errno
, strerror(errno
));
10544 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET6
, mDNSNULL
);
10545 if (err
) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET6) failed error %d errno %d (%s)", err
, errno
, strerror(errno
));
10547 struct sockaddr_in s4
;
10548 socklen_t n4
= sizeof(s4
);
10549 if (getsockname(m
->p
->permanentsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0)
10550 LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
10552 m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
10554 if (m
->p
->permanentsockets
.sktv6
>= 0)
10556 struct sockaddr_in6 s6
;
10557 socklen_t n6
= sizeof(s6
);
10558 if (getsockname(m
->p
->permanentsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
10559 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
10562 m
->p
->InterfaceList
= mDNSNULL
;
10563 m
->p
->userhostlabel
.c
[0] = 0;
10564 m
->p
->usernicelabel
.c
[0] = 0;
10565 m
->p
->prevoldnicelabel
.c
[0] = 0;
10566 m
->p
->prevnewnicelabel
.c
[0] = 0;
10567 m
->p
->prevoldhostlabel
.c
[0] = 0;
10568 m
->p
->prevnewhostlabel
.c
[0] = 0;
10569 m
->p
->NotifyUser
= 0;
10570 m
->p
->KeyChainTimer
= 0;
10571 m
->p
->WakeAtUTC
= 0;
10572 m
->p
->RequestReSleep
= 0;
10573 // Assume that everything is good to begin with. If something is not working,
10574 // we will detect that when we start sending questions.
10575 m
->p
->v4answers
= 1;
10576 m
->p
->v6answers
= 1;
10577 m
->p
->DNSTrigger
= 0;
10578 m
->p
->LastConfigGeneration
= 0;
10580 #if APPLE_OSX_mDNSResponder
10581 uuid_generate(m
->asl_uuid
);
10584 m
->AutoTunnelRelayAddr
= zerov6Addr
;
10586 NetworkChangedKey_IPv4
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
10587 NetworkChangedKey_IPv6
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
10588 NetworkChangedKey_Hostnames
= SCDynamicStoreKeyCreateHostNames(NULL
);
10589 NetworkChangedKey_Computername
= SCDynamicStoreKeyCreateComputerName(NULL
);
10590 NetworkChangedKey_DNS
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
10591 NetworkChangedKey_StateInterfacePrefix
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, CFSTR(""), NULL
);
10592 if (!NetworkChangedKey_IPv4
|| !NetworkChangedKey_IPv6
|| !NetworkChangedKey_Hostnames
|| !NetworkChangedKey_Computername
|| !NetworkChangedKey_DNS
|| !NetworkChangedKey_StateInterfacePrefix
)
10593 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr
); }
10595 err
= WatchForNetworkChanges(m
);
10596 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err
); return(err
); }
10598 err
= WatchForSysEvents(m
);
10599 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err
); return(err
); }
10601 mDNSs32 utc
= mDNSPlatformUTC();
10602 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
10604 UpdateInterfaceList(m
, utc
);
10605 SetupActiveInterfaces(m
, utc
);
10607 // Explicitly ensure that our Keychain operations utilize the system domain.
10608 #ifndef NO_SECURITYFRAMEWORK
10609 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
10613 SetDomainSecrets(m
);
10617 #ifndef NO_SECURITYFRAMEWORK
10618 err
= SecKeychainAddCallback(KeychainChanged
, kSecAddEventMask
|kSecDeleteEventMask
|kSecUpdateEventMask
, m
);
10619 if (err
) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err
); return(err
); }
10622 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
10623 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
10626 IOReturn iopmerr
= IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU
, &c
);
10627 if (iopmerr
) LogMsg("IOPMConnectionCreate failed %d", iopmerr
);
10630 iopmerr
= IOPMConnectionSetNotification(c
, m
, SnowLeopardPowerChanged
);
10631 if (iopmerr
) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr
);
10634 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10635 IOPMConnectionSetDispatchQueue(c
, dispatch_get_main_queue());
10636 LogInfo("IOPMConnectionSetDispatchQueue is now running");
10638 iopmerr
= IOPMConnectionScheduleWithRunLoop(c
, CFRunLoopGetMain(), kCFRunLoopDefaultMode
);
10639 if (iopmerr
) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr
);
10640 LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
10641 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
10644 m
->p
->IOPMConnection
= iopmerr
? mDNSNULL
: c
;
10645 if (iopmerr
) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
10646 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
10648 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &m
->p
->PowerPortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
10649 if (!m
->p
->PowerConnection
) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
10652 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10653 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, dispatch_get_main_queue());
10655 CFRunLoopAddSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
10656 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
10660 #if APPLE_OSX_mDNSResponder
10661 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
10662 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
10663 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
10664 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
10665 if (!strncasecmp(HINFO_HWstring
, "Xserve", 6)) { SPMetricPortability
= 25 /* 30kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
10666 else if (!strncasecmp(HINFO_HWstring
, "RackMac", 7)) { SPMetricPortability
= 25 /* 30kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
10667 else if (!strncasecmp(HINFO_HWstring
, "MacPro", 6)) { SPMetricPortability
= 27 /* 20kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
10668 else if (!strncasecmp(HINFO_HWstring
, "PowerMac", 8)) { SPMetricPortability
= 27 /* 20kg */; SPMetricMarginalPower
= 82 /* 160W */; SPMetricTotalPower
= 83 /* 200W */; }
10669 else if (!strncasecmp(HINFO_HWstring
, "iMac", 4)) { SPMetricPortability
= 30 /* 10kg */; SPMetricMarginalPower
= 77 /* 50W */; SPMetricTotalPower
= 78 /* 60W */; }
10670 else if (!strncasecmp(HINFO_HWstring
, "Macmini", 7)) { SPMetricPortability
= 33 /* 5kg */; SPMetricMarginalPower
= 73 /* 20W */; SPMetricTotalPower
= 74 /* 25W */; }
10671 else if (!strncasecmp(HINFO_HWstring
, "TimeCapsule", 11)) { SPMetricPortability
= 34 /* 4kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 70 /* 13W */; }
10672 else if (!strncasecmp(HINFO_HWstring
, "AirPort", 7)) { SPMetricPortability
= 35 /* 3kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 70 /* 12W */; }
10673 else if ( IsAppleTV() ) { SPMetricPortability
= 35 /* 3kg */; SPMetricMarginalPower
= 60 /* 1W */; SPMetricTotalPower
= 63 /* 2W */; }
10674 else if (!strncasecmp(HINFO_HWstring
, "MacBook", 7)) { SPMetricPortability
= 37 /* 2kg */; SPMetricMarginalPower
= 71 /* 13W */; SPMetricTotalPower
= 72 /* 15W */; }
10675 else if (!strncasecmp(HINFO_HWstring
, "PowerBook", 9)) { SPMetricPortability
= 37 /* 2kg */; SPMetricMarginalPower
= 71 /* 13W */; SPMetricTotalPower
= 72 /* 15W */; }
10676 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
10677 HINFO_HWstring_prefixlen
, HINFO_HWstring
, HINFO_HWstring
, SPMetricPortability
, SPMetricMarginalPower
, SPMetricTotalPower
, SPMetricFeatures
);
10678 #endif // APPLE_OSX_mDNSResponder
10680 // Currently this is not defined. SSL code will eventually fix this. If it becomes
10681 // critical, we will define this to workaround the bug in SSL.
10682 #ifdef __SSL_NEEDS_SERIALIZATION__
10683 SSLqueue
= dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL
);
10685 SSLqueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
10687 if (SSLqueue
== mDNSNULL
) LogMsg("dispatch_queue_create: SSL queue NULL");
10689 mDNSMacOSXUpdateEtcHosts(m
);
10690 SetupLocalHostRecords(m
);
10692 return(mStatus_NoError
);
10695 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
10697 #if MDNS_NO_DNSINFO
10698 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
10701 // Adding interfaces will use this flag, so set it now.
10702 m
->DivertMulticastAdvertisements
= !m
->AdvertiseLocalAddresses
;
10704 #if APPLE_OSX_mDNSResponder
10705 m
->SPSBrowseCallback
= UpdateSPSStatus
;
10706 #endif // APPLE_OSX_mDNSResponder
10708 mStatus result
= mDNSPlatformInit_setup(m
);
10710 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
10711 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
10712 if (result
== mStatus_NoError
)
10714 mDNSCoreInitComplete(m
, mStatus_NoError
);
10717 // We only initialize if mDNSCore successfully initialized.
10720 D2DStatus ds
= D2DInitialize(CFRunLoopGetMain(), xD2DServiceCallback
, m
) ;
10721 if (ds
!= kD2DSuccess
)
10722 LogMsg("D2DInitialiize failed: %d", ds
);
10724 LogMsg("D2DInitialize succeeded");
10729 result
= DNSSECCryptoInit(m
);
10733 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
10735 if (m
->p
->PowerConnection
)
10737 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10738 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, NULL
);
10740 CFRunLoopRemoveSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
10742 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
10743 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
10744 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
10745 IOServiceClose ( m
->p
->PowerConnection
);
10746 IONotificationPortDestroy ( m
->p
->PowerPortRef
);
10747 m
->p
->PowerConnection
= 0;
10752 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10753 if (!SCDynamicStoreSetDispatchQueue(m
->p
->Store
, NULL
))
10754 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
10756 CFRunLoopRemoveSource(CFRunLoopGetMain(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
10757 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
10758 CFRelease(m
->p
->StoreRLS
);
10759 m
->p
->StoreRLS
= NULL
;
10761 CFRelease(m
->p
->Store
);
10762 m
->p
->Store
= NULL
;
10767 CFRunLoopRemoveSource(CFRunLoopGetMain(), m
->p
->PMRLS
, kCFRunLoopDefaultMode
);
10768 CFRunLoopSourceInvalidate(m
->p
->PMRLS
);
10769 CFRelease(m
->p
->PMRLS
);
10770 m
->p
->PMRLS
= NULL
;
10773 if (m
->p
->SysEventNotifier
>= 0) { close(m
->p
->SysEventNotifier
); m
->p
->SysEventNotifier
= -1; }
10778 D2DStatus ds
= D2DTerminate();
10779 if (ds
!= kD2DSuccess
)
10780 LogMsg("D2DTerminate failed: %d", ds
);
10782 LogMsg("D2DTerminate succeeded");
10786 mDNSs32 utc
= mDNSPlatformUTC();
10787 MarkAllInterfacesInactive(m
, utc
);
10788 ClearInactiveInterfaces(m
, utc
);
10789 CloseSocketSet(&m
->p
->permanentsockets
);
10791 #if APPLE_OSX_mDNSResponder
10792 // clean up tunnels
10793 while (m
->TunnelClients
)
10795 ClientTunnel
*cur
= m
->TunnelClients
;
10796 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur
, cur
->dstname
.c
);
10797 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
10798 AutoTunnelSetKeys(cur
, mDNSfalse
);
10799 m
->TunnelClients
= cur
->next
;
10800 freeL("ClientTunnel", cur
);
10803 if (AnonymousRacoonConfig
)
10805 AnonymousRacoonConfig
= mDNSNULL
;
10806 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel need not be done in mDNSResponder");
10808 #endif // APPLE_OSX_mDNSResponder
10811 #if COMPILER_LIKES_PRAGMA_MARK
10813 #pragma mark - General Platform Support Layer functions
10816 mDNSexport mDNSu32
mDNSPlatformRandomNumber(void)
10818 return(arc4random());
10821 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
10822 mDNSexport mDNSu32 mDNSPlatformClockDivisor
= 0;
10824 mDNSexport mStatus
mDNSPlatformTimeInit(void)
10826 // Notes: Typical values for mach_timebase_info:
10827 // tbi.numer = 1000 million
10828 // tbi.denom = 33 million
10829 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
10830 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
10831 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
10832 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
10833 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
10835 // Arithmetic notes:
10836 // tbi.denom is at least 1, and not more than 2^32-1.
10837 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
10838 // tbi.denom is at least 1, and not more than 2^32-1.
10839 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
10840 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
10841 // which is unlikely on any current or future Macintosh.
10842 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
10843 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
10844 struct mach_timebase_info tbi
;
10845 kern_return_t result
= mach_timebase_info(&tbi
);
10846 if (result
== KERN_SUCCESS
) mDNSPlatformClockDivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
10850 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
10852 if (mDNSPlatformClockDivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
10854 static uint64_t last_mach_absolute_time
= 0;
10855 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
10856 uint64_t this_mach_absolute_time
= mach_absolute_time();
10857 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
10859 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
10860 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
10861 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
10862 last_mach_absolute_time
= this_mach_absolute_time
;
10863 // Note: This bug happens all the time on 10.3
10864 NotifyOfElusiveBug("mach_absolute_time went backwards!",
10865 "This error occurs from time to time, often on newly released hardware, "
10866 "and usually the exact cause is different in each instance.\r\r"
10867 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
10868 "and assign it to Radar Component “Kernel” Version “X”.");
10870 last_mach_absolute_time
= this_mach_absolute_time
;
10872 return((mDNSs32
)(this_mach_absolute_time
/ mDNSPlatformClockDivisor
));
10875 mDNSexport mDNSs32
mDNSPlatformUTC(void)
10880 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
10881 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
10882 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
10883 mDNSexport
void mDNSPlatformStrCopy( void *dst
, const void *src
) { strcpy((char *)dst
, (const char *)src
); }
10884 mDNSexport mDNSu32
mDNSPlatformStrLCopy( void *dst
, const void *src
, mDNSu32 dstlen
) { return (strlcpy((char *)dst
, (const char *)src
, dstlen
)); }
10885 mDNSexport mDNSu32
mDNSPlatformStrLen ( const void *src
) { return(strlen((const char*)src
)); }
10886 mDNSexport
void mDNSPlatformMemCopy( void *dst
, const void *src
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
10887 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *dst
, const void *src
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
10888 mDNSexport
int mDNSPlatformMemCmp(const void *dst
, const void *src
, mDNSu32 len
) { return(memcmp(dst
, src
, len
)); }
10889 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { memset(dst
, 0, len
); }
10890 mDNSexport
void mDNSPlatformQsort ( void *base
, int nel
, int width
, int (*compar
)(const void *, const void *))
10892 return (qsort(base
, nel
, width
, compar
));
10894 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
10895 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
10897 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }
10899 mDNSexport
void mDNSPlatformSetAllowSleep(mDNS
*const m
, mDNSBool allowSleep
, const char *reason
)
10901 if (allowSleep
&& m
->p
->IOPMAssertion
)
10903 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__
);
10904 IOPMAssertionRelease(m
->p
->IOPMAssertion
);
10905 m
->p
->IOPMAssertion
= 0;
10907 else if (!allowSleep
)
10909 #ifdef kIOPMAssertionTypeNoIdleSleep
10910 if (m
->p
->IOPMAssertion
)
10912 IOPMAssertionRelease(m
->p
->IOPMAssertion
);
10913 m
->p
->IOPMAssertion
= 0;
10916 CFStringRef assertionName
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s.%d %s"), getprogname(), getpid(), reason
? reason
: "");
10917 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep
, kIOPMAssertionLevelOn
, assertionName
? assertionName
: CFSTR("mDNSResponder"), &m
->p
->IOPMAssertion
);
10918 if (assertionName
) CFRelease(assertionName
);
10919 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__
);
10924 mDNSexport
void mDNSPlatformPreventSleep(mDNS
*const m
, mDNSu32 timeout
, const char *reason
)
10926 if (m
->p
->IOPMAssertion
)
10928 LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout
, reason
);
10931 #ifdef kIOPMAssertionTypeNoIdleSleep
10933 #if TARGET_OS_EMBEDDED
10935 return; // No need for maintenance wakes on non-AppleTV embedded devices.
10938 double timeoutVal
= (double)timeout
;
10939 CFStringRef str
= CFStringCreateWithCString(NULL
, reason
, kCFStringEncodingUTF8
);
10940 CFNumberRef Timeout_num
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &timeoutVal
);
10941 CFMutableDictionaryRef assertionProperties
= CFDictionaryCreateMutable(NULL
, 0,
10942 &kCFTypeDictionaryKeyCallBacks
,
10943 &kCFTypeDictionaryValueCallBacks
);
10945 CFDictionarySetValue(assertionProperties
, kIOPMAssertionTypeKey
, kIOPMAssertPreventUserIdleSystemSleep
);
10947 CFDictionarySetValue(assertionProperties
, kIOPMAssertionTypeKey
, kIOPMAssertMaintenanceActivity
);
10949 CFDictionarySetValue(assertionProperties
, kIOPMAssertionTimeoutKey
, Timeout_num
);
10950 CFDictionarySetValue(assertionProperties
, kIOPMAssertionNameKey
, str
);
10952 IOPMAssertionCreateWithProperties(assertionProperties
, (IOPMAssertionID
*)&m
->p
->IOPMAssertion
);
10954 CFRelease(Timeout_num
);
10955 CFRelease(assertionProperties
);
10956 LogSPS("Got an idle sleep assertion for %d seconds for %s", timeout
, reason
);
10960 mDNSexport
void mDNSPlatformSendWakeupPacket(mDNS
*const m
, mDNSInterfaceID InterfaceID
, char *EthAddr
, char *IPAddr
, int iteration
)
10965 ifindex
= mDNSPlatformInterfaceIndexfromInterfaceID(m
, InterfaceID
, mDNStrue
);
10968 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex
);
10971 mDNSSendWakeupPacket(ifindex
, EthAddr
, IPAddr
, iteration
);
10974 mDNSexport mDNSBool
mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID
)
10976 NetworkInterfaceInfoOSX
*info
;
10978 if (InterfaceID
== mDNSInterface_P2P
)
10981 // mDNSInterface_BLE not considered a D2D interface for the purpose of this
10982 // routine, since it's not implemented via a D2D plugin.
10983 if (InterfaceID
== mDNSInterface_BLE
)
10986 if ( (InterfaceID
== mDNSInterface_Any
)
10987 || (InterfaceID
== mDNSInterfaceMark
)
10988 || (InterfaceID
== mDNSInterface_LocalOnly
)
10989 || (InterfaceID
== mDNSInterface_Unicast
))
10992 // Compare to cached AWDL interface ID.
10993 if (AWDLInterfaceID
&& (InterfaceID
== AWDLInterfaceID
))
10996 info
= IfindexToInterfaceInfoOSX(&mDNSStorage
, InterfaceID
);
10999 // this log message can print when operations are stopped on an interface that has gone away
11000 LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID
);
11004 return (mDNSBool
) info
->D2DInterface
;
11007 // Filter records send over P2P (D2D) type interfaces
11008 // Note that the terms P2P and D2D are used synonymously in the current code and comments.
11009 mDNSexport mDNSBool
mDNSPlatformValidRecordForInterface(const AuthRecord
*rr
, mDNSInterfaceID InterfaceID
)
11011 // For an explicit match to a valid interface ID, return true.
11012 if (rr
->resrec
.InterfaceID
== InterfaceID
)
11015 // Only filtering records for D2D type interfaces, return true for all other interface types.
11016 if (!mDNSPlatformInterfaceIsD2D(InterfaceID
))
11019 // If it's an AWDL interface the record must be explicitly marked to include AWDL.
11020 if (InterfaceID
== AWDLInterfaceID
)
11022 if (rr
->ARType
== AuthRecordAnyIncludeAWDL
|| rr
->ARType
== AuthRecordAnyIncludeAWDLandP2P
)
11028 // Send record if it is explicitly marked to include all other P2P type interfaces.
11029 if (rr
->ARType
== AuthRecordAnyIncludeP2P
|| rr
->ARType
== AuthRecordAnyIncludeAWDLandP2P
)
11032 // Don't send the record over this interface.
11036 // Filter questions send over P2P (D2D) type interfaces.
11037 mDNSexport mDNSBool
mDNSPlatformValidQuestionForInterface(DNSQuestion
*q
, const NetworkInterfaceInfo
*intf
)
11039 // For an explicit match to a valid interface ID, return true.
11040 if (q
->InterfaceID
== intf
->InterfaceID
)
11043 // Only filtering questions for D2D type interfaces
11044 if (!mDNSPlatformInterfaceIsD2D(intf
->InterfaceID
))
11047 // If it's an AWDL interface the question must be explicitly marked to include AWDL.
11048 if (intf
->InterfaceID
== AWDLInterfaceID
)
11050 if (q
->flags
& kDNSServiceFlagsIncludeAWDL
)
11056 // Sent question if it is explicitly marked to include all other P2P type interfaces.
11057 if (q
->flags
& kDNSServiceFlagsIncludeP2P
)
11060 // Don't send the question over this interface.
11064 // Returns true unless record was received over the AWDL interface and
11065 // the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
11066 // with the kDNSServiceFlagsIncludeAWDL flag set.
11067 mDNSexport mDNSBool
mDNSPlatformValidRecordForQuestion(const ResourceRecord
*const rr
, const DNSQuestion
*const q
)
11069 if (!rr
->InterfaceID
|| (rr
->InterfaceID
== q
->InterfaceID
))
11072 if ((rr
->InterfaceID
== AWDLInterfaceID
) && !(q
->flags
& kDNSServiceFlagsIncludeAWDL
))
11078 // formating time to RFC 4034 format
11079 mDNSexport
void mDNSPlatformFormatTime(unsigned long te
, mDNSu8
*buf
, int bufsize
)
11082 time_t t
= (time_t)te
;
11083 // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
11084 // gmtime_r first and then use strftime
11085 gmtime_r(&t
, &tmTime
);
11086 strftime((char *)buf
, bufsize
, "%Y%m%d%H%M%S", &tmTime
);
11089 mDNSexport mDNSs32
mDNSPlatformGetPID()
11094 // Schedule a function asynchronously on the main queue
11095 mDNSexport
void mDNSPlatformDispatchAsync(mDNS
*const m
, void *context
, AsyncDispatchFunc func
)
11097 // KQueueLock/Unlock is used for two purposes
11099 // 1. We can't be running along with the KQueue thread and hence acquiring the lock
11100 // serializes the access to the "core"
11102 // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
11103 // up and calls udsserver_idle which schedules the messages across the uds socket.
11104 // If "func" delivers something to the uds socket from the dispatch thread, it will
11105 // not be delivered immediately if not for the Unlock.
11106 dispatch_async(dispatch_get_main_queue(), ^{
11109 KQueueUnlock(m
, "mDNSPlatformDispatchAsync");
11110 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
11111 // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
11112 // to handle any message that "func" might deliver.
11113 TriggerEventCompletion();
11118 // definitions for device-info record construction
11119 #define DEVINFO_MODEL "model="
11120 #define DEVINFO_MODEL_LEN sizeof_string(DEVINFO_MODEL)
11122 #define OSX_VER "osxvers="
11123 #define OSX_VER_LEN sizeof_string(OSX_VER)
11124 #define VER_NUM_LEN 2 // 2 digits of version number added to base string
11126 #define MODEL_COLOR "ecolor="
11127 #define MODEL_COLOR_LEN sizeof_string(MODEL_COLOR)
11128 #define MODEL_RGB_VALUE_LEN sizeof_string("255,255,255") // 'r,g,b'
11130 // Bytes available in TXT record for model name after subtracting space for other
11131 // fixed size strings and their length bytes.
11132 #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))
11134 mDNSlocal mDNSu8
getModelIconColors(char *color
)
11136 mDNSPlatformMemZero(color
, MODEL_RGB_VALUE_LEN
+ 1);
11138 #if !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
11143 IOReturn rGetDeviceColor
= IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey
,
11144 &red
, &green
, &blue
);
11145 if (kIOReturnSuccess
== rGetDeviceColor
)
11147 // IOKit was able to get enclosure color for the current device.
11148 return snprintf(color
, MODEL_RGB_VALUE_LEN
+ 1, "%d,%d,%d", red
, green
, blue
);
11150 #endif // !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
11156 // Initialize device-info TXT record contents and return total length of record data.
11157 mDNSexport mDNSu32
initializeDeviceInfoTXT(mDNS
*m
, mDNSu8
*ptr
)
11159 mDNSu8
*bufferStart
= ptr
;
11160 mDNSu8 len
= m
->HIHardware
.c
[0] < MAX_MODEL_NAME_LEN
? m
->HIHardware
.c
[0] : MAX_MODEL_NAME_LEN
;
11162 *ptr
= DEVINFO_MODEL_LEN
+ len
; // total length of DEVINFO_MODEL string plus the hardware name string
11164 mDNSPlatformMemCopy(ptr
, DEVINFO_MODEL
, DEVINFO_MODEL_LEN
);
11165 ptr
+= DEVINFO_MODEL_LEN
;
11166 mDNSPlatformMemCopy(ptr
, m
->HIHardware
.c
+ 1, len
);
11169 // only include this string for OSX
11172 char ver_num
[VER_NUM_LEN
+ 1]; // version digits + null written by snprintf
11173 *ptr
= OSX_VER_LEN
+ VER_NUM_LEN
; // length byte
11175 mDNSPlatformMemCopy(ptr
, OSX_VER
, OSX_VER_LEN
);
11176 ptr
+= OSX_VER_LEN
;
11177 // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
11178 // WARNING: This code assumes that OSXVers is always exactly two digits
11179 snprintf(ver_num
, VER_NUM_LEN
+ 1, "%d", OSXVers
);
11180 mDNSPlatformMemCopy(ptr
, ver_num
, VER_NUM_LEN
);
11181 ptr
+= VER_NUM_LEN
;
11183 char rgb
[MODEL_RGB_VALUE_LEN
+ 1]; // RGB value + null written by snprintf
11184 len
= getModelIconColors(rgb
);
11187 *ptr
= MODEL_COLOR_LEN
+ len
; // length byte
11190 mDNSPlatformMemCopy(ptr
, MODEL_COLOR
, MODEL_COLOR_LEN
);
11191 ptr
+= MODEL_COLOR_LEN
;
11193 mDNSPlatformMemCopy(ptr
, rgb
, len
);
11198 return (ptr
- bufferStart
);