1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, 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 // For enabling AAAA records over IPv4. Setting this to 0 sends only
28 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
29 // AAAA and A records over both IPv4 and IPv6.
30 #define AAAA_OVER_V4 1
32 // In Mac OS X 10.4 and earlier, to reduce traffic, we would send and receive using IPv6 only on interfaces that had no routable
33 // IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
34 // which means there's a good chance that most or all the other devices on that network should also have IPv4.
35 // By doing this we lost the ability to talk to true IPv6-only devices on that link, but we cut the packet rate in half.
36 // At that time, reducing the packet rate was more important than v6-only devices on a large configured network,
37 // so were willing to make that sacrifice.
38 // In Mac OS X 10.5, in 2007, two things have changed:
39 // 1. IPv6-only devices are starting to become more common, so we can't ignore them.
40 // 2. Other efficiency improvements in the code mean that crude hacks like this should no longer be necessary.
42 #define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
44 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
45 #include "DNSCommon.h"
47 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
48 #include "dns_sd.h" // For mDNSInterface_LocalOnly etc.
49 #include "PlatformCommon.h"
50 #include "uds_daemon.h"
51 #include <CoreServices/CoreServices.h>
54 #include <stdarg.h> // For va_list support
55 #include <stdlib.h> // For arc4random
57 #include <net/if_types.h> // For IFT_ETHER
58 #include <net/if_dl.h>
59 #include <net/bpf.h> // For BIOCSETIF etc.
61 #include <sys/param.h>
62 #include <sys/socket.h>
63 #include <sys/sysctl.h>
64 #include <sys/event.h>
66 #include <sys/ioctl.h>
67 #include <time.h> // platform support for UTC time
68 #include <arpa/inet.h> // for inet_aton
71 #include <netinet/in.h> // For IP_RECVTTL
73 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
76 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
77 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
78 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
79 #include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
81 #if TARGET_OS_EMBEDDED
82 #define NO_SECURITYFRAMEWORK 1
83 #define NO_CFUSERNOTIFICATION 1
86 #ifndef NO_SECURITYFRAMEWORK
87 #include <Security/SecureTransport.h>
88 #include <Security/Security.h>
89 #endif /* NO_SECURITYFRAMEWORK */
91 #include <DebugServices.h>
94 // Code contributed by Dave Heller:
95 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
96 // work on Mac OS X 10.1, which does not have the getifaddrs call.
97 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
98 #if RUN_ON_PUMA_WITHOUT_IFADDRS
99 #include "mDNSMacOSXPuma.c"
104 #include <IOKit/IOKitLib.h>
105 #include <IOKit/IOMessage.h>
107 #ifdef __LIB_DISPATCH__
108 // This is currently defined in IOKit/PrivateHeaders/IOKitLibPrivate.h. Till it becomes an Public
109 // API, we will have our own declaration
110 void IONotificationPortSetDispatchQueue(IONotificationPortRef notify
, dispatch_queue_t queue
);
113 #if USE_IOPMCOPYACTIVEPMPREFERENCES
114 #include <IOKit/ps/IOPowerSources.h>
115 #include <IOKit/ps/IOPowerSourcesPrivate.h>
118 #include <mach/mach_error.h>
119 #include <mach/mach_port.h>
120 #include <mach/mach_time.h>
125 #if APPLE_OSX_mDNSResponder
126 #include <DeviceToDeviceManager/DeviceToDeviceManager.h>
130 D2DStatus
D2DInitialize(CFRunLoopRef runLoop
, D2DServiceCallback serviceCallback
, void* userData
) __attribute__((weak_import
));
131 D2DStatus
D2DTerminate() __attribute__((weak_import
));
132 D2DStatus
D2DStartAdvertisingPair(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
) __attribute__((weak_import
));
133 D2DStatus
D2DStopAdvertisingPair(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
) __attribute__((weak_import
));
134 D2DStatus
D2DStartBrowsingForKey(const Byte
*key
, const size_t keySize
) __attribute__((weak_import
));
135 D2DStatus
D2DStopBrowsingForKey(const Byte
*key
, const size_t keySize
) __attribute__((weak_import
));
136 void D2DStartResolvingPair(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
) __attribute__((weak_import
));
137 void D2DStopResolvingPair(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
) __attribute__((weak_import
));
138 D2DStatus
D2DRetain(D2DServiceInstance instanceHandle
, D2DTransportType transportType
) __attribute__((weak_import
));
139 D2DStatus
D2DRelease(D2DServiceInstance instanceHandle
, D2DTransportType transportType
) __attribute__((weak_import
));
141 #define CHECK_D2D_FUNCTION(X) if (X)
148 #endif // APPLE_OSX_mDNSResponder
150 #define kInterfaceSpecificOption "interface="
152 // ***************************************************************************
155 #if COMPILER_LIKES_PRAGMA_MARK
156 #pragma mark - Globals
159 // By default we don't offer sleep proxy service
160 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
161 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
162 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
163 mDNSexport
int OfferSleepProxyService
= 0;
164 mDNSexport
int DisableSleepProxyClient
= 0;
166 // We disable inbound relay connection if this value is set to true (typically via command-line switch).
167 mDNSBool DisableInboundRelayConnection
= mDNSfalse
;
168 mDNSexport
int OSXVers
;
169 mDNSexport
int KQueueFD
;
171 #ifndef NO_SECURITYFRAMEWORK
172 static CFArrayRef ServerCerts
;
173 OSStatus
SSLSetAllowAnonymousCiphers(SSLContextRef context
, Boolean enable
);
174 #endif /* NO_SECURITYFRAMEWORK */
176 static CFStringRef NetworkChangedKey_IPv4
;
177 static CFStringRef NetworkChangedKey_IPv6
;
178 static CFStringRef NetworkChangedKey_Hostnames
;
179 static CFStringRef NetworkChangedKey_Computername
;
180 static CFStringRef NetworkChangedKey_DNS
;
181 static CFStringRef NetworkChangedKey_DynamicDNS
= CFSTR("Setup:/Network/DynamicDNS");
182 static CFStringRef NetworkChangedKey_BackToMyMac
= CFSTR("Setup:/Network/BackToMyMac");
183 static CFStringRef NetworkChangedKey_BTMMConnectivity
= CFSTR("State:/Network/Connectivity");
184 static CFStringRef NetworkChangedKey_PowerSettings
= CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
186 static char HINFO_HWstring_buffer
[32];
187 static char *HINFO_HWstring
= "Device";
188 static int HINFO_HWstring_prefixlen
= 6;
190 mDNSexport
int WatchDogReportingThreshold
= 250;
192 #ifdef __LIB_DISPATCH__
193 dispatch_queue_t SSLqueue
;
196 #if APPLE_OSX_mDNSResponder
197 static mDNSu8 SPMetricPortability
= 99;
198 static mDNSu8 SPMetricMarginalPower
= 99;
199 static mDNSu8 SPMetricTotalPower
= 99;
200 mDNSexport domainname ActiveDirectoryPrimaryDomain
;
201 mDNSexport
int ActiveDirectoryPrimaryDomainLabelCount
;
202 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer
;
203 #endif // APPLE_OSX_mDNSResponder
205 // ***************************************************************************
206 #if COMPILER_LIKES_PRAGMA_MARK
208 #pragma mark - D2D Support
213 // Name compression items for fake packet version number 1
214 static const mDNSu8 compression_packet_v1
= 0x01;
216 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" };
217 static mDNSu8
*const compression_limit
= (mDNSu8
*) &compression_base_msg
+ sizeof(DNSMessage
);
218 static mDNSu8
*const compression_lhs
= (mDNSu8
*const) compression_base_msg
.data
+ 27;
220 mDNSlocal
void FreeD2DARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
221 mDNSlocal
void PrintHex(mDNSu8
*data
, mDNSu16 len
);
223 static ARListElem
*D2DRecords
= NULL
; // List of locally-generated PTR records to records found via D2D
225 typedef struct D2DBrowseListElem
227 struct D2DBrowseListElem
*next
;
230 unsigned int refCount
;
233 D2DBrowseListElem
* D2DBrowseList
= NULL
;
235 mDNSlocal mDNSu8
*putVal16(mDNSu8
*ptr
, mDNSu16 val
)
237 ptr
[0] = (mDNSu8
)((val
>> 8 ) & 0xFF);
238 ptr
[1] = (mDNSu8
)((val
) & 0xFF);
239 return ptr
+ sizeof(mDNSu16
);
242 mDNSlocal mDNSu8
*putVal32(mDNSu8
*ptr
, mDNSu32 val
)
244 ptr
[0] = (mDNSu8
)((val
>> 24) & 0xFF);
245 ptr
[1] = (mDNSu8
)((val
>> 16) & 0xFF);
246 ptr
[2] = (mDNSu8
)((val
>> 8) & 0xFF);
247 ptr
[3] = (mDNSu8
)((val
) & 0xFF);
248 return ptr
+ sizeof(mDNSu32
);
251 mDNSlocal
void DomainnameToLower(const domainname
* const in
, domainname
* const out
)
253 const mDNSu8
* const start
= (const mDNSu8
* const)in
;
254 mDNSu8
*ptr
= (mDNSu8
*)start
;
258 out
->c
[ptr
-start
] = *ptr
;
260 for (;c
;c
--,ptr
++) out
->c
[ptr
-start
] = mDNSIsUpperCase(*ptr
) ? (*ptr
- 'A' + 'a') : *ptr
;
262 out
->c
[ptr
-start
] = *ptr
;
265 mDNSlocal mStatus
DNSNameCompressionParseBytes(mDNS
*const m
, const mDNSu8
*const lhs
, const mDNSu16 lhs_len
, const mDNSu8
*const rhs
, const mDNSu16 rhs_len
, AuthRecord
*rr
)
267 if (mDNS_LoggingEnabled
)
269 LogInfo("%s", __func__
);
270 LogInfo(" Static Bytes: ");
271 PrintHex((mDNSu8
*)&compression_base_msg
, compression_lhs
- (mDNSu8
*)&compression_base_msg
);
274 mDNSu8
*ptr
= compression_lhs
; // pointer to the end of our fake packet
276 // Check to make sure we're not going to go past the end of the DNSMessage data
277 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
278 if (ptr
+ lhs_len
- 7 + rhs_len
>= compression_limit
) return mStatus_NoMemoryErr
;
280 // Copy the LHS onto our fake wire packet
281 mDNSPlatformMemCopy(ptr
, lhs
, lhs_len
);
284 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
285 if (*ptr
!= compression_packet_v1
) return mStatus_Incompatible
;
287 // two bytes of CLASS
288 ptr
= putVal16(ptr
, kDNSClass_IN
| kDNSClass_UniqueRRSet
);
291 ptr
= putVal32(ptr
, 120);
293 // Copy the RHS length into the RDLENGTH of our fake wire packet
294 ptr
= putVal16(ptr
, rhs_len
);
296 // Copy the RHS onto our fake wire packet
297 mDNSPlatformMemCopy(ptr
, rhs
, rhs_len
);
300 if (mDNS_LoggingEnabled
)
302 LogInfo(" Our Bytes %d: ", __LINE__
);
303 PrintHex(compression_lhs
, ptr
- compression_lhs
);
306 ptr
= (mDNSu8
*) GetLargeResourceRecord(m
, &compression_base_msg
, compression_lhs
, ptr
, mDNSInterface_Any
, kDNSRecordTypePacketAns
, &m
->rec
);
307 if (!ptr
|| m
->rec
.r
.resrec
.RecordType
== kDNSRecordTypePacketNegative
)
308 { LogMsg("DNSNameCompressionParseBytes: failed to get large RR"); m
->rec
.r
.resrec
.RecordType
= 0; return mStatus_UnknownErr
; }
309 else LogInfo("DNSNameCompressionParseBytes: got rr: %s", CRDisplayString(m
, &m
->rec
.r
));
311 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_P2P
, m
->rec
.r
.resrec
.rrtype
, 7200, kDNSRecordTypeShared
, FreeD2DARElemCallback
, NULL
);
312 AssignDomainName(&rr
->namestorage
, &m
->rec
.namestorage
);
313 rr
->resrec
.rdlength
= m
->rec
.r
.resrec
.rdlength
;
314 rr
->resrec
.rdata
->MaxRDLength
= m
->rec
.r
.resrec
.rdlength
;
315 mDNSPlatformMemCopy(rr
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdlength
);
316 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
317 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
319 m
->rec
.r
.resrec
.RecordType
= 0; // Mark m->rec as no longer in use
321 return mStatus_NoError
;
324 mDNSlocal mDNSu8
* DNSNameCompressionBuildLHS(const domainname
const *typeDomain
, DNS_TypeValues qtype
)
326 mDNSu8
*ptr
= putDomainNameAsLabels(&compression_base_msg
, compression_lhs
, compression_limit
, typeDomain
);
327 if (!ptr
) return ptr
;
328 *ptr
= (qtype
>> 8) & 0xff;
332 *ptr
= compression_packet_v1
;
336 mDNSlocal mDNSu8
* DNSNameCompressionBuildRHS(mDNSu8
*start
, const ResourceRecord
*const resourceRecord
)
338 return putRData(&compression_base_msg
, start
, compression_limit
, resourceRecord
);
341 mDNSlocal
void PrintHex(mDNSu8
*data
, mDNSu16 len
)
343 mDNSu8
*end
= data
+ len
;
344 char buffer
[49] = {0};
345 char *bufend
= buffer
+ sizeof(buffer
);
349 for(; data
< end
&& ptr
< bufend
-1; ptr
+=3,data
++)
350 mDNS_snprintf(ptr
, bufend
- ptr
, "%02X ", *data
);
351 LogInfo(" %s", buffer
);
355 mDNSlocal
void PrintHelper(const char *const tag
, mDNSu8
*lhs
, mDNSu16 lhs_len
, mDNSu8
*rhs
, mDNSu16 rhs_len
)
357 if (!mDNS_LoggingEnabled
) return;
361 PrintHex(lhs
, lhs_len
);
366 PrintHex(rhs
, rhs_len
);
369 mDNSlocal
void FreeD2DARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
372 if (result
== mStatus_MemFree
)
374 ARListElem
**ptr
= &D2DRecords
;
376 while (*ptr
&& &(*ptr
)->ar
!= rr
) ptr
= &(*ptr
)->next
;
377 if (!*ptr
) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m
, rr
)); return; }
378 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m
, rr
));
381 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
382 mDNSPlatformMemFree(tmp
);
386 mDNSlocal
void xD2DClearCache(mDNS
*const m
, const domainname
*regType
)
388 ARListElem
*ptr
= D2DRecords
;
389 for ( ; ptr
; ptr
= ptr
->next
)
391 if (SameDomainName(&ptr
->ar
.namestorage
, regType
))
393 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
394 mDNS_Deregister(m
, &ptr
->ar
);
395 ConvertDomainNameToCString(regType
, buffer
);
396 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", buffer
);
401 mDNSlocal D2DBrowseListElem
** D2DFindInBrowseList(const domainname
*const name
, mDNSu16 type
)
403 D2DBrowseListElem
**ptr
= &D2DBrowseList
;
405 for ( ; *ptr
; ptr
= &(*ptr
)->next
)
406 if ((*ptr
)->type
== type
&& SameDomainName(&(*ptr
)->name
, name
))
412 mDNSlocal
unsigned int D2DBrowseListRefCount(const domainname
*const name
, mDNSu16 type
)
414 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
415 return *ptr
? (*ptr
)->refCount
: 0;
418 mDNSlocal
void D2DBrowseListRetain(const domainname
*const name
, mDNSu16 type
)
420 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
424 *ptr
= mDNSPlatformMemAllocate(sizeof(**ptr
));
425 mDNSPlatformMemZero(*ptr
, sizeof(**ptr
));
427 AssignDomainName(&(*ptr
)->name
, name
);
429 (*ptr
)->refCount
+= 1;
431 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
434 mDNSlocal
void D2DBrowseListRelease(const domainname
*const name
, mDNSu16 type
)
436 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
438 if (!*ptr
) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name
->c
, DNSTypeName(type
)); return; }
440 (*ptr
)->refCount
-= 1;
442 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
444 if (!(*ptr
)->refCount
)
446 D2DBrowseListElem
*tmp
= *ptr
;
448 mDNSPlatformMemFree(tmp
);
452 mDNSlocal mStatus
xD2DParse(mDNS
*const m
, const mDNSu8
* const lhs
, const mDNSu16 lhs_len
, const mDNSu8
* const rhs
, const mDNSu16 rhs_len
, AuthRecord
*rr
)
454 if (*(lhs
+ (lhs_len
- 1)) == compression_packet_v1
)
455 return DNSNameCompressionParseBytes(m
, lhs
, lhs_len
, rhs
, rhs_len
, rr
);
457 return mStatus_Incompatible
;
460 mDNSlocal
void xD2DAddToCache(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
462 (void)transportType
; // We don't care about this, yet.
463 (void)instanceHandle
; // We don't care about this, yet.
465 if (result
== kD2DSuccess
)
467 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
470 ARListElem
*ptr
= mDNSPlatformMemAllocate(sizeof(ARListElem
) + (valueSize
< sizeof(RData
) ? 0 : valueSize
- sizeof(RData
)));
472 if (ptr
== NULL
) { LogMsg("xD2DAddToCache: memory allocation failure"); return; }
474 err
= xD2DParse(m
, (const mDNSu8
* const)key
, (const mDNSu16
)keySize
, (const mDNSu8
* const)value
, (const mDNSu16
)valueSize
, &ptr
->ar
);
477 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err
);
478 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
479 mDNSPlatformMemFree(ptr
);
483 err
= mDNS_Register(m
, &ptr
->ar
);
486 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err
, ARDisplayString(m
, &ptr
->ar
));
487 mDNSPlatformMemFree(ptr
);
491 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m
, &ptr
->ar
));
492 ptr
->next
= D2DRecords
;
496 LogMsg("xD2DAddToCache: Unexpected result %d", result
);
499 mDNSlocal ARListElem
* xD2DFindInList(mDNS
*const m
, const Byte
*const key
, const size_t keySize
, const Byte
*const value
, const size_t valueSize
)
501 ARListElem
*ptr
= D2DRecords
;
504 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL
; }
506 arptr
= mDNSPlatformMemAllocate(sizeof(ARListElem
) + (valueSize
< sizeof(RData
) ? 0 : valueSize
- sizeof(RData
)));
507 if (arptr
== NULL
) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL
; }
509 if (xD2DParse(m
, (const mDNSu8
*const)key
, (const mDNSu16
)keySize
, (const mDNSu8
*const)value
, (const mDNSu16
)valueSize
, &arptr
->ar
) != mStatus_NoError
)
511 LogMsg("xD2DFindInList: xD2DParse failed for key: %p (%u) value: %p (%u)", key
, keySize
, value
, valueSize
);
512 mDNSPlatformMemFree(arptr
);
518 if (IdenticalResourceRecord(&arptr
->ar
.resrec
, &ptr
->ar
.resrec
)) break;
522 if (!ptr
) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(m
, &arptr
->ar
));
523 mDNSPlatformMemFree(arptr
);
527 mDNSlocal
void xD2DRemoveFromCache(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
529 (void)transportType
; // We don't care about this, yet.
530 (void)instanceHandle
; // We don't care about this, yet.
532 if (result
== kD2DSuccess
)
534 ARListElem
*ptr
= xD2DFindInList(m
, key
, keySize
, value
, valueSize
);
537 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m
, &ptr
->ar
));
538 mDNS_Deregister(m
, &ptr
->ar
);
542 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result
);
545 mDNSlocal
void xD2DServiceResolved(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
553 if (result
== kD2DSuccess
)
555 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle
);
556 CHECK_D2D_FUNCTION(D2DRetain
) D2DRetain(instanceHandle
, transportType
);
558 else LogMsg("xD2DServiceResolved: Unexpected result %d", result
);
561 mDNSlocal
void xD2DRetainHappened(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
564 (void)instanceHandle
;
571 if (result
== kD2DSuccess
) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle
);
572 else LogMsg("xD2DRetainHappened: Unexpected result %d", result
);
575 mDNSlocal
void xD2DReleaseHappened(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
578 (void)instanceHandle
;
585 if (result
== kD2DSuccess
) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle
);
586 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result
);
589 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
)
591 mDNS
*m
= (mDNS
*) userData
;
592 const char *eventString
= "unknown";
596 if (keySize
> 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize
);
597 if (valueSize
> 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize
);
601 case D2DServiceFound
:
602 eventString
= "D2DServiceFound";
605 eventString
= "D2DServiceLost";
607 case D2DServiceResolved
:
608 eventString
= "D2DServiceResolved";
610 case D2DServiceRetained
:
611 eventString
= "D2DServiceRetained";
613 case D2DServiceReleased
:
614 eventString
= "D2DServiceReleased";
620 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
);
621 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
625 case D2DServiceFound
:
626 xD2DAddToCache(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
629 xD2DRemoveFromCache(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
631 case D2DServiceResolved
:
632 xD2DServiceResolved(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
634 case D2DServiceRetained
:
635 xD2DRetainHappened(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
637 case D2DServiceReleased
:
638 xD2DReleaseHappened(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
644 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
645 KQueueUnlock(m
, "xD2DServiceCallback");
648 mDNSexport
void external_start_browsing_for_service(mDNS
*const m
, const domainname
*const typeDomain
, DNS_TypeValues qtype
)
653 if (qtype
== kDNSServiceType_A
|| qtype
== kDNSServiceType_AAAA
)
655 LogInfo("external_start_browsing_for_service: ignoring address record");
659 DomainnameToLower(typeDomain
, &lower
);
661 if (!D2DBrowseListRefCount(&lower
, qtype
))
663 LogInfo("external_start_browsing_for_service: Starting browse for: %##s %s", lower
.c
, DNSTypeName(qtype
));
664 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
665 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
666 CHECK_D2D_FUNCTION(D2DStartBrowsingForKey
) D2DStartBrowsingForKey(compression_lhs
, end
- compression_lhs
);
668 D2DBrowseListRetain(&lower
, qtype
);
671 mDNSexport
void external_stop_browsing_for_service(mDNS
*const m
, const domainname
*const typeDomain
, DNS_TypeValues qtype
)
675 if (qtype
== kDNSServiceType_A
|| qtype
== kDNSServiceType_AAAA
)
677 LogInfo("external_stop_browsing_for_service: ignoring address record");
681 DomainnameToLower(typeDomain
, &lower
);
683 D2DBrowseListRelease(&lower
, qtype
);
684 if (!D2DBrowseListRefCount(&lower
, qtype
))
686 LogInfo("external_stop_browsing_for_service: Stopping browse for: %##s %s", lower
.c
, DNSTypeName(qtype
));
687 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
688 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
689 CHECK_D2D_FUNCTION(D2DStopBrowsingForKey
) D2DStopBrowsingForKey(compression_lhs
, end
- compression_lhs
);
690 xD2DClearCache(m
, &lower
);
694 mDNSexport
void external_start_advertising_service(const ResourceRecord
*const resourceRecord
)
699 DomainnameToLower(resourceRecord
->name
, &lower
);
701 LogInfo("external_start_advertising_service: %s", RRDisplayString(&mDNSStorage
, resourceRecord
));
702 if (resourceRecord
->rrtype
== kDNSServiceType_A
|| resourceRecord
->rrtype
== kDNSServiceType_AAAA
)
704 LogInfo("external_start_advertising_service: ignoring address record");
707 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
708 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
709 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
710 CHECK_D2D_FUNCTION(D2DStartAdvertisingPair
) D2DStartAdvertisingPair(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
713 mDNSexport
void external_stop_advertising_service(const ResourceRecord
*const resourceRecord
)
718 DomainnameToLower(resourceRecord
->name
, &lower
);
720 LogInfo("external_stop_advertising_service: %s", RRDisplayString(&mDNSStorage
, resourceRecord
));
721 if (resourceRecord
->rrtype
== kDNSServiceType_A
|| resourceRecord
->rrtype
== kDNSServiceType_AAAA
)
723 LogInfo("external_stop_advertising_service: ignoring address record");
726 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
727 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
728 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
729 CHECK_D2D_FUNCTION(D2DStopAdvertisingPair
) D2DStopAdvertisingPair(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
732 mDNSexport
void external_start_resolving_service(const domainname
*const fqdn
)
737 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
739 LogInfo("external_start_resolving_service: %##s", fqdn
->c
);
740 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
741 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
742 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
743 CHECK_D2D_FUNCTION(D2DStartResolvingPair
) D2DStartResolvingPair(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
746 mDNSexport
void external_stop_resolving_service(const domainname
*const fqdn
)
751 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
753 LogInfo("external_stop_resolving_service: %##s", fqdn
->c
);
754 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
755 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
756 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
757 CHECK_D2D_FUNCTION(D2DStopResolvingPair
) D2DStopResolvingPair(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
760 #elif APPLE_OSX_mDNSResponder
762 mDNSexport
void external_start_browsing_for_service(mDNS
*const m
, const domainname
*const type
, DNS_TypeValues qtype
) { (void)m
; (void)type
; (void)qtype
; }
763 mDNSexport
void external_stop_browsing_for_service(mDNS
*const m
, const domainname
*const type
, DNS_TypeValues qtype
) { (void)m
; (void)type
; (void)qtype
; }
764 mDNSexport
void external_start_advertising_service(const ResourceRecord
*const resourceRecord
) { (void)resourceRecord
; }
765 mDNSexport
void external_stop_advertising_service(const ResourceRecord
*const resourceRecord
) { (void)resourceRecord
; }
766 mDNSexport
void external_start_resolving_service(const domainname
*const fqdn
) { (void)fqdn
; }
767 mDNSexport
void external_stop_resolving_service(const domainname
*const fqdn
) { (void)fqdn
; }
771 // ***************************************************************************
774 #if COMPILER_LIKES_PRAGMA_MARK
776 #pragma mark - Utility Functions
779 // We only attempt to send and receive multicast packets on interfaces that are
780 // (a) flagged as multicast-capable
781 // (b) *not* flagged as point-to-point (e.g. modem)
782 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
783 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
784 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
785 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
787 mDNSexport
void NotifyOfElusiveBug(const char *title
, const char *msg
) // Both strings are UTF-8 text
789 static int notifyCount
= 0;
790 if (notifyCount
) return;
792 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
793 // To avoid this, we don't try to display alerts in the first three minutes after boot.
794 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return;
796 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
799 // Determine if we're at Apple (17.*.*.*)
800 extern mDNS mDNSStorage
;
801 NetworkInterfaceInfoOSX
*i
;
802 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
803 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& i
->ifinfo
.ip
.ip
.v4
.b
[0] == 17)
805 if (!i
) return; // If not at Apple, don't show the alert
811 // Display a notification to the user
814 #ifndef NO_CFUSERNOTIFICATION
815 mDNSNotify(title
, msg
);
816 #endif /* NO_CFUSERNOTIFICATION */
819 mDNSlocal
struct ifaddrs
*myGetIfAddrs(int refresh
)
821 static struct ifaddrs
*ifa
= NULL
;
829 if (ifa
== NULL
) getifaddrs(&ifa
);
834 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
835 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, const char *ifname
, int type
)
837 NetworkInterfaceInfoOSX
*i
;
838 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
839 if (i
->Exists
&& !strcmp(i
->ifinfo
.ifname
, ifname
) &&
840 ((type
== AF_UNSPEC
) ||
841 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
842 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
))) return(i
);
846 mDNSlocal
int myIfIndexToName(u_short ifindex
, char *name
)
849 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
850 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
851 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== ifindex
)
852 { strlcpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
856 mDNSexport NetworkInterfaceInfoOSX
*IfindexToInterfaceInfoOSX(const mDNS
*const m
, mDNSInterfaceID ifindex
)
858 mDNSu32 scope_id
= (mDNSu32
)(uintptr_t)ifindex
;
859 NetworkInterfaceInfoOSX
*i
;
861 // Don't get tricked by inactive interfaces
862 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
863 if (i
->Registered
&& i
->scope_id
== scope_id
) return(i
);
868 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS
*const m
, mDNSu32 ifindex
)
870 if (ifindex
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
871 if (ifindex
== kDNSServiceInterfaceIndexP2P
) return(mDNSInterface_P2P
);
872 if (ifindex
== kDNSServiceInterfaceIndexAny
) return(mDNSNULL
);
874 NetworkInterfaceInfoOSX
* ifi
= IfindexToInterfaceInfoOSX(m
, (mDNSInterfaceID
)(uintptr_t)ifindex
);
877 // Not found. Make sure our interface list is up to date, then try again.
878 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex
);
879 mDNSMacOSXNetworkChanged(m
);
880 ifi
= IfindexToInterfaceInfoOSX(m
, (mDNSInterfaceID
)(uintptr_t)ifindex
);
883 if (!ifi
) return(mDNSNULL
);
885 return(ifi
->ifinfo
.InterfaceID
);
889 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS
*const m
, mDNSInterfaceID id
)
891 NetworkInterfaceInfoOSX
*i
;
892 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
893 if (id
== mDNSInterface_P2P
) return(kDNSServiceInterfaceIndexP2P
);
894 if (id
== mDNSInterface_Any
) return(0);
896 mDNSu32 scope_id
= (mDNSu32
)(uintptr_t)id
;
898 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
899 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
900 if (i
->scope_id
== scope_id
) return(i
->scope_id
);
902 // Not found. Make sure our interface list is up to date, then try again.
903 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id
);
904 mDNSMacOSXNetworkChanged(m
);
905 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
906 if (i
->scope_id
== scope_id
) return(i
->scope_id
);
911 #if APPLE_OSX_mDNSResponder
912 mDNSexport
void mDNSASLLog(uuid_t
*uuid
, const char *subdomain
, const char *result
, const char *signature
, const char *fmt
, ...)
914 if (OSXVers
< OSXVers_10_6_SnowLeopard
) return;
916 static char buffer
[512];
917 aslmsg asl_msg
= asl_new(ASL_TYPE_MSG
);
919 if (!asl_msg
) { LogMsg("mDNSASLLog: asl_new failed"); return; }
923 uuid_unparse(*uuid
, uuidStr
);
924 asl_set (asl_msg
, "com.apple.message.uuid", uuidStr
);
927 static char domainBase
[] = "com.apple.mDNSResponder.%s";
928 mDNS_snprintf (buffer
, sizeof(buffer
), domainBase
, subdomain
);
929 asl_set (asl_msg
, "com.apple.message.domain", buffer
);
931 if (result
) asl_set(asl_msg
, "com.apple.message.result", result
);
932 if (signature
) asl_set(asl_msg
, "com.apple.message.signature", signature
);
936 mDNS_vsnprintf(buffer
, sizeof(buffer
), fmt
, ptr
);
939 int old_filter
= asl_set_filter(NULL
,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
));
940 asl_log(NULL
, asl_msg
, ASL_LEVEL_DEBUG
, "%s", buffer
);
941 asl_set_filter(NULL
, old_filter
);
944 #endif // APPLE_OSX_mDNSResponder
946 #if COMPILER_LIKES_PRAGMA_MARK
948 #pragma mark - UDP & TCP send & receive
951 mDNSlocal mDNSBool
AddrRequiresPPPConnection(const struct sockaddr
*addr
)
953 mDNSBool result
= mDNSfalse
;
954 SCNetworkConnectionFlags flags
;
955 SCNetworkReachabilityRef ReachRef
= NULL
;
957 ReachRef
= SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault
, addr
);
958 if (!ReachRef
) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end
; }
959 if (!SCNetworkReachabilityGetFlags(ReachRef
, &flags
)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end
; }
960 result
= flags
& kSCNetworkFlagsConnectionRequired
;
963 if (ReachRef
) CFRelease(ReachRef
);
967 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
968 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
969 // OR send via our primary v4 unicast socket
970 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
971 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
972 mDNSInterfaceID InterfaceID
, UDPSocket
*src
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
974 NetworkInterfaceInfoOSX
*info
= mDNSNULL
;
975 struct sockaddr_storage to
;
977 mStatus result
= mStatus_NoError
;
981 info
= IfindexToInterfaceInfoOSX(m
, InterfaceID
);
984 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID
);
985 return mStatus_BadParamErr
;
989 char *ifa_name
= InterfaceID
? info
->ifinfo
.ifname
: "unicast";
991 if (dst
->type
== mDNSAddrType_IPv4
)
993 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
994 sin_to
->sin_len
= sizeof(*sin_to
);
995 sin_to
->sin_family
= AF_INET
;
996 sin_to
->sin_port
= dstPort
.NotAnInteger
;
997 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
998 s
= (src
? src
->ss
: m
->p
->permanentsockets
).sktv4
;
1000 if (info
) // Specify outgoing interface
1002 if (!mDNSAddrIsDNSMulticast(dst
))
1005 if (info
->scope_id
== 0)
1006 LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info
, ifa_name
);
1008 setsockopt(s
, IPPROTO_IP
, IP_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1011 static int displayed
= 0;
1012 if (displayed
< 1000)
1015 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
1021 #ifdef IP_MULTICAST_IFINDEX
1023 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IFINDEX
, &info
->scope_id
, sizeof(info
->scope_id
));
1024 // We get an error when we compile on a machine that supports this option and run the binary on
1025 // a different machine that does not support it
1028 if (errno
!= ENOPROTOOPT
) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno
);
1029 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
1030 if (err
< 0 && !m
->p
->NetworkChanged
)
1031 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
1036 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
1037 if (err
< 0 && !m
->p
->NetworkChanged
)
1038 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
1045 else if (dst
->type
== mDNSAddrType_IPv6
)
1047 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
1048 sin6_to
->sin6_len
= sizeof(*sin6_to
);
1049 sin6_to
->sin6_family
= AF_INET6
;
1050 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
1051 sin6_to
->sin6_flowinfo
= 0;
1052 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1053 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
1054 s
= (src
? src
->ss
: m
->p
->permanentsockets
).sktv6
;
1055 if (info
&& mDNSAddrIsDNSMulticast(dst
)) // Specify outgoing interface
1057 err
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1058 if (err
< 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err
, errno
, strerror(errno
));
1064 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1068 return mStatus_BadParamErr
;
1072 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1073 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
1075 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1076 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
1078 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1079 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1080 if (s
< 0) return(mStatus_Invalid
);
1082 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
1085 static int MessageCount
= 0;
1086 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1087 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
1088 if (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== EHOSTUNREACH
|| errno
== ENETUNREACH
) return(mStatus_TransientErr
);
1089 // Don't report EHOSTUNREACH in the first three minutes after boot
1090 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1091 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1092 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(mStatus_TransientErr
);
1093 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1094 if (errno
== EADDRNOTAVAIL
&& m
->p
->NetworkChanged
) return(mStatus_TransientErr
);
1095 if (MessageCount
< 1000)
1098 if (errno
== EHOSTUNREACH
|| errno
== EADDRNOTAVAIL
|| errno
== ENETDOWN
)
1099 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1100 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
1102 LogMsg("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1103 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
1105 result
= mStatus_UnknownErr
;
1109 if (dst
->type
== mDNSAddrType_IPv4
&& info
&& !mDNSAddrIsDNSMulticast(dst
))
1111 static const mDNSu32 ifindex
= 0;
1112 setsockopt(s
, IPPROTO_IP
, IP_BOUND_IF
, &ifindex
, sizeof(ifindex
));
1119 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
1120 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
1122 static unsigned int numLogMessages
= 0;
1123 struct iovec databuffers
= { (char *)buffer
, max
};
1126 struct cmsghdr
*cmPtr
;
1127 char ancillary
[1024];
1129 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1131 // Set up the message
1132 msg
.msg_name
= (caddr_t
)from
;
1133 msg
.msg_namelen
= *fromlen
;
1134 msg
.msg_iov
= &databuffers
;
1136 msg
.msg_control
= (caddr_t
)&ancillary
;
1137 msg
.msg_controllen
= sizeof(ancillary
);
1141 n
= recvmsg(s
, &msg
, 0);
1144 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
1147 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
1149 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1150 s
, n
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
1153 if (msg
.msg_flags
& MSG_CTRUNC
)
1155 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
1159 *fromlen
= msg
.msg_namelen
;
1161 // Parse each option out of the ancillary data.
1162 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
1164 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1165 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
1167 dstaddr
->type
= mDNSAddrType_IPv4
;
1168 dstaddr
->ip
.v4
= *(mDNSv4Addr
*)CMSG_DATA(cmPtr
);
1169 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
1171 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
1173 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
1174 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
1176 mDNSPlatformMemCopy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
1177 ifname
[sdl
->sdl_nlen
] = 0;
1178 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1181 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
1182 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
1183 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
1185 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
1186 dstaddr
->type
= mDNSAddrType_IPv6
;
1187 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
1188 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
1190 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
1191 *ttl
= *(int*)CMSG_DATA(cmPtr
);
1197 mDNSlocal
void myKQSocketCallBack(int s1
, short filter
, void *context
)
1199 KQSocketSet
*const ss
= (KQSocketSet
*)context
;
1200 mDNS
*const m
= ss
->m
;
1201 int err
= 0, count
= 0, closed
= 0;
1203 if (filter
!= EVFILT_READ
)
1204 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter
, EVFILT_READ
);
1212 LogMsg("myKQSocketCallBack: native socket %d", s1
);
1213 LogMsg("myKQSocketCallBack: sktv4 %d", ss
->sktv4
);
1215 LogMsg("myKQSocketCallBack: sktv6 %d", ss
->sktv6
);
1221 mDNSAddr senderAddr
, destAddr
;
1222 mDNSIPPort senderPort
;
1223 struct sockaddr_storage from
;
1224 size_t fromlen
= sizeof(from
);
1225 char packetifname
[IF_NAMESIZE
] = "";
1227 err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
1231 if (from
.ss_family
== AF_INET
)
1233 struct sockaddr_in
*s
= (struct sockaddr_in
*)&from
;
1234 senderAddr
.type
= mDNSAddrType_IPv4
;
1235 senderAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
1236 senderPort
.NotAnInteger
= s
->sin_port
;
1237 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1239 else if (from
.ss_family
== AF_INET6
)
1241 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
1242 senderAddr
.type
= mDNSAddrType_IPv6
;
1243 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
1244 senderPort
.NotAnInteger
= sin6
->sin6_port
;
1245 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1249 LogMsg("myKQSocketCallBack from is unknown address family %d", from
.ss_family
);
1253 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1254 mDNSInterfaceID InterfaceID
= mDNSNULL
;
1255 //NetworkInterfaceInfo *intf = m->HostInterfaces;
1256 //while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
1258 NetworkInterfaceInfoOSX
*intf
= m
->p
->InterfaceList
;
1259 while (intf
&& strcmp(intf
->ifinfo
.ifname
, packetifname
)) intf
= intf
->next
;
1261 // When going to sleep we deregister all our interfaces, but if the machine
1262 // takes a few seconds to sleep we may continue to receive multicasts
1263 // during that time, which would confuse mDNSCoreReceive, because as far
1264 // as it's concerned, we should have no active interfaces any more.
1265 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1266 if (intf
) InterfaceID
= intf
->ifinfo
.InterfaceID
;
1267 else if (mDNSAddrIsDNSMulticast(&destAddr
)) continue;
1269 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1270 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
1272 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
1273 // loop when that happens, or we may try to read from an invalid FD. We do this by
1274 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
1275 // if it closes the socketset.
1276 ss
->closeFlag
= &closed
;
1278 mDNSCoreReceive(m
, &m
->imsg
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, ss
->port
, InterfaceID
);
1280 // if we didn't close, we can safely dereference the socketset, and should to
1281 // reset the closeFlag, since it points to something on the stack
1282 if (!closed
) ss
->closeFlag
= mDNSNULL
;
1285 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
1287 // Something is busted here.
1288 // kqueue says there is a packet, but myrecvfrom says there is not.
1289 // Try calling select() to get another opinion.
1290 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1291 // All of this is racy, as data may have arrived after the call to select()
1292 static unsigned int numLogMessages
= 0;
1293 int save_errno
= errno
;
1297 socklen_t solen
= sizeof(int);
1299 struct timeval timeout
;
1302 FD_SET(s1
, &readfds
);
1304 timeout
.tv_usec
= 0;
1305 selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
1306 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
1307 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
1308 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
1309 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
1310 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
1311 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno
);
1312 if (numLogMessages
++ < 100)
1313 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1314 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
1315 if (numLogMessages
> 5)
1316 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1317 "Congratulations, you've reproduced an elusive bug.\r"
1318 "Please contact the current assignee of <rdar://problem/3375328>.\r"
1319 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1320 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1322 sleep(1); // After logging this error, rate limit so we don't flood syslog
1326 // TCP socket support
1331 handshake_in_progress
,
1332 handshake_completed
,
1333 handshake_to_be_closed
1336 struct TCPSocket_struct
1338 TCPSocketFlags flags
; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
1339 TCPConnectionCallback callback
;
1341 KQueueEntry
*kqEntry
;
1343 #ifndef NO_SECURITYFRAMEWORK
1344 SSLContextRef tlsContext
;
1345 pthread_t handshake_thread
;
1346 #endif /* NO_SECURITYFRAMEWORK */
1347 domainname hostname
;
1351 handshakeStatus handshake
;
1352 mDNS
*m
; // So we can call KQueueLock from the SSLHandshake thread
1356 mDNSlocal
void doTcpSocketCallback(TCPSocket
*sock
)
1358 mDNSBool c
= !sock
->connected
;
1359 sock
->connected
= mDNStrue
;
1360 sock
->callback(sock
, sock
->context
, c
, sock
->err
);
1361 // Note: the callback may call CloseConnection here, which frees the context structure!
1364 #ifndef NO_SECURITYFRAMEWORK
1366 mDNSlocal OSStatus
tlsWriteSock(SSLConnectionRef connection
, const void *data
, size_t *dataLength
)
1368 int ret
= send(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1369 if (ret
>= 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1370 if (ret
>= 0) { *dataLength
= ret
; return(noErr
); }
1372 if (errno
== EAGAIN
) return(errSSLWouldBlock
);
1373 if (errno
== ENOENT
) return(errSSLClosedGraceful
);
1374 if (errno
== EPIPE
|| errno
== ECONNRESET
) return(errSSLClosedAbort
);
1375 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket
*)connection
)->fd
, errno
, strerror(errno
));
1376 return(errSSLClosedAbort
);
1379 mDNSlocal OSStatus
tlsReadSock(SSLConnectionRef connection
, void *data
, size_t *dataLength
)
1381 int ret
= recv(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1382 if (ret
> 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1383 if (ret
> 0) { *dataLength
= ret
; return(noErr
); }
1385 if (ret
== 0 || errno
== ENOENT
) return(errSSLClosedGraceful
);
1386 if ( errno
== EAGAIN
) return(errSSLWouldBlock
);
1387 if ( errno
== ECONNRESET
) return(errSSLClosedAbort
);
1388 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno
, strerror(errno
));
1389 return(errSSLClosedAbort
);
1392 mDNSlocal OSStatus
tlsSetupSock(TCPSocket
*sock
, mDNSBool server
)
1394 char domname_cstr
[MAX_ESCAPED_DOMAIN_NAME
];
1396 mStatus err
= SSLNewContext(server
, &sock
->tlsContext
);
1397 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err
); return(err
); }
1399 err
= SSLSetIOFuncs(sock
->tlsContext
, tlsReadSock
, tlsWriteSock
);
1400 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err
); return(err
); }
1402 err
= SSLSetConnection(sock
->tlsContext
, (SSLConnectionRef
) sock
);
1403 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err
); return(err
); }
1405 // Instead of listing all the acceptable ciphers, we just disable the bad ciphers. It does not disable
1406 // all the bad ciphers like RC4_MD5, but it assumes that the servers don't offer them.
1407 err
= SSLSetAllowAnonymousCiphers(sock
->tlsContext
, 0);
1408 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err
); return(err
); }
1410 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
1411 // (error not in OSStatus space) is okay.
1412 if (!sock
->hostname
.c
[0]) {LogMsg("ERROR: tlsSetupSock: hostname NULL"); return -1; }
1414 ConvertDomainNameToCString(&sock
->hostname
, domname_cstr
);
1415 err
= SSLSetPeerDomainName(sock
->tlsContext
, domname_cstr
, strlen(domname_cstr
));
1416 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr
, err
); return(err
); }
1421 #ifdef __LIB_DISPATCH__
1422 mDNSlocal
void doSSLHandshake(void *ctx
)
1424 TCPSocket
*sock
= (TCPSocket
*)ctx
;
1425 mStatus err
= SSLHandshake(sock
->tlsContext
);
1427 //Can't have multiple threads in mDNS core. When __LIB_DISPATCH__ is
1428 //defined, KQueueLock is a noop. Hence we need to serialize here
1430 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
1431 //We need the rest of the logic also. Otherwise, we can enable the READ
1432 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
1433 //ConnFailed which means we are going to free the tcpInfo. While it
1434 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
1435 //and potentially call doTCPCallback with error which can close the fd and free the
1436 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
1439 dispatch_async(dispatch_get_main_queue(), ^{
1441 LogInfo("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
1443 if (sock
->handshake
== handshake_to_be_closed
)
1445 LogInfo("SSLHandshake completed after close");
1446 mDNSPlatformTCPCloseConnection(sock
);
1450 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1451 else LogMsg("doSSLHandshake: sock->fd is -1");
1453 if (err
== errSSLWouldBlock
)
1454 sock
->handshake
= handshake_required
;
1459 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
1460 SSLDisposeContext(sock
->tlsContext
);
1461 sock
->tlsContext
= NULL
;
1464 sock
->err
= err
? mStatus_ConnFailed
: 0;
1465 sock
->handshake
= handshake_completed
;
1467 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
1468 doTcpSocketCallback(sock
);
1472 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
1477 mDNSlocal
void *doSSLHandshake(void *ctx
)
1479 // Warning: Touching sock without the kqueue lock!
1480 // We're protected because sock->handshake == handshake_in_progress
1481 TCPSocket
*sock
= (TCPSocket
*)ctx
;
1482 mDNS
* const m
= sock
->m
; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
1483 mStatus err
= SSLHandshake(sock
->tlsContext
);
1486 debugf("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
1488 if (sock
->handshake
== handshake_to_be_closed
)
1490 LogInfo("SSLHandshake completed after close");
1491 mDNSPlatformTCPCloseConnection(sock
);
1495 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1496 else LogMsg("doSSLHandshake: sock->fd is -1");
1498 if (err
== errSSLWouldBlock
)
1499 sock
->handshake
= handshake_required
;
1504 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
1505 SSLDisposeContext(sock
->tlsContext
);
1506 sock
->tlsContext
= NULL
;
1509 sock
->err
= err
? mStatus_ConnFailed
: 0;
1510 sock
->handshake
= handshake_completed
;
1512 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
1513 doTcpSocketCallback(sock
);
1517 debugf("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
1518 KQueueUnlock(m
, "doSSLHandshake");
1523 mDNSlocal mStatus
spawnSSLHandshake(TCPSocket
* sock
)
1525 debugf("spawnSSLHandshake %p: entry", sock
);
1528 if (sock
->handshake
!= handshake_required
) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock
->handshake
);
1529 sock
->handshake
= handshake_in_progress
;
1530 KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_READ
, sock
->kqEntry
);
1531 #ifdef __LIB_DISPATCH__
1533 // Dispatch it on a separate serial queue to avoid deadlocks with threads running on main queue
1534 dispatch_async(SSLqueue
, ^{doSSLHandshake(sock
);});
1537 pthread_attr_t attr
;
1538 pthread_attr_init(&attr
);
1539 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
1540 err
= pthread_create(&sock
->handshake_thread
, &attr
, doSSLHandshake
, sock
);
1541 pthread_attr_destroy(&attr
);
1544 LogMsg("Could not start SSLHandshake thread: (%d) %s", err
, strerror(err
));
1545 sock
->handshake
= handshake_completed
;
1547 KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1550 debugf("spawnSSLHandshake %p: done for %d", sock
, sock
->fd
);
1554 mDNSlocal mDNSBool
IsTunnelModeDomain(const domainname
*d
)
1556 static const domainname
*mmc
= (const domainname
*) "\x7" "members" "\x3" "mac" "\x3" "com";
1557 const domainname
*d1
= mDNSNULL
; // TLD
1558 const domainname
*d2
= mDNSNULL
; // SLD
1559 const domainname
*d3
= mDNSNULL
;
1560 while (d
->c
[0]) { d3
= d2
; d2
= d1
; d1
= d
; d
= (const domainname
*)(d
->c
+ 1 + d
->c
[0]); }
1561 return(d3
&& SameDomainName(d3
, mmc
));
1564 #endif /* NO_SECURITYFRAMEWORK */
1566 mDNSlocal
void tcpKQSocketCallback(__unused
int fd
, short filter
, void *context
)
1568 TCPSocket
*sock
= context
;
1569 sock
->err
= mStatus_NoError
;
1571 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1572 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1573 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1574 if (filter
== EVFILT_WRITE
) KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_WRITE
, sock
->kqEntry
);
1576 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1578 #ifndef NO_SECURITYFRAMEWORK
1579 if (!sock
->setup
) { sock
->setup
= mDNStrue
; tlsSetupSock(sock
, mDNSfalse
); }
1581 if (sock
->handshake
== handshake_required
) { if (spawnSSLHandshake(sock
) == 0) return; }
1582 else if (sock
->handshake
== handshake_in_progress
|| sock
->handshake
== handshake_to_be_closed
) return;
1583 else if (sock
->handshake
!= handshake_completed
)
1585 if (!sock
->err
) sock
->err
= mStatus_UnknownErr
;
1586 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock
->handshake
);
1589 sock
->err
= mStatus_UnsupportedErr
;
1590 #endif /* NO_SECURITYFRAMEWORK */
1593 doTcpSocketCallback(sock
);
1596 #ifdef __LIB_DISPATCH__
1597 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, KQueueEntry
*const entryRef
)
1599 dispatch_queue_t queue
= dispatch_get_main_queue();
1600 dispatch_source_t source
;
1601 if (flags
== EV_DELETE
)
1603 if (filter
== EVFILT_READ
)
1605 dispatch_source_cancel(entryRef
->readSource
);
1606 dispatch_release(entryRef
->readSource
);
1607 entryRef
->readSource
= mDNSNULL
;
1608 debugf("KQueueSet: source cancel for read %p, %p", entryRef
->readSource
, entryRef
->writeSource
);
1610 else if (filter
== EVFILT_WRITE
)
1612 dispatch_source_cancel(entryRef
->writeSource
);
1613 dispatch_release(entryRef
->writeSource
);
1614 entryRef
->writeSource
= mDNSNULL
;
1615 debugf("KQueueSet: source cancel for write %p, %p", entryRef
->readSource
, entryRef
->writeSource
);
1618 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter
);
1621 if (flags
!= EV_ADD
) LogMsg("KQueueSet: Invalid flags %d", flags
);
1623 if (filter
== EVFILT_READ
)
1625 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, fd
, 0, queue
);
1627 else if (filter
== EVFILT_WRITE
)
1629 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE
, fd
, 0, queue
);
1633 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter
);
1636 if (!source
) return -1;
1637 dispatch_source_set_event_handler(source
, ^{
1639 mDNSs32 stime
= mDNSPlatformRawTime();
1640 entryRef
->KQcallback(fd
, filter
, entryRef
->KQcontext
);
1641 mDNSs32 etime
= mDNSPlatformRawTime();
1642 if (etime
- stime
>= WatchDogReportingThreshold
)
1643 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime
- stime
);
1645 // Trigger the event delivery to the application. Even though we trigger the
1646 // event completion after handling every event source, these all will hopefully
1648 TriggerEventCompletion();
1651 dispatch_source_set_cancel_handler(source
, ^{
1652 if (entryRef
->fdClosed
)
1654 //LogMsg("CancelHandler: closing fd %d", fd);
1658 dispatch_resume(source
);
1659 if (filter
== EVFILT_READ
)
1660 entryRef
->readSource
= source
;
1662 entryRef
->writeSource
= source
;
1667 mDNSexport
void KQueueLock(mDNS
*const m
)
1671 mDNSexport
void KQueueUnlock(mDNS
*const m
, const char const *task
)
1674 (void)task
; //unused
1677 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, const KQueueEntry
*const entryRef
)
1679 struct kevent new_event
;
1680 EV_SET(&new_event
, fd
, filter
, flags
, 0, 0, (void*)entryRef
);
1681 return (kevent(KQueueFD
, &new_event
, 1, NULL
, 0, NULL
) < 0) ? errno
: 0;
1684 mDNSexport
void KQueueLock(mDNS
*const m
)
1686 pthread_mutex_lock(&m
->p
->BigMutex
);
1687 m
->p
->BigMutexStartTime
= mDNSPlatformRawTime();
1690 mDNSexport
void KQueueUnlock(mDNS
*const m
, const char const *task
)
1692 mDNSs32 end
= mDNSPlatformRawTime();
1694 if (end
- m
->p
->BigMutexStartTime
>= WatchDogReportingThreshold
)
1695 LogInfo("WARNING: %s took %dms to complete", task
, end
- m
->p
->BigMutexStartTime
);
1697 pthread_mutex_unlock(&m
->p
->BigMutex
);
1700 if (send(m
->p
->WakeKQueueLoopFD
, &wake
, sizeof(wake
), 0) == -1)
1701 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno
, strerror(errno
));
1705 mDNSexport
void mDNSPlatformCloseFD(KQueueEntry
*kq
, int fd
)
1707 #ifdef __LIB_DISPATCH__
1711 dispatch_source_cancel(kq
->readSource
);
1712 kq
->readSource
= mDNSNULL
;
1714 if (kq
->writeSource
)
1716 dispatch_source_cancel(kq
->writeSource
);
1717 kq
->writeSource
= mDNSNULL
;
1719 // Close happens in the cancellation handler
1720 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd
);
1721 kq
->fdClosed
= mDNStrue
;
1728 mDNSlocal mStatus
SetupTCPSocket(TCPSocket
*sock
, u_short sa_family
, mDNSIPPort
*port
)
1730 KQSocketSet
*cp
= &sock
->ss
;
1732 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1733 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1735 int *s
= &cp
->sktv4
;
1736 KQueueEntry
*k
= &cp
->kqsv4
;
1738 const int on
= 1; // "on" for setsockopt
1741 int skt
= socket(sa_family
, SOCK_STREAM
, IPPROTO_TCP
);
1742 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
1743 if (sa_family
== AF_INET
)
1746 struct sockaddr_in addr
;
1747 mDNSPlatformMemZero(&addr
, sizeof(addr
));
1748 addr
.sin_family
= AF_INET
;
1749 addr
.sin_port
= port
->NotAnInteger
;
1750 err
= bind(skt
, (struct sockaddr
*) &addr
, sizeof(addr
));
1751 if (err
< 0) { LogMsg("ERROR: bind %s", strerror(errno
)); return err
; }
1753 // Receive interface identifiers
1754 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1755 if (err
< 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
)); return err
; }
1757 mDNSPlatformMemZero(&addr
, sizeof(addr
));
1758 socklen_t len
= sizeof(addr
);
1759 err
= getsockname(skt
, (struct sockaddr
*) &addr
, &len
);
1760 if (err
< 0) { LogMsg("getsockname - %s", strerror(errno
)); return err
; }
1762 port
->NotAnInteger
= addr
.sin_port
;
1767 struct sockaddr_in6 addr6
;
1768 mDNSPlatformMemZero(&addr6
, sizeof(addr6
));
1769 addr6
.sin6_family
= AF_INET6
;
1770 addr6
.sin6_port
= port
->NotAnInteger
;
1771 err
= bind(skt
, (struct sockaddr
*) &addr6
, sizeof(addr6
));
1772 if (err
< 0) { LogMsg("ERROR: bind6 %s", strerror(errno
)); return err
; }
1774 // We want to receive destination addresses and receive interface identifiers
1775 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
1776 if (err
< 0) { LogMsg("ERROR: setsockopt IPV6_PKTINFO %s", strerror(errno
)); return err
; }
1778 mDNSPlatformMemZero(&addr6
, sizeof(addr6
));
1779 socklen_t len
= sizeof(addr6
);
1780 err
= getsockname(skt
, (struct sockaddr
*) &addr6
, &len
);
1781 if (err
< 0) { LogMsg("getsockname6 - %s", strerror(errno
)); return err
; }
1783 port
->NotAnInteger
= addr6
.sin6_port
;
1787 k
->KQcallback
= tcpKQSocketCallback
;
1788 k
->KQcontext
= sock
;
1789 k
->KQtask
= "mDNSPlatformTCPSocket";
1790 #ifdef __LIB_DISPATCH__
1791 k
->readSource
= mDNSNULL
;
1792 k
->writeSource
= mDNSNULL
;
1793 k
->fdClosed
= mDNSfalse
;
1795 return mStatus_NoError
;
1798 mDNSexport TCPSocket
*mDNSPlatformTCPSocket(mDNS
*const m
, TCPSocketFlags flags
, mDNSIPPort
*port
)
1803 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket
));
1804 if (!sock
) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL
); }
1806 mDNSPlatformMemZero(sock
, sizeof(TCPSocket
));
1809 sock
->ss
.sktv4
= -1;
1811 sock
->ss
.sktv6
= -1;
1813 err
= SetupTCPSocket(sock
, AF_INET
, port
);
1817 err
= SetupTCPSocket(sock
, AF_INET6
, port
);
1818 if (err
) { mDNSPlatformCloseFD(&sock
->ss
.kqsv4
, sock
->ss
.sktv4
); sock
->ss
.sktv4
= -1; }
1823 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock
->fd
, errno
, strerror(errno
));
1824 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1828 sock
->callback
= mDNSNULL
;
1829 sock
->flags
= flags
;
1830 sock
->context
= mDNSNULL
;
1831 sock
->setup
= mDNSfalse
;
1832 sock
->connected
= mDNSfalse
;
1833 sock
->handshake
= handshake_required
;
1835 sock
->err
= mStatus_NoError
;
1840 mDNSexport mStatus
mDNSPlatformTCPConnect(TCPSocket
*sock
, const mDNSAddr
*dst
, mDNSOpaque16 dstport
, domainname
*hostname
, mDNSInterfaceID InterfaceID
, TCPConnectionCallback callback
, void *context
)
1842 KQSocketSet
*cp
= &sock
->ss
;
1844 int *s
= (dst
->type
== mDNSAddrType_IPv4
) ? &cp
->sktv4
: &cp
->sktv6
;
1845 KQueueEntry
*k
= (dst
->type
== mDNSAddrType_IPv4
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1847 int *s
= &cp
->sktv4
;
1848 KQueueEntry
*k
= &cp
->kqsv4
;
1850 mStatus err
= mStatus_NoError
;
1851 struct sockaddr_storage ss
;
1853 sock
->callback
= callback
;
1854 sock
->context
= context
;
1855 sock
->setup
= mDNSfalse
;
1856 sock
->connected
= mDNSfalse
;
1857 sock
->handshake
= handshake_required
;
1858 sock
->err
= mStatus_NoError
;
1860 if (hostname
) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname
->c
); AssignDomainName(&sock
->hostname
, hostname
); }
1862 if (dst
->type
== mDNSAddrType_IPv4
)
1864 struct sockaddr_in
*saddr
= (struct sockaddr_in
*)&ss
;
1865 mDNSPlatformMemZero(saddr
, sizeof(*saddr
));
1866 saddr
->sin_family
= AF_INET
;
1867 saddr
->sin_port
= dstport
.NotAnInteger
;
1868 saddr
->sin_len
= sizeof(*saddr
);
1869 saddr
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1873 struct sockaddr_in6
*saddr6
= (struct sockaddr_in6
*)&ss
;
1874 mDNSPlatformMemZero(saddr6
, sizeof(*saddr6
));
1875 saddr6
->sin6_family
= AF_INET6
;
1876 saddr6
->sin6_port
= dstport
.NotAnInteger
;
1877 saddr6
->sin6_len
= sizeof(*saddr6
);
1878 saddr6
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1881 // Watch for connect complete (write is ready)
1882 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1883 if (KQueueSet(*s
, EV_ADD
/* | EV_ONESHOT */, EVFILT_WRITE
, k
))
1885 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1889 // Watch for incoming data
1890 if (KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
))
1892 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1896 if (fcntl(*s
, F_SETFL
, fcntl(*s
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
1898 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1899 return mStatus_UnknownErr
;
1902 // We bind to the interface and all subsequent packets including the SYN will be sent out
1903 // on this interface
1905 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
1906 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
1907 if (InterfaceID
&& InterfaceID
!= mDNSInterface_Unicast
)
1909 extern mDNS mDNSStorage
;
1910 NetworkInterfaceInfoOSX
*info
= IfindexToInterfaceInfoOSX(&mDNSStorage
, InterfaceID
);
1911 if (dst
->type
== mDNSAddrType_IPv4
)
1914 if (info
) setsockopt(*s
, IPPROTO_IP
, IP_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1915 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID
); return mStatus_BadParamErr
; }
1917 (void)InterfaceID
; // Unused
1918 (void)info
; // Unused
1923 #ifdef IPV6_BOUND_IF
1924 if (info
) setsockopt(*s
, IPPROTO_IPV6
, IPV6_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1925 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID
); return mStatus_BadParamErr
; }
1927 (void)InterfaceID
; // Unused
1928 (void)info
; // Unused
1933 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
1934 // from which we can infer the destination address family. Hence we need to remember that here.
1935 // Instead of remembering the address family, we remember the right fd.
1938 // initiate connection wth peer
1939 if (connect(*s
, (struct sockaddr
*)&ss
, ss
.ss_len
) < 0)
1941 if (errno
== EINPROGRESS
) return mStatus_ConnPending
;
1942 if (errno
== EHOSTUNREACH
|| errno
== EADDRNOTAVAIL
|| errno
== ENETDOWN
)
1943 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock
->fd
, errno
, strerror(errno
));
1945 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock
->fd
, errno
, strerror(errno
), ss
.ss_len
);
1946 return mStatus_ConnFailed
;
1949 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1950 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1954 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1955 mDNSexport TCPSocket
*mDNSPlatformTCPAccept(TCPSocketFlags flags
, int fd
)
1957 mStatus err
= mStatus_NoError
;
1959 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket
));
1960 if (!sock
) return(mDNSNULL
);
1962 mDNSPlatformMemZero(sock
, sizeof(*sock
));
1964 sock
->flags
= flags
;
1966 if (flags
& kTCPSocketFlags_UseTLS
)
1968 #ifndef NO_SECURITYFRAMEWORK
1969 if (!ServerCerts
) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err
= mStatus_UnknownErr
; goto exit
; }
1971 err
= tlsSetupSock(sock
, mDNStrue
);
1972 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err
); goto exit
; }
1974 err
= SSLSetCertificate(sock
->tlsContext
, ServerCerts
);
1975 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err
); goto exit
; }
1977 err
= mStatus_UnsupportedErr
;
1978 #endif /* NO_SECURITYFRAMEWORK */
1980 #ifndef NO_SECURITYFRAMEWORK
1984 if (err
) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock
); return(mDNSNULL
); }
1988 mDNSlocal
void CloseSocketSet(KQSocketSet
*ss
)
1990 if (ss
->sktv4
!= -1)
1992 mDNSPlatformCloseFD(&ss
->kqsv4
, ss
->sktv4
);
1996 if (ss
->sktv6
!= -1)
1998 mDNSPlatformCloseFD(&ss
->kqsv6
, ss
->sktv6
);
2002 if (ss
->closeFlag
) *ss
->closeFlag
= 1;
2005 mDNSexport
void mDNSPlatformTCPCloseConnection(TCPSocket
*sock
)
2009 #ifndef NO_SECURITYFRAMEWORK
2010 if (sock
->tlsContext
)
2012 if (sock
->handshake
== handshake_in_progress
) // SSLHandshake thread using this sock (esp. tlsContext)
2014 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
2015 sock
->handshake
= handshake_to_be_closed
;
2017 if (sock
->handshake
== handshake_to_be_closed
)
2020 SSLClose(sock
->tlsContext
);
2021 SSLDisposeContext(sock
->tlsContext
);
2022 sock
->tlsContext
= NULL
;
2024 #endif /* NO_SECURITYFRAMEWORK */
2025 if (sock
->ss
.sktv4
!= -1) shutdown(sock
->ss
.sktv4
, 2);
2027 if (sock
->ss
.sktv6
!= -1) shutdown(sock
->ss
.sktv6
, 2);
2029 CloseSocketSet(&sock
->ss
);
2032 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock
);
2036 mDNSexport
long mDNSPlatformReadTCP(TCPSocket
*sock
, void *buf
, unsigned long buflen
, mDNSBool
*closed
)
2039 *closed
= mDNSfalse
;
2041 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
2043 #ifndef NO_SECURITYFRAMEWORK
2044 if (sock
->handshake
== handshake_required
) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
2045 else if (sock
->handshake
== handshake_in_progress
) return 0;
2046 else if (sock
->handshake
!= handshake_completed
) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock
->handshake
);
2048 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
2049 mStatus err
= SSLRead(sock
->tlsContext
, buf
, buflen
, &nread
);
2050 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
2051 if (err
== errSSLClosedGraceful
) { nread
= 0; *closed
= mDNStrue
; }
2052 else if (err
&& err
!= errSSLWouldBlock
)
2053 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err
); nread
= -1; *closed
= mDNStrue
; }
2057 #endif /* NO_SECURITYFRAMEWORK */
2061 static int CLOSEDcount
= 0;
2062 static int EAGAINcount
= 0;
2063 nread
= recv(sock
->fd
, buf
, buflen
, 0);
2065 if (nread
> 0) { CLOSEDcount
= 0; EAGAINcount
= 0; } // On success, clear our error counters
2066 else if (nread
== 0)
2069 if ((++CLOSEDcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock
->fd
, CLOSEDcount
); sleep(1); }
2071 // else nread is negative -- see what kind of error we got
2072 else if (errno
== ECONNRESET
) { nread
= 0; *closed
= mDNStrue
; }
2073 else if (errno
!= EAGAIN
) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno
, strerror(errno
)); nread
= -1; }
2074 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
2077 if ((++EAGAINcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock
->fd
, EAGAINcount
); sleep(1); }
2084 mDNSexport
long mDNSPlatformWriteTCP(TCPSocket
*sock
, const char *msg
, unsigned long len
)
2088 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
2090 #ifndef NO_SECURITYFRAMEWORK
2092 if (sock
->handshake
== handshake_required
) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
2093 if (sock
->handshake
== handshake_in_progress
) return 0;
2094 else if (sock
->handshake
!= handshake_completed
) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock
->handshake
);
2096 mStatus err
= SSLWrite(sock
->tlsContext
, msg
, len
, &processed
);
2098 if (!err
) nsent
= (int) processed
;
2099 else if (err
== errSSLWouldBlock
) nsent
= 0;
2100 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err
); nsent
= -1; }
2103 #endif /* NO_SECURITYFRAMEWORK */
2107 nsent
= send(sock
->fd
, msg
, len
, 0);
2110 if (errno
== EAGAIN
) nsent
= 0;
2111 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno
)); nsent
= -1; }
2118 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
2123 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
2124 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
2125 mDNSlocal mStatus
SetupSocket(KQSocketSet
*cp
, const mDNSIPPort port
, u_short sa_family
, mDNSIPPort
*const outport
)
2128 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
2129 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
2131 int *s
= &cp
->sktv4
;
2132 KQueueEntry
*k
= &cp
->kqsv4
;
2135 const int twofivefive
= 255;
2136 mStatus err
= mStatus_NoError
;
2137 char *errstr
= mDNSNULL
;
2140 if (sa_family
!= AF_INET
) return -1;
2143 cp
->closeFlag
= mDNSNULL
;
2145 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
2146 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
2148 // ... with a shared UDP port, if it's for multicast receiving
2149 if (mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSSameIPPort(port
, NATPMPAnnouncementPort
)) err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
2150 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
2152 if (sa_family
== AF_INET
)
2154 // We want to receive destination addresses
2155 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
2156 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
2158 // We want to receive interface identifiers
2159 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
2160 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
2162 // We want to receive packet TTL value so we can check it
2163 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
2164 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
2166 // Send unicast packets with TTL 255
2167 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
2168 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
2170 // And multicast packets with TTL 255 too
2171 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
2172 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
2174 // And start listening for packets
2175 struct sockaddr_in listening_sockaddr
;
2176 listening_sockaddr
.sin_family
= AF_INET
;
2177 listening_sockaddr
.sin_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
2178 listening_sockaddr
.sin_addr
.s_addr
= mDNSSameIPPort(port
, NATPMPAnnouncementPort
) ? AllHosts_v4
.NotAnInteger
: 0;
2179 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
2180 if (err
) { errstr
= "bind"; goto fail
; }
2181 if (outport
) outport
->NotAnInteger
= listening_sockaddr
.sin_port
;
2184 else if (sa_family
== AF_INET6
)
2186 // NAT-PMP Announcements make no sense on IPv6, so bail early w/o error
2187 if (mDNSSameIPPort(port
, NATPMPAnnouncementPort
)) { if (outport
) *outport
= zeroIPPort
; return mStatus_NoError
; }
2189 // We want to receive destination addresses and receive interface identifiers
2190 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
2191 if (err
< 0) { errstr
= "setsockopt - IPV6_PKTINFO"; goto fail
; }
2193 // We want to receive packet hop count value so we can check it
2194 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
2195 if (err
< 0) { errstr
= "setsockopt - IPV6_HOPLIMIT"; goto fail
; }
2197 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
2198 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
2199 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
2200 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
2202 // Send unicast packets with TTL 255
2203 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
2204 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
2206 // And multicast packets with TTL 255 too
2207 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
2208 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
2210 // Want to receive our own packets
2211 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
2212 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
2214 // And start listening for packets
2215 struct sockaddr_in6 listening_sockaddr6
;
2216 mDNSPlatformMemZero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
2217 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
2218 listening_sockaddr6
.sin6_family
= AF_INET6
;
2219 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
2220 listening_sockaddr6
.sin6_flowinfo
= 0;
2221 listening_sockaddr6
.sin6_addr
= in6addr_any
; // Want to receive multicasts AND unicasts on this socket
2222 listening_sockaddr6
.sin6_scope_id
= 0;
2223 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
2224 if (err
) { errstr
= "bind"; goto fail
; }
2225 if (outport
) outport
->NotAnInteger
= listening_sockaddr6
.sin6_port
;
2229 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
2230 fcntl(skt
, F_SETFD
, 1); // set close-on-exec
2232 k
->KQcallback
= myKQSocketCallBack
;
2234 k
->KQtask
= "UDP packet reception";
2235 #ifdef __LIB_DISPATCH__
2236 k
->readSource
= mDNSNULL
;
2237 k
->writeSource
= mDNSNULL
;
2238 k
->fdClosed
= mDNSfalse
;
2240 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
2245 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
2246 if (strcmp(errstr
, "bind") || mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSIPPortIsZero(port
))
2247 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr
, skt
, mDNSVal16(port
), err
, errno
, strerror(errno
));
2249 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
2250 if (!strcmp(errstr
, "bind") && errno
== EADDRINUSE
)
2253 if (mDNSSameIPPort(port
, MulticastDNSPort
))
2254 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
2255 "Congratulations, you've reproduced an elusive bug.\r"
2256 "Please contact the current assignee of <rdar://problem/3814904>.\r"
2257 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2258 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2261 mDNSPlatformCloseFD(k
, skt
);
2265 mDNSexport UDPSocket
*mDNSPlatformUDPSocket(mDNS
*const m
, const mDNSIPPort requestedport
)
2268 mDNSIPPort port
= requestedport
;
2269 mDNSBool randomizePort
= mDNSIPPortIsZero(requestedport
);
2270 int i
= 10000; // Try at most 10000 times to get a unique random port
2271 UDPSocket
*p
= mallocL("UDPSocket", sizeof(UDPSocket
));
2272 if (!p
) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL
); }
2273 mDNSPlatformMemZero(p
, sizeof(UDPSocket
));
2274 p
->ss
.port
= zeroIPPort
;
2283 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
2284 if (randomizePort
) port
= mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
2285 err
= SetupSocket(&p
->ss
, port
, AF_INET
, &p
->ss
.port
);
2289 err
= SetupSocket(&p
->ss
, port
, AF_INET6
, &p
->ss
.port
);
2290 if (err
) { mDNSPlatformCloseFD(&p
->ss
.kqsv4
, p
->ss
.sktv4
); p
->ss
.sktv4
= -1; }
2294 } while (err
== EADDRINUSE
&& randomizePort
&& i
);
2298 // In customer builds we don't want to log failures with port 5351, because this is a known issue
2299 // of failing to bind to this port when Internet Sharing has already bound to it
2300 // We also don't want to log about port 5350, due to a known bug when some other
2301 // process is bound to it.
2302 if (mDNSSameIPPort(requestedport
, NATPMPPort
) || mDNSSameIPPort(requestedport
, NATPMPAnnouncementPort
))
2303 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
2304 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
2305 freeL("UDPSocket", p
);
2311 mDNSexport
void mDNSPlatformUDPClose(UDPSocket
*sock
)
2313 CloseSocketSet(&sock
->ss
);
2314 freeL("UDPSocket", sock
);
2317 #if COMPILER_LIKES_PRAGMA_MARK
2319 #pragma mark - BPF Raw packet sending/receiving
2322 #if APPLE_OSX_mDNSResponder
2324 mDNSexport
void mDNSPlatformSendRawPacket(const void *const msg
, const mDNSu8
*const end
, mDNSInterfaceID InterfaceID
)
2326 if (!InterfaceID
) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2327 NetworkInterfaceInfoOSX
*info
;
2329 extern mDNS mDNSStorage
;
2330 info
= IfindexToInterfaceInfoOSX(&mDNSStorage
, InterfaceID
);
2333 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID
);
2336 if (info
->BPF_fd
< 0)
2337 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info
->ifinfo
.ifname
, info
->BPF_fd
);
2340 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
2341 if (write(info
->BPF_fd
, msg
, end
- (mDNSu8
*)msg
) < 0)
2342 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info
->BPF_fd
, errno
, strerror(errno
));
2346 mDNSexport
void mDNSPlatformSetLocalAddressCacheEntry(mDNS
*const m
, const mDNSAddr
*const tpa
, const mDNSEthAddr
*const tha
, mDNSInterfaceID InterfaceID
)
2348 if (!InterfaceID
) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
2349 NetworkInterfaceInfoOSX
*info
;
2350 info
= IfindexToInterfaceInfoOSX(m
, InterfaceID
);
2351 if (info
== NULL
) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID
); return; }
2352 // Manually inject an entry into our local ARP cache.
2353 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
2354 if (!mDNS_AddressIsLocalSubnet(m
, InterfaceID
, tpa
))
2355 LogSPS("Don't need address cache entry for %s %#a %.6a", info
->ifinfo
.ifname
, tpa
, tha
);
2358 int result
= mDNSSetLocalAddressCacheEntry(info
->scope_id
, tpa
->type
, tpa
->ip
.v6
.b
, tha
->b
);
2359 if (result
) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info
->ifinfo
.ifname
, tpa
, tha
, result
);
2360 else LogSPS("Set local address cache entry for %s %#a %.6a", info
->ifinfo
.ifname
, tpa
, tha
);
2364 mDNSlocal
void CloseBPF(NetworkInterfaceInfoOSX
*const i
)
2366 LogSPS("%s closing BPF fd %d", i
->ifinfo
.ifname
, i
->BPF_fd
);
2367 #ifdef __LIB_DISPATCH__
2368 // close will happen in the cancel handler
2369 dispatch_source_cancel(i
->BPF_source
);
2372 // Note: MUST NOT close() the underlying native BSD sockets.
2373 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
2374 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
2375 CFRunLoopRemoveSource(i
->m
->p
->CFRunLoop
, i
->BPF_rls
, kCFRunLoopDefaultMode
);
2376 CFRelease(i
->BPF_rls
);
2377 CFSocketInvalidate(i
->BPF_cfs
);
2378 CFRelease(i
->BPF_cfs
);
2381 if (i
->BPF_mcfd
>= 0) { close(i
->BPF_mcfd
); i
->BPF_mcfd
= -1; }
2384 mDNSlocal
void bpf_callback_common(NetworkInterfaceInfoOSX
*info
)
2386 KQueueLock(info
->m
);
2388 // 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
2389 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
2390 if (info
->BPF_fd
< 0) goto exit
;
2392 ssize_t n
= read(info
->BPF_fd
, &info
->m
->imsg
, info
->BPF_len
);
2393 const mDNSu8
*ptr
= (const mDNSu8
*)&info
->m
->imsg
;
2394 const mDNSu8
*end
= (const mDNSu8
*)&info
->m
->imsg
+ n
;
2395 debugf("%3d: bpf_callback got %d bytes on %s", info
->BPF_fd
, n
, info
->ifinfo
.ifname
);
2399 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info
->ifinfo
.ifname
, info
->BPF_fd
, errno
, strerror(errno
));
2406 const struct bpf_hdr
*const bh
= (const struct bpf_hdr
*)ptr
;
2407 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
2408 info
->BPF_fd
, ptr
, bh
->bh_hdrlen
, ptr
+ bh
->bh_hdrlen
, bh
->bh_caplen
, bh
->bh_datalen
,
2409 ptr
+ BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
), end
- (ptr
+ BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
)));
2410 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
2411 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
2412 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
2413 mDNSCoreReceiveRawPacket(info
->m
, ptr
+ bh
->bh_hdrlen
, ptr
+ bh
->bh_hdrlen
+ bh
->bh_caplen
, info
->ifinfo
.InterfaceID
);
2414 ptr
+= BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
);
2417 KQueueUnlock(info
->m
, "bpf_callback");
2419 #ifdef __LIB_DISPATCH__
2420 mDNSlocal
void bpf_callback_dispatch(NetworkInterfaceInfoOSX
*const info
)
2422 bpf_callback_common(info
);
2425 mDNSlocal
void bpf_callback(const CFSocketRef cfs
, const CFSocketCallBackType CallBackType
, const CFDataRef address
, const void *const data
, void *const context
)
2431 bpf_callback_common((NetworkInterfaceInfoOSX
*)context
);
2435 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2437 mDNSlocal
int CountProxyTargets(mDNS
*const m
, NetworkInterfaceInfoOSX
*x
, int *p4
, int *p6
)
2439 int numv4
= 0, numv6
= 0;
2442 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2443 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2445 if (p4
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv4
, &rr
->AddressProxy
.ip
.v4
);
2449 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2450 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
2452 if (p6
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv6
, &rr
->AddressProxy
.ip
.v6
);
2456 if (p4
) *p4
= numv4
;
2457 if (p6
) *p6
= numv6
;
2458 return(numv4
+ numv6
);
2461 mDNSexport
void mDNSPlatformUpdateProxyList(mDNS
*const m
, const mDNSInterfaceID InterfaceID
)
2463 NetworkInterfaceInfoOSX
*x
;
2465 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
2466 for (x
= m
->p
->InterfaceList
; x
; x
= x
->next
) if (x
->ifinfo
.InterfaceID
== InterfaceID
) break;
2468 if (!x
) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID
); return; }
2470 #define MAX_BPF_ADDRS 250
2471 int numv4
= 0, numv6
= 0;
2473 if (CountProxyTargets(m
, x
, &numv4
, &numv6
) > MAX_BPF_ADDRS
)
2475 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4
, numv6
);
2476 if (numv4
> MAX_BPF_ADDRS
) numv4
= MAX_BPF_ADDRS
;
2477 numv6
= MAX_BPF_ADDRS
- numv4
;
2480 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x
->BPF_fd
, x
->ifinfo
.ifname
, &x
->ifinfo
.MAC
, numv4
, numv6
);
2482 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
2483 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
2484 static struct bpf_insn filter
[17 + MAX_BPF_ADDRS
] =
2486 BPF_STMT(BPF_LD
+ BPF_H
+ BPF_ABS
, 12), // 0 Read Ethertype (bytes 12,13)
2488 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
2489 BPF_STMT(BPF_RET
+ BPF_K
, 42), // 2 Return 42-byte ARP
2491 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
2493 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
2494 BPF_STMT(BPF_LD
+ BPF_H
+ BPF_ABS
, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
2495 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
2496 BPF_STMT(BPF_RET
+ BPF_K
, 86), // 7 Return 86-byte ND
2498 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
2499 BPF_STMT(BPF_LD
+ BPF_W
+ BPF_ABS
, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
2502 struct bpf_insn
*pc
= &filter
[9];
2503 struct bpf_insn
*chk6
= pc
+ numv4
+ 1; // numv4 address checks, plus a "return 0"
2504 struct bpf_insn
*fail
= chk6
+ 1 + numv6
; // Get v6 Dst LSW, plus numv6 address checks
2505 struct bpf_insn
*ret4
= fail
+ 1;
2506 struct bpf_insn
*ret6
= ret4
+ 4;
2508 static const struct bpf_insn rf
= BPF_STMT(BPF_RET
+ BPF_K
, 0); // No match: Return nothing
2510 static const struct bpf_insn g6
= BPF_STMT(BPF_LD
+ BPF_W
+ BPF_ABS
, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
2512 static const struct bpf_insn r4a
= BPF_STMT(BPF_LDX
+ BPF_B
+ BPF_MSH
, 14); // Get IP Header length (normally 20)
2513 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)
2514 static const struct bpf_insn r4c
= BPF_STMT(BPF_ALU
+ BPF_ADD
+ BPF_X
, 0); // A += IP Header length
2515 static const struct bpf_insn r4d
= BPF_STMT(BPF_RET
+ BPF_A
, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
2517 static const struct bpf_insn r6a
= BPF_STMT(BPF_RET
+ BPF_K
, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
2519 BPF_SetOffset(&filter
[4], jf
, fail
); // If Ethertype not ARP, IPv4, or IPv6, fail
2520 BPF_SetOffset(&filter
[6], jf
, chk6
); // If IPv6 but not ICMPv6, go to IPv6 address list check
2522 // BPF Byte-Order Note
2523 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
2524 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
2525 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
2526 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
2527 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
2528 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
2529 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
2530 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
2531 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
2532 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
2534 // IPSEC capture size notes:
2535 // 8 bytes UDP header
2536 // 4 bytes Non-ESP Marker
2537 // 28 bytes IKE Header
2539 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
2542 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2543 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2545 mDNSv4Addr a
= rr
->AddressProxy
.ip
.v4
;
2546 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
2547 BPF_SetOffset(pc
, jt
, ret4
);
2549 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];
2554 if (pc
!= chk6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc
, chk6
);
2555 *pc
++ = g6
; // chk6 points here
2557 // First cancel any previous ND group memberships we had, then create a fresh socket
2558 if (x
->BPF_mcfd
>= 0) close(x
->BPF_mcfd
);
2559 x
->BPF_mcfd
= socket(AF_INET6
, SOCK_DGRAM
, 0);
2561 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2562 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
2564 const mDNSv6Addr
*const a
= &rr
->AddressProxy
.ip
.v6
;
2565 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
2566 BPF_SetOffset(pc
, jt
, ret6
);
2568 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];
2571 struct ipv6_mreq i6mr
;
2572 i6mr
.ipv6mr_interface
= x
->scope_id
;
2573 i6mr
.ipv6mr_multiaddr
= *(const struct in6_addr
*)&NDP_prefix
;
2574 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xD] = a
->b
[0xD];
2575 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xE] = a
->b
[0xE];
2576 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xF] = a
->b
[0xF];
2578 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
2579 mStatus err
= setsockopt(x
->BPF_mcfd
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
2580 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
2581 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2583 err
= setsockopt(x
->BPF_mcfd
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
2584 if (err
< 0 && (errno
!= EADDRINUSE
)) // Joining same group twice can give "Address already in use" error -- no need to report that
2585 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2587 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr
.ipv6mr_multiaddr
, a
);
2590 if (pc
!= fail
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc
, fail
);
2591 *pc
++ = rf
; // fail points here
2593 if (pc
!= ret4
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc
, ret4
);
2594 *pc
++ = r4a
; // ret4 points here
2599 if (pc
!= ret6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc
, ret6
);
2600 *pc
++ = r6a
; // ret6 points here
2602 struct bpf_program prog
= { pc
- filter
, filter
};
2605 // For debugging BPF filter program
2607 for (q
=0; q
<prog
.bf_len
; q
++)
2608 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
);
2611 if (!numv4
&& !numv6
)
2613 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
2614 if (m
->timenow
== 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
2615 // Schedule check to see if we can close this BPF_fd now
2616 if (!m
->p
->NetworkChanged
) m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2);
2617 // prog.bf_len = 0; This seems to panic the kernel
2618 if (x
->BPF_fd
< 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
2621 if (ioctl(x
->BPF_fd
, BIOCSETF
, &prog
) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETF(%d) failed %d (%s)", prog
.bf_len
, errno
, strerror(errno
));
2622 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETF(%d) successful", prog
.bf_len
);
2625 mDNSexport
void mDNSPlatformReceiveBPF_fd(mDNS
*const m
, int fd
)
2629 NetworkInterfaceInfoOSX
*i
;
2630 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
) if (i
->BPF_fd
== -2) break;
2631 if (!i
) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd
); close(fd
); }
2634 LogSPS("%s using BPF fd %d", i
->ifinfo
.ifname
, fd
);
2636 struct bpf_version v
;
2637 if (ioctl(fd
, BIOCVERSION
, &v
) < 0)
2638 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2639 else if (BPF_MAJOR_VERSION
!= v
.bv_major
|| BPF_MINOR_VERSION
!= v
.bv_minor
)
2640 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
2641 fd
, i
->ifinfo
.ifname
, BPF_MAJOR_VERSION
, BPF_MINOR_VERSION
, v
.bv_major
, v
.bv_minor
);
2643 if (ioctl(fd
, BIOCGBLEN
, &i
->BPF_len
) < 0)
2644 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2646 if (i
->BPF_len
> sizeof(m
->imsg
))
2648 i
->BPF_len
= sizeof(m
->imsg
);
2649 if (ioctl(fd
, BIOCSBLEN
, &i
->BPF_len
) < 0)
2650 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2651 else LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", i
->BPF_len
);
2654 static const u_int opt_one
= 1;
2655 if (ioctl(fd
, BIOCIMMEDIATE
, &opt_one
) < 0)
2656 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2658 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
2659 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2661 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
2662 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2665 mDNSPlatformMemZero(&ifr
, sizeof(ifr
));
2666 strlcpy(ifr
.ifr_name
, i
->ifinfo
.ifname
, sizeof(ifr
.ifr_name
));
2667 if (ioctl(fd
, BIOCSETIF
, &ifr
) < 0)
2668 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
)); i
->BPF_fd
= -3; }
2671 #ifdef __LIB_DISPATCH__
2673 i
->BPF_source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, fd
, 0, dispatch_get_main_queue());
2674 if (!i
->BPF_source
) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed");return;}
2675 dispatch_source_set_event_handler(i
->BPF_source
, ^{bpf_callback_dispatch(i
);});
2676 dispatch_source_set_cancel_handler(i
->BPF_source
, ^{close(fd
);});
2677 dispatch_resume(i
->BPF_source
);
2679 CFSocketContext myCFSocketContext
= { 0, i
, NULL
, NULL
, NULL
};
2681 i
->BPF_cfs
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
, bpf_callback
, &myCFSocketContext
);
2682 i
->BPF_rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, i
->BPF_cfs
, 0);
2683 CFRunLoopAddSource(i
->m
->p
->CFRunLoop
, i
->BPF_rls
, kCFRunLoopDefaultMode
);
2685 mDNSPlatformUpdateProxyList(m
, i
->ifinfo
.InterfaceID
);
2692 #endif // APPLE_OSX_mDNSResponder
2694 #if COMPILER_LIKES_PRAGMA_MARK
2696 #pragma mark - Key Management
2699 #ifndef NO_SECURITYFRAMEWORK
2700 mDNSlocal CFArrayRef
GetCertChain(SecIdentityRef identity
)
2702 CFMutableArrayRef certChain
= NULL
;
2703 if (!identity
) { LogMsg("getCertChain: identity is NULL"); return(NULL
); }
2704 SecCertificateRef cert
;
2705 OSStatus err
= SecIdentityCopyCertificate(identity
, &cert
);
2706 if (err
|| !cert
) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err
);
2709 SecPolicySearchRef searchRef
;
2710 err
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, &CSSMOID_APPLE_X509_BASIC
, NULL
, &searchRef
);
2711 if (err
|| !searchRef
) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err
);
2714 SecPolicyRef policy
;
2715 err
= SecPolicySearchCopyNext(searchRef
, &policy
);
2716 if (err
|| !policy
) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err
);
2719 CFArrayRef wrappedCert
= CFArrayCreate(NULL
, (const void**) &cert
, 1, &kCFTypeArrayCallBacks
);
2720 if (!wrappedCert
) LogMsg("getCertChain: wrappedCert is NULL");
2724 err
= SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
);
2725 if (err
|| !trust
) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err
);
2728 err
= SecTrustEvaluate(trust
, NULL
);
2729 if (err
) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err
);
2732 CFArrayRef rawCertChain
;
2733 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
2734 err
= SecTrustGetResult(trust
, NULL
, &rawCertChain
, &statusChain
);
2735 if (err
|| !rawCertChain
|| !statusChain
) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err
);
2738 certChain
= CFArrayCreateMutableCopy(NULL
, 0, rawCertChain
);
2739 if (!certChain
) LogMsg("getCertChain: certChain is NULL");
2742 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
2743 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
2744 CFArraySetValueAtIndex(certChain
, 0, identity
);
2745 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
2746 if (CFArrayGetCount(certChain
) > 1) CFArrayRemoveValueAtIndex(certChain
, CFArrayGetCount(certChain
) - 1);
2748 CFRelease(rawCertChain
);
2749 // Do not free statusChain:
2750 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
2751 // certChain: Call the CFRelease function to release this object when you are finished with it.
2752 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
2757 CFRelease(wrappedCert
);
2761 CFRelease(searchRef
);
2767 #endif /* NO_SECURITYFRAMEWORK */
2769 mDNSexport mStatus
mDNSPlatformTLSSetupCerts(void)
2771 #ifdef NO_SECURITYFRAMEWORK
2772 return mStatus_UnsupportedErr
;
2774 SecIdentityRef identity
= nil
;
2775 SecIdentitySearchRef srchRef
= nil
;
2778 // search for "any" identity matching specified key use
2779 // In this app, we expect there to be exactly one
2780 err
= SecIdentitySearchCreate(NULL
, CSSM_KEYUSE_DECRYPT
, &srchRef
);
2781 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err
); return err
; }
2783 err
= SecIdentitySearchCopyNext(srchRef
, &identity
);
2784 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err
); return err
; }
2786 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
2787 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr
; }
2789 // Found one. Call getCertChain to create the correct certificate chain.
2790 ServerCerts
= GetCertChain(identity
);
2791 if (ServerCerts
== nil
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr
; }
2793 return mStatus_NoError
;
2794 #endif /* NO_SECURITYFRAMEWORK */
2797 mDNSexport
void mDNSPlatformTLSTearDownCerts(void)
2799 #ifndef NO_SECURITYFRAMEWORK
2800 if (ServerCerts
) { CFRelease(ServerCerts
); ServerCerts
= NULL
; }
2801 #endif /* NO_SECURITYFRAMEWORK */
2804 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
2805 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
2807 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
2808 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
2811 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
2816 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
2817 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
2819 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
2822 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
2827 mDNSexport mDNSBool
DictionaryIsEnabled(CFDictionaryRef dict
)
2830 CFNumberRef state
= (CFNumberRef
)CFDictionaryGetValue(dict
, CFSTR("Enabled"));
2831 if (!state
) return mDNSfalse
;
2832 if (!CFNumberGetValue(state
, kCFNumberSInt32Type
, &val
))
2833 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse
; }
2834 return val
? mDNStrue
: mDNSfalse
;
2837 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
2839 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
2841 if (sa
->sa_family
== AF_INET
)
2843 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
2844 ip
->type
= mDNSAddrType_IPv4
;
2845 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
2846 return(mStatus_NoError
);
2849 if (sa
->sa_family
== AF_INET6
)
2851 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
2852 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
2853 // value into the second word of the IPv6 link-local address, so they can just
2854 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
2855 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
2856 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
2857 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
2858 ip
->type
= mDNSAddrType_IPv6
;
2859 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
2860 return(mStatus_NoError
);
2863 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
2864 return(mStatus_Invalid
);
2867 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
2869 mDNSEthAddr eth
= zeroEthAddr
;
2870 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetBSSID"), NULL
, NULL
);
2872 LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
2875 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
2878 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, entityname
);
2881 CFRange range
= { 0, 6 }; // Offset, length
2882 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
2883 if (data
&& CFDataGetLength(data
) == 6) CFDataGetBytes(data
, range
, eth
.b
);
2886 CFRelease(entityname
);
2893 mDNSlocal
int GetMAC(mDNSEthAddr
*eth
, u_short ifindex
)
2895 struct ifaddrs
*ifa
;
2896 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
2897 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2899 const struct sockaddr_dl
*const sdl
= (const struct sockaddr_dl
*)ifa
->ifa_addr
;
2900 if (sdl
->sdl_index
== ifindex
)
2901 { mDNSPlatformMemCopy(eth
->b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6); return 0; }
2907 #ifndef SIOCGIFWAKEFLAGS
2908 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
2911 #ifndef IF_WAKE_ON_MAGIC_PACKET
2912 #define IF_WAKE_ON_MAGIC_PACKET 0x01
2915 #ifndef ifr_wake_flags
2916 #define ifr_wake_flags ifr_ifru.ifru_intval
2919 mDNSlocal mDNSBool
NetWakeInterface(NetworkInterfaceInfoOSX
*i
)
2921 if (!MulticastInterface(i
) ) return(mDNSfalse
); // We only use Sleep Proxy Service on multicast-capable interfaces
2922 if (i
->ifa_flags
& IFF_LOOPBACK
) return(mDNSfalse
); // except loopback
2924 int s
= socket(AF_INET
, SOCK_DGRAM
, 0);
2925 if (s
< 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i
->ifinfo
.ifname
, s
, errno
, strerror(errno
)); return(mDNSfalse
); }
2928 strlcpy(ifr
.ifr_name
, i
->ifinfo
.ifname
, sizeof(ifr
.ifr_name
));
2929 if (ioctl(s
, SIOCGIFWAKEFLAGS
, &ifr
) < 0)
2931 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
2932 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
2933 // error code is being returned from the kernel, we need to use the kernel version.
2934 #define KERNEL_EOPNOTSUPP 102
2935 if (errno
!= KERNEL_EOPNOTSUPP
) // "Operation not supported on socket", the expected result on Leopard and earlier
2936 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i
->ifinfo
.ifname
, errno
, strerror(errno
));
2937 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
2938 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
2939 ifr
.ifr_wake_flags
= (errno
== KERNEL_EOPNOTSUPP
&& !(i
)->BSSID
.l
[0] && i
->m
->SystemWakeOnLANEnabled
) ? IF_WAKE_ON_MAGIC_PACKET
: 0;
2944 // 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
2946 LogSPS("%-6s %#-14a %s WOMP", i
->ifinfo
.ifname
, &i
->ifinfo
.ip
, (ifr
.ifr_wake_flags
& IF_WAKE_ON_MAGIC_PACKET
) ? "supports" : "no");
2948 return((ifr
.ifr_wake_flags
& IF_WAKE_ON_MAGIC_PACKET
) != 0);
2951 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
2952 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
2953 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
2954 // (e.g. sa_family not AF_INET or AF_INET6)
2955 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
, mDNSs32 utc
)
2957 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
2958 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
2961 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
2962 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
2964 NetworkInterfaceInfoOSX
**p
;
2965 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
2966 if (scope_id
== (*p
)->scope_id
&&
2967 mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) &&
2968 mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
2970 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, *p
);
2971 (*p
)->Exists
= mDNStrue
;
2972 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
2973 if ((*p
)->LastSeen
!= utc
) (*p
)->AppearanceTime
= utc
;
2975 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
2976 // we may need to start or stop or sleep proxy browse operation
2977 const mDNSBool NetWake
= NetWakeInterface(*p
);
2978 if ((*p
)->ifinfo
.NetWake
!= NetWake
)
2980 (*p
)->ifinfo
.NetWake
= NetWake
;
2981 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
2982 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
2983 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
2984 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
2985 if ((*p
)->Registered
)
2988 if (NetWake
) mDNS_ActivateNetWake_internal (m
, &(*p
)->ifinfo
);
2989 else mDNS_DeactivateNetWake_internal(m
, &(*p
)->ifinfo
);
2997 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
2998 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
2999 if (!i
) return(mDNSNULL
);
3000 mDNSPlatformMemZero(i
, sizeof(NetworkInterfaceInfoOSX
));
3001 i
->ifinfo
.InterfaceID
= (mDNSInterfaceID
)(uintptr_t)scope_id
;
3003 i
->ifinfo
.mask
= mask
;
3004 strlcpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
3005 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
3006 // We can be configured to disable multicast advertisement, but we want to to support
3007 // local-only services, which need a loopback address record.
3008 i
->ifinfo
.Advertise
= m
->DivertMulticastAdvertisements
? ((ifa
->ifa_flags
& IFF_LOOPBACK
) ? mDNStrue
: mDNSfalse
) : m
->AdvertiseLocalAddresses
;
3009 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
3013 i
->Exists
= mDNStrue
;
3014 i
->Flashing
= mDNSfalse
;
3015 i
->Occulting
= mDNSfalse
;
3016 i
->AppearanceTime
= utc
; // Brand new interface; AppearanceTime is now
3018 i
->ifa_flags
= ifa
->ifa_flags
;
3019 i
->scope_id
= scope_id
;
3021 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
3025 i
->Registered
= mDNSNULL
;
3027 // Do this AFTER i->BSSID has been set up
3028 i
->ifinfo
.NetWake
= NetWakeInterface(i
);
3029 GetMAC(&i
->ifinfo
.MAC
, scope_id
);
3030 if (i
->ifinfo
.NetWake
&& !i
->ifinfo
.MAC
.l
[0])
3031 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i
->ifinfo
.MAC
, scope_id
, i
->ifinfo
.ifname
, &ip
);
3037 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
3038 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
3040 NetworkInterfaceInfoOSX
*i
;
3041 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
3042 if (i
->Exists
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
3043 if (!mDNSv4AddressIsLinkLocal(&i
->ifinfo
.ip
.ip
.v4
))
3049 #if APPLE_OSX_mDNSResponder
3051 #if COMPILER_LIKES_PRAGMA_MARK
3053 #pragma mark - AutoTunnel
3056 #define kRacoonPort 4500
3058 static DomainAuthInfo
* AnonymousRacoonConfig
= mDNSNULL
;
3060 // We arbitrarily limit the message size to 128 bytes (which seems sufficient now) so that
3061 // freeing ELogContext is simpler which is treated as opaque quantity in many places
3070 typedef enum { HTTPGet
= 1, HTTPPost
} HTTPOperation
;
3071 typedef enum { ConfigInvalid
= 0, ConfigFetching
, ConfigValid
} ConfigState
;
3072 typedef void (*HTTPClientCallback
)(CFMutableDataRef responseData
, ELogContext
*context
);
3073 #define kReadStreamBufferSize 4096
3074 #define kMaximumResponseSize 32768
3075 #define kHTTPResponseCodeOK 200
3076 #define kHTTPResponseCodeAuthFailure 401
3077 #define kHTTPResponseCodeForbidden 403
3078 #define kHTTPResponseCodeNotFound 404
3080 // eReporter configuration needs to be fetched whenever it becomes stale. We fetch it lazily
3081 // when we send the report.
3082 struct eReporterConfiguration
{
3083 CFDictionaryRef eRDict
;
3084 ConfigState eRState
;
3089 mDNSBool authChecked
;
3090 CFHTTPAuthenticationRef authentication
;
3091 CFMutableDataRef responseData
;
3092 HTTPClientCallback callback
;
3093 ELogContext cbcontext
;
3095 CFStringRef headerFieldName
;
3096 CFStringRef headerFieldValue
;
3099 } HTTPDataStreamContext
;
3102 // Forward declarations
3103 mDNSlocal
void HTTPDataStream(CFStringRef url
, HTTPOperation op
, CFDataRef bodyData
, CFStringRef headerFieldName
,
3104 CFStringRef headerFieldValue
, CFHTTPAuthenticationRef auth
, CFMutableDictionaryRef credentials
,
3105 HTTPClientCallback callback
, ELogContext
*context
);
3106 mDNSlocal
void mDNSReporterLogValidConfig(ELogContext
*elog
);
3108 mDNSlocal
void CancelReadStream(CFReadStreamRef readStream
)
3112 CFReadStreamSetClient(readStream
, kCFStreamEventNone
, NULL
, NULL
);
3113 CFReadStreamUnscheduleFromRunLoop(readStream
, CFRunLoopGetMain(), kCFRunLoopCommonModes
);
3114 CFReadStreamClose(readStream
);
3115 CFRelease(readStream
);
3119 mDNSlocal
void CancelHTTPDataStream(CFReadStreamRef stream
, HTTPDataStreamContext
*context
)
3121 LogInfo("CancelHTTPDataStream: called");
3124 if (context
->authentication
) CFRelease(context
->authentication
);
3125 if (context
->responseData
) CFRelease(context
->responseData
);
3126 if (context
->headerFieldName
) CFRelease(context
->headerFieldName
);
3127 if (context
->headerFieldValue
) CFRelease(context
->headerFieldValue
);
3128 if (context
->bodyData
) CFRelease(context
->bodyData
);
3129 if (context
->url
) CFRelease(context
->url
);
3130 freeL("HTTPDataStreamContext", context
);
3132 CancelReadStream(stream
);
3135 mDNSlocal CFIndex
HTTPResponseCode(CFReadStreamRef stream
)
3137 CFIndex errorCode
= 0;
3138 CFHTTPMessageRef responseHeaders
= (CFHTTPMessageRef
)CFReadStreamCopyProperty(stream
, kCFStreamPropertyHTTPResponseHeader
);
3139 if (responseHeaders
)
3141 errorCode
= CFHTTPMessageGetResponseStatusCode(responseHeaders
);
3142 CFRelease(responseHeaders
);
3147 mDNSlocal
void RetryWithHTTPAuth(HTTPDataStreamContext
*context
, CFReadStreamRef stream
)
3150 DomainAuthInfo
*FoundInList
;
3151 CFMutableDictionaryRef credentials
= NULL
;
3153 // Need to use the same authentication object till it goes invalid
3154 if (!context
->authentication
)
3156 CFHTTPMessageRef responseHeader
= (CFHTTPMessageRef
)CFReadStreamCopyProperty(stream
, kCFStreamPropertyHTTPResponseHeader
);
3157 // Get the authentication information from the response.
3158 context
->authentication
= CFHTTPAuthenticationCreateFromResponse(NULL
, responseHeader
);
3159 CFRelease(responseHeader
);
3162 // Check to see if the authentication is valid for use. Anything could have gone wrong
3163 // from bad credentials to wrong type of authentication etc.
3164 if (!context
->authentication
|| !CFHTTPAuthenticationIsValid(context
->authentication
, &err
))
3166 LogMsg("RetryWithHTTPAuth: ERROR!! Authentication failed");
3167 if (context
->authentication
)
3169 // Check for bad credentials and treat these separately
3170 if (err
.domain
== kCFStreamErrorDomainHTTP
&& (err
.error
== kCFStreamErrorHTTPAuthenticationBadUserName
||
3171 err
.error
== kCFStreamErrorHTTPAuthenticationBadPassword
))
3173 LogMsg("RetryWithHTTPAuth: ERROR!! Bad credentials %d", err
.error
);
3176 CancelHTTPDataStream(stream
, context
);
3180 // Do we need username & password? Not all authentication types require them.
3181 if (CFHTTPAuthenticationRequiresUserNameAndPassword(context
->authentication
))
3183 char username
[MAX_DOMAIN_LABEL
+ 1];
3186 // Use the first BTMM username and password
3187 for (FoundInList
= (&mDNSStorage
)->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
3188 if (!FoundInList
->deltime
&& FoundInList
->AutoTunnel
) break;
3192 LogInfo("RetryHTTPWithAuth: No BTMM credentials");
3193 CancelHTTPDataStream(stream
, context
);
3197 ConvertDomainLabelToCString_unescaped((domainlabel
*)FoundInList
->domain
.c
, username
);
3198 CFStringRef user
= CFStringCreateWithBytes(NULL
, (const mDNSu8
*)username
, strlen(username
), kCFStringEncodingASCII
, false);
3201 LogMsg("RetryHTTPWithAuth: ERROR!! CFStringCreateWithBytes error");
3202 CancelHTTPDataStream(stream
, context
);
3205 CFStringRef pass
= CFStringCreateWithBytes(NULL
, (const mDNSu8
*)FoundInList
->b64keydata
, strlen(FoundInList
->b64keydata
),
3206 kCFStringEncodingASCII
, false);
3209 LogMsg("RetryHTTPWithAuth: ERROR!! CFStringCreateWithBytes error");
3211 CancelHTTPDataStream(stream
, context
);
3214 // Build the credentials dictionary
3215 credentials
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3218 LogMsg("RetryHTTPWithAuth: ERROR!! cannot allocate credentials");
3221 CancelHTTPDataStream(stream
, context
);
3224 CFDictionarySetValue(credentials
, kCFHTTPAuthenticationUsername
, user
);
3225 CFDictionarySetValue(credentials
, kCFHTTPAuthenticationPassword
, pass
);
3231 LogMsg("RetryHTTPWithAuth: ERROR!! Unknown authentication method");
3232 CancelHTTPDataStream(stream
, context
);
3236 HTTPDataStream(context
->url
, context
->op
, context
->bodyData
, context
->headerFieldName
, context
->headerFieldValue
,
3237 context
->authentication
, credentials
, context
->callback
, &context
->cbcontext
);
3239 if (credentials
) CFRelease(credentials
);
3241 // Cancel the old one
3242 CancelHTTPDataStream(stream
, context
);
3245 mDNSlocal
void HTTPDataStreamCallback(CFReadStreamRef stream
, CFStreamEventType type
, void *info
)
3247 HTTPDataStreamContext
*context
= (HTTPDataStreamContext
*)info
;
3250 status
= HTTPResponseCode(stream
);
3252 // if we are forbidden to access, we need to refetch the configuration file.
3253 // For keeping it simple, we don't retry immediately. When the next message
3254 // is logged, we will try getting the config file. If we want to modify this
3255 // in the future to retry now, then we need to know to stop retrying after a
3257 if ((status
== kHTTPResponseCodeNotFound
) || (status
== kHTTPResponseCodeForbidden
))
3259 if (status
== kHTTPResponseCodeNotFound
)
3260 LogMsg("HTTPDataStreamCallback: ERROR!! Config plist cannot be found");
3261 else if (status
== kHTTPResponseCodeForbidden
)
3262 LogInfo("HTTPDataStreamCallback: Config plist Forbidden by server");
3263 if (context
->callback
) context
->callback(context
->responseData
, &context
->cbcontext
);
3264 CancelHTTPDataStream(stream
, context
);
3270 case kCFStreamEventHasBytesAvailable
:
3272 mDNSu8 buffer
[kReadStreamBufferSize
];
3275 if (!context
->authChecked
)
3277 context
->authChecked
= mDNStrue
;
3278 if (status
== kHTTPResponseCodeAuthFailure
)
3280 RetryWithHTTPAuth(context
, stream
);
3285 bytesRead
= CFReadStreamRead(stream
, buffer
, sizeof(buffer
));
3288 CFDataAppendBytes(context
->responseData
, buffer
, bytesRead
);
3289 if (CFDataGetLength(context
->responseData
) > kMaximumResponseSize
)
3291 LogMsg("HTTPDataStreamCallback: ERROR!! Appended max data %d", kMaximumResponseSize
);
3293 else { LogInfo("HTTPDataStreamCallback: successfully appended data of size %ld", bytesRead
); return; }
3295 else if (bytesRead
< 0)
3297 LogMsg("HTTPDataStreamCallback: ERROR!! CFReadStreamRead returned %ld", bytesRead
);
3301 case kCFStreamEventEndEncountered
:
3303 if (!context
->authChecked
)
3305 context
->authChecked
= mDNStrue
;
3306 if (status
== kHTTPResponseCodeAuthFailure
)
3308 RetryWithHTTPAuth(context
, stream
);
3312 if (status
!= kHTTPResponseCodeOK
)
3313 LogMsg("HTTPDataStreamCallback: ERROR!! EndEncountered, statusCode %d, Operation %d", status
, context
->op
);
3315 LogInfo("HTTPDataStreamCallback: HTTP Ok for Operation %d", context
->op
);
3316 if (context
->callback
) context
->callback(context
->responseData
, &context
->cbcontext
);
3319 case kCFStreamEventErrorOccurred
:
3320 LogInfo("HTTPDataStreamCallback: ERROR!! kCFStreamEventErrorOccurred for Operation %d", context
->op
);
3321 if (context
->callback
) context
->callback(context
->responseData
, &context
->cbcontext
);
3324 LogMsg("HTTPDataStreamCallback: ERROR!! default case");
3325 if (context
->callback
) context
->callback(context
->responseData
, &context
->cbcontext
);
3328 CancelHTTPDataStream(stream
, context
);
3331 // Everything needs to be copied or retained locally if need to be accessed beyond function scope
3332 mDNSlocal
void HTTPDataStream(CFStringRef url
, HTTPOperation op
, CFDataRef bodyData
, CFStringRef headerFieldName
,
3333 CFStringRef headerFieldValue
, CFHTTPAuthenticationRef authentication
, CFMutableDictionaryRef credentials
,
3334 HTTPClientCallback callback
, ELogContext
*cbcontext
)
3336 CFURLRef myURL
= NULL
;
3337 CFHTTPMessageRef myRequest
= NULL
;
3338 CFReadStreamRef readStream
= NULL
;
3339 HTTPDataStreamContext
*contextInfo
= NULL
;
3340 CFDictionaryRef proxyDict
= NULL
;
3342 contextInfo
= mallocL("HTTPDataStreamContext", sizeof(HTTPDataStreamContext
));
3343 if (!contextInfo
) { LogMsg("HTTPDataStream: mallocL failure"); return; }
3345 mDNSPlatformMemZero(contextInfo
, sizeof(*contextInfo
));
3346 // Need to remember the state, so that if we need to retry with authentication, we can
3347 // reissue the request
3348 contextInfo
->url
= CFRetain(url
);
3349 contextInfo
->callback
= callback
;
3350 if(cbcontext
) memcpy(&contextInfo
->cbcontext
, cbcontext
, sizeof(ELogContext
));
3351 contextInfo
->authChecked
= mDNSfalse
;
3352 contextInfo
->op
= op
;
3353 if (authentication
) contextInfo
->authentication
= (CFHTTPAuthenticationRef
) CFRetain(authentication
);
3354 if (headerFieldName
) contextInfo
->headerFieldName
= CFRetain(headerFieldName
);
3355 if (headerFieldValue
) contextInfo
->headerFieldValue
= CFRetain(headerFieldValue
);
3356 if (bodyData
) contextInfo
->bodyData
= CFRetain(bodyData
);
3358 myURL
= CFURLCreateWithString(kCFAllocatorDefault
, url
, NULL
);
3359 if (!myURL
) { LogMsg("HTTPDataStream: CFURLCreateWithString error"); goto cleanup
; }
3361 CFStringRef requestMethod
= op
== HTTPGet
? CFSTR("GET") : CFSTR("POST");
3362 myRequest
= CFHTTPMessageCreateRequest(kCFAllocatorDefault
, requestMethod
, myURL
, kCFHTTPVersion1_1
);
3363 if (!myRequest
) { LogMsg("HTTPDataStream: CFHTTPMessageCreateRequest error"); goto cleanup
; }
3365 if (bodyData
) CFHTTPMessageSetBody(myRequest
, bodyData
);
3366 if (headerFieldName
) CFHTTPMessageSetHeaderFieldValue(myRequest
, headerFieldName
, headerFieldValue
);
3370 if (!CFHTTPMessageApplyCredentialDictionary(myRequest
, contextInfo
->authentication
, credentials
, NULL
))
3372 LogMsg("HTTPDataStream: ERROR!! CFHTTPMessageApplyCredentialDictionary error");
3377 readStream
= CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault
, myRequest
);
3378 if (!readStream
) { LogMsg("HTTPDataStream: CFStringCreateWithBytes error"); goto cleanup
; }
3380 proxyDict
= SCDynamicStoreCopyProxies(NULL
);
3383 mDNSBool ret
= CFReadStreamSetProperty(readStream
, kCFStreamPropertyHTTPProxy
, proxyDict
);
3384 CFRelease(proxyDict
);
3387 LogMsg("HTTPDataStream: CFReadStreamSetProperty HTTP proxy failed");
3392 CFOptionFlags events
= kCFStreamEventHasBytesAvailable
| kCFStreamEventErrorOccurred
| kCFStreamEventEndEncountered
;
3394 CFStreamClientContext readContext
= {0, contextInfo
, NULL
, NULL
, NULL
};
3395 CFReadStreamSetClient(readStream
, events
, HTTPDataStreamCallback
, &readContext
);
3396 CFReadStreamScheduleWithRunLoop(readStream
, CFRunLoopGetMain(), kCFRunLoopCommonModes
);
3397 if (CFReadStreamOpen(readStream
))
3399 contextInfo
->responseData
= CFDataCreateMutable(NULL
, 0);
3400 if (contextInfo
->responseData
)
3402 // Release the things that we don't need
3404 CFRelease(myRequest
);
3407 LogMsg("HTTPDataStream: ERROR!! responseData allocation failed");
3409 else LogMsg("HTTPDataStream: ERROR!! CFReadStreamOpen failed");
3411 if (readStream
) CancelReadStream(readStream
);
3412 if (myRequest
) CFRelease(myRequest
);
3413 if (myURL
) CFRelease(myURL
);
3416 if (contextInfo
->authentication
) CFRelease(contextInfo
->authentication
);
3417 if (contextInfo
->headerFieldName
) CFRelease(contextInfo
->headerFieldName
);
3418 if (contextInfo
->headerFieldValue
) CFRelease(contextInfo
->headerFieldValue
);
3419 if (contextInfo
->bodyData
) CFRelease(contextInfo
->bodyData
);
3420 if (contextInfo
->url
) CFRelease(contextInfo
->url
);
3421 freeL("HTTPDataStreamContext", contextInfo
);
3425 mDNSlocal CFStringRef
eReporterGetValueForKey(CFDictionaryRef dict
, char *keyCString
)
3430 key
= CFStringCreateWithCString(NULL
, keyCString
, kCFStringEncodingUTF8
);
3431 if (!CFDictionaryContainsKey(dict
, key
))
3433 LogMsg("eReporterGetValueForKey: ERROR!! key %s not found", keyCString
);
3436 value
= (CFStringRef
)CFDictionaryGetValue(dict
, key
);
3440 LogMsg("eReporterGetValueForKey: ERROR!! value not found for %s", keyCString
);
3446 mDNSlocal
void eReporterConfigCallback(CFMutableDataRef responseData
, ELogContext
*context
)
3448 CFDictionaryRef dict
= NULL
;
3449 char *plistKeys
[] = {"URL", "Publish", "LoadText", "URI", NULL
};
3453 if (!CFDataGetLength(responseData
))
3455 LogInfo("eReporterConfigCallback: Zero length data");
3456 eReporterConfig
.eRState
= ConfigInvalid
;
3459 CFPropertyListFormat format
= kCFPropertyListXMLFormat_v1_0
;
3460 dict
= CFPropertyListCreateWithData(0, responseData
, kCFPropertyListImmutable
, &format
, &error
);
3463 LogMsg("eReporterConfigCallback: Parsing property list failed");
3464 eReporterConfig
.eRState
= ConfigInvalid
;
3469 while (plistKeys
[i
] != NULL
)
3471 if (eReporterGetValueForKey(dict
, plistKeys
[i
]) == NULL
)
3473 LogMsg("eReporterConfigCallback: ERROR!! problem accessing key %s", plistKeys
[i
]);
3475 eReporterConfig
.eRState
= ConfigInvalid
;
3480 if (eReporterConfig
.eRDict
) CFRelease(eReporterConfig
.eRDict
);
3481 eReporterConfig
.eRDict
= dict
;
3482 eReporterConfig
.eRState
= ConfigValid
;
3483 mDNSReporterLogValidConfig(context
);
3486 mDNSlocal mDNSBool
FetchEReporterConfiguration(ELogContext
*context
)
3488 const char *urlString
= "https://configuration.apple.com./configurations/internetservices/e3/mDNSResponder/Configurations1.0.plist";
3489 //const char *urlString = "http://isdev02:9702/configuration/configurations/internetservices/e3/btmm/Configurations1.0.plist"; //dev server
3491 CFStringRef url
= CFStringCreateWithBytes(NULL
, (const mDNSu8
*)urlString
, strlen(urlString
), kCFStringEncodingASCII
, false);
3492 if (!url
) { LogMsg("FetchEReporterConfiguration: CFStringCreateWithBytes error"); return mDNSfalse
; }
3494 if (eReporterConfig
.eRState
== ConfigValid
|| eReporterConfig
.eRState
== ConfigFetching
)
3500 eReporterConfig
.eRState
= ConfigFetching
;
3501 HTTPDataStream(url
, HTTPGet
, NULL
, NULL
, NULL
, NULL
, NULL
, eReporterConfigCallback
, context
);
3506 // Builds an element of type : <key name="nameAttr"> value </key> and attaches it to
3508 mDNSlocal mDNSBool
AddElementToTree(CFXMLTreeRef xmlTree
, char *nameAttr
, char *value
)
3510 /* <key name="BTMM domain"> domain </key> */
3512 CFStringRef textval
= CFStringCreateWithCString(NULL
, value
, kCFStringEncodingUTF8
);
3513 if (!textval
) { LogMsg("AddElementToTree: cannot create CString for value %s", value
); return mDNSfalse
; }
3515 CFStringRef keys
[1] = { CFSTR("name") };
3516 CFStringRef values
[1] = { CFStringCreateWithCString(NULL
, nameAttr
, kCFStringEncodingUTF8
) };
3518 CFDictionaryRef dict
= CFDictionaryCreate(NULL
, (void*)keys
, (void*)values
, 1, &kCFTypeDictionaryKeyCallBacks
,
3519 &kCFTypeDictionaryValueCallBacks
);
3522 LogMsg("AddElementToTree: ERROR!! CFDictionaryCreate failed for %s", nameAttr
);
3524 CFRelease(values
[0]);
3528 CFMutableArrayRef attr
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3531 LogMsg("AddElementToTree: ERROR!! CFArrayCreateMutable failed for %s", nameAttr
);
3534 CFRelease(values
[0]);
3538 CFArrayAppendValue(attr
, keys
[0]);
3540 /* Build <key name="nameAttr"> */
3542 CFXMLElementInfo nameInfo
;
3543 nameInfo
.attributes
= (CFDictionaryRef
)dict
;
3544 nameInfo
.attributeOrder
= (CFArrayRef
) attr
;
3545 nameInfo
.isEmpty
= mDNSfalse
;
3546 CFXMLNodeRef nameNode
= CFXMLNodeCreate(kCFAllocatorDefault
, kCFXMLNodeTypeElement
, CFSTR("key"), &nameInfo
,
3547 kCFXMLNodeCurrentVersion
);
3548 CFXMLTreeRef nameTree
= CFXMLTreeCreateWithNode(kCFAllocatorDefault
, nameNode
);
3549 CFTreeAppendChild(xmlTree
, nameTree
);
3550 CFRelease(nameNode
);
3553 CFRelease(values
[0]);
3555 /* Build the rest: value </key> */
3557 CFXMLNodeRef nameTextNode
= CFXMLNodeCreate(kCFAllocatorDefault
, kCFXMLNodeTypeText
, textval
, NULL
,
3558 kCFXMLNodeCurrentVersion
);
3559 CFXMLTreeRef nameTextTree
= CFXMLTreeCreateWithNode(kCFAllocatorDefault
, nameTextNode
);
3560 CFTreeAppendChild(nameTree
, nameTextTree
);
3561 CFRelease(nameTextTree
);
3562 CFRelease(nameTextNode
);
3565 // Now that we are done with nameTree, we can release it
3566 CFRelease(nameTree
);
3571 mDNSlocal
void LogPOSTArgs(CFStringRef finalURL
, CFStringRef LoadTextName
, CFStringRef LoadTextValue
, CFDataRef bodyData
)
3573 char buf1
[128], buf2
[64], buf3
[64], buf4
[1024];
3575 if (!CFStringGetCString(finalURL
, buf1
, sizeof(buf1
), kCFStringEncodingUTF8
) ||
3576 !CFStringGetCString(LoadTextName
, buf2
, sizeof(buf2
), kCFStringEncodingUTF8
) ||
3577 !CFStringGetCString(LoadTextValue
, buf3
, sizeof(buf3
), kCFStringEncodingUTF8
))
3579 LogMsg("mDNSEReportPOSTArgs: Error in parsing arguments");
3582 CFStringRef bstr
= CFStringCreateFromExternalRepresentation(NULL
, bodyData
, kCFStringEncodingUTF8
);
3584 if (!CFStringGetCString(bstr
, buf4
, sizeof(buf4
), kCFStringEncodingUTF8
))
3586 LogMsg("mDNSEReportPOSTArgs: buf4 cstring conversion problem");
3588 if (bstr
) CFRelease(bstr
);
3589 LogInfo("LogPOSTArgs: URL : %s, LoadTextName: %s, LoadTextValue: %s, bodyData %s", buf1
, buf2
, buf3
, buf4
);
3592 // This function is called when there is a valid configuration for eReporter service
3593 // We add the following:
3595 // <key name="uuid"> uuid </key>
3596 // <key name="Subdomain"> subdomain </key>
3597 // <key name="Message"> message </key>
3598 // <key name="Time"> YYYY-MM-DD HH24:MI:SS </key>
3599 // <key name="SPS"> True/False </key>
3600 // <key name="Result"> Success/Fail </key>
3602 // if result is -1, result won't be added. 1 means "Failed" and 0 means "Success"
3604 mDNSlocal
void mDNSReporterLogValidConfig(ELogContext
*elog
)
3606 CFMutableStringRef finalURL
= NULL
;
3607 CFStringRef LoadTextName
= NULL
;
3608 CFDataRef bodyData
= NULL
;
3610 CFXMLTreeRef appTree
= NULL
;
3612 pub
= (CFBooleanRef
)eReporterGetValueForKey(eReporterConfig
.eRDict
, "Publish");
3615 LogMsg("mDNSReporterLogValidConfig: Publish key does not exist");
3619 Boolean pubVal
= CFBooleanGetValue(pub
);
3622 // Set the config state to invalid so that we will refetch the configuration next time
3623 // in case Publish value changes between now and then
3624 eReporterConfig
.eRState
= ConfigInvalid
;
3625 LogInfo("mDNSReporterLogValidConfig: Value for Publish is %d", pubVal
);
3629 CFXMLDocumentInfo documentInfo
;
3630 documentInfo
.sourceURL
= NULL
;
3631 documentInfo
.encoding
= kCFStringEncodingUTF8
;
3632 CFXMLNodeRef docNode
= CFXMLNodeCreate( kCFAllocatorDefault
, kCFXMLNodeTypeDocument
, CFSTR(""), &documentInfo
,
3633 kCFXMLNodeCurrentVersion
);
3634 CFXMLTreeRef xmlDocument
= CFXMLTreeCreateWithNode(kCFAllocatorDefault
, docNode
);
3637 /* <?xml version="1.0" encoding="utf-8"?> */
3638 CFXMLProcessingInstructionInfo instructionInfo
;
3639 instructionInfo
.dataString
= CFSTR("version=\"1.0\" encoding=\"utf-8\"");
3640 CFXMLNodeRef instructionNode
= CFXMLNodeCreate(NULL
, kCFXMLNodeTypeProcessingInstruction
, CFSTR("xml"),
3641 &instructionInfo
, kCFXMLNodeCurrentVersion
);
3642 CFXMLTreeRef instructionTree
= CFXMLTreeCreateWithNode(kCFAllocatorDefault
, instructionNode
);
3643 CFTreeAppendChild(xmlDocument
, instructionTree
);
3644 CFRelease(instructionTree
);
3645 CFRelease(instructionNode
);
3647 /* Root Element: <app name="mDNSResponder" version="XXX"> */
3649 CFStringRef appKeys
[2] = { CFSTR("name"), CFSTR("version") };
3650 CFStringRef appValues
[2] = { CFStringCreateWithCString(NULL
, "mDNSResponder", kCFStringEncodingUTF8
),
3651 CFStringCreateWithCString(NULL
, STRINGIFY(mDNSResponderVersion
), kCFStringEncodingUTF8
) };
3653 CFDictionaryRef appDict
= CFDictionaryCreate(NULL
, (void*)appKeys
, (void*)appValues
, 2, &kCFTypeDictionaryKeyCallBacks
,
3654 &kCFTypeDictionaryValueCallBacks
);
3655 if (!appDict
) { LogMsg("mDNSEReporterLogValidConfig: CFDictionaryCreate App failed"); goto cleanup
; }
3657 CFMutableArrayRef appAttr
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3658 if (!appAttr
) { LogMsg("mDNSEReporterLogValidConfig: CFArrayCreateMutable App failed"); goto cleanup
; }
3660 CFArrayAppendValue(appAttr
, appKeys
[0]);
3661 CFArrayAppendValue(appAttr
, appKeys
[1]);
3663 CFXMLElementInfo appInfo
;
3664 appInfo
.attributes
= (CFDictionaryRef
) appDict
;
3665 appInfo
.attributeOrder
= (CFArrayRef
) appAttr
;
3666 appInfo
.isEmpty
= mDNSfalse
;
3667 CFXMLNodeRef appNode
= CFXMLNodeCreate ( kCFAllocatorDefault
, kCFXMLNodeTypeElement
, CFSTR("app"), &appInfo
,
3668 kCFXMLNodeCurrentVersion
);
3669 appTree
= CFXMLTreeCreateWithNode(kCFAllocatorDefault
, appNode
);
3670 CFTreeAppendChild(xmlDocument
, appTree
);
3674 CFRelease(appValues
[0]);
3675 CFRelease(appValues
[1]);
3676 // appTree will be released at the end as we will be appeneding other nodes to appTree below
3679 uuid_unparse(elog
->uuid
, uuidStr
);
3680 AddElementToTree(appTree
, "UUID", uuidStr
);
3682 AddElementToTree(appTree
, "Subdomain", elog
->subdomain
);
3683 AddElementToTree(appTree
, "Message", elog
->message
);
3685 char tm_buffer
[128];
3686 time_t t
= time(NULL
);
3687 struct tm
*tm_t
= gmtime(&t
);
3688 mDNS_snprintf(tm_buffer
, sizeof(tm_buffer
), "%4d-%02d-%02d %02d:%02d:%02d", tm_t
->tm_year
+ 1900, tm_t
->tm_mon
+ 1,
3689 tm_t
->tm_mday
, tm_t
->tm_hour
, tm_t
->tm_min
, tm_t
->tm_sec
);
3690 AddElementToTree(appTree
, "Time", tm_buffer
);
3692 const CacheRecord
*sps
[3] = { mDNSNULL
};
3693 NetworkInterfaceInfo
*intf
;
3694 mDNSBool SleepProxy
= mDNSfalse
;
3695 for (intf
= GetFirstActiveInterface(mDNSStorage
.HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
3699 FindSPSInCache(&mDNSStorage
, &intf
->NetWakeBrowse
, sps
);
3702 SleepProxy
= mDNStrue
;
3706 else { LogInfo("mDNSEReporterValidConfig: NetWake is not set %p", intf
->InterfaceID
); }
3708 AddElementToTree(appTree
, "SPS", (SleepProxy
? "True" : "False"));
3710 if (elog
->result
!= -1)
3711 AddElementToTree(appTree
, "Result", elog
->result
? "fail" : "success");
3713 bodyData
= CFXMLTreeCreateXMLData(NULL
, xmlDocument
);
3714 if (!bodyData
) { LogMsg("mDNSEReporterLogValidConfig: CFXMLTreeCreateData failed for bodyData"); goto cleanup
; }
3716 CFStringRef url
= eReporterGetValueForKey(eReporterConfig
.eRDict
, "URL");
3717 if (!url
) { LogMsg("mDNSEReporterLogValidConfig: eReporterGetValueForKey failed for URL"); goto cleanup
; }
3719 CFStringRef uri
= eReporterGetValueForKey(eReporterConfig
.eRDict
, "URI");
3720 if (!uri
) { LogMsg("mDNSEReporterLogValidConfig: eReporterGetValueForKey failed for URI"); goto cleanup
; }
3722 finalURL
= CFStringCreateMutable(NULL
, 0);
3723 if (!finalURL
) { LogMsg("mDNSEReporterLogValidConfig: CFStringCreateMutable failed for finalURL"); goto cleanup
; }
3725 CFStringAppend(finalURL
, url
);
3726 CFStringAppend(finalURL
, uri
);
3728 LoadTextName
= CFStringCreateWithCString(NULL
, "x-LoadText", kCFStringEncodingUTF8
);
3729 if (!LoadTextName
) { LogMsg("mDNSEReporterLogValidConfig: CFStringCreateWithCString failed for LoadText"); goto cleanup
; }
3731 CFStringRef LoadTextValue
= eReporterGetValueForKey(eReporterConfig
.eRDict
, "LoadText");
3732 if (!LoadTextValue
) { LogMsg("mDNSEReporterLogValidConfig: eReporterGetValueForKey failed for LoadTextValue"); goto cleanup
; }
3734 LogPOSTArgs(finalURL
, LoadTextName
, LoadTextValue
, bodyData
);
3736 // we don't have a callback for the POST. If there is an error in POST, it will be logged
3737 // by the callback of HTTPDataStream
3738 HTTPDataStream(finalURL
, HTTPPost
, bodyData
, LoadTextName
, LoadTextValue
, NULL
, NULL
, NULL
, NULL
);
3741 // Free whatever was allocated in this function
3742 if (bodyData
) CFRelease(bodyData
);
3743 if (finalURL
) CFRelease(finalURL
);
3744 if (LoadTextName
) CFRelease(LoadTextName
);
3745 if (appTree
) CFRelease(appTree
);
3746 CFRelease(xmlDocument
);
3749 mDNSlocal
void mDNSEReporterLog(uuid_t
*uuid
, const char *subdomain
, int result
, char *message
)
3751 // We allocate ELogContext and free it at the end of the function. It is the
3752 // responsibility of the called function to copy it if it needs to hold
3754 ELogContext
*info
= mallocL("ELogContext", sizeof (ELogContext
));
3755 if (!info
) { LogMsg("mDNSEReporterLog: malloc failed"); return; }
3757 // Take a local copy of all the log information
3758 strlcpy(info
->subdomain
, subdomain
, sizeof(info
->subdomain
));
3759 strlcpy(info
->message
, message
, sizeof(info
->message
));
3760 info
->result
= result
;
3761 uuid_copy(info
->uuid
, *uuid
);
3762 if (eReporterConfig
.eRState
!= ConfigValid
)
3764 // Currently we can't have two outstanding configuration fetches. If we have two quick
3765 // back to back logs while the configuration is being fetched, we log only the first
3766 // message to EReporter. If the configuration is valid (common case), then we don't
3767 // drop any messages
3768 if (!FetchEReporterConfiguration(info
))
3770 LogInfo("mDNSEReporterLog: Configuration being fetched.., Not logging");
3772 freeL("ELogContext", info
);
3775 mDNSReporterLogValidConfig(info
);
3776 freeL("ELogContext", info
);
3779 #ifndef NO_SECURITYFRAMEWORK
3781 static CFMutableDictionaryRef domainStatusDict
= NULL
;
3783 // MUST be called with lock held
3784 mDNSlocal
void RemoveAutoTunnelDomainStatus(const mDNS
*const m
, const DomainAuthInfo
*const info
)
3789 LogInfo("RemoveAutoTunnelDomainStatus: %##s", info
->domain
.c
);
3791 if (!domainStatusDict
) { LogMsg("RemoveAutoTunnelDomainStatus: No domainStatusDict"); return; }
3793 buffer
[mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", info
->domain
.c
) - 1] = 0;
3794 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3795 if (!domain
) { LogMsg("RemoveAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3797 if (CFDictionaryContainsKey(domainStatusDict
, domain
))
3799 CFDictionaryRemoveValue(domainStatusDict
, domain
);
3800 if (!m
->ShutdownTime
) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, mDNSNULL
, domainStatusDict
);
3805 mDNSlocal mStatus
CheckQuestionForStatus(const DNSQuestion
*const q
)
3809 if (q
->servAddr
.type
== mDNSAddrType_IPv4
&& mDNSIPv4AddressIsOnes(q
->servAddr
.ip
.v4
))
3810 return mStatus_NoSuchRecord
;
3811 else if (q
->state
== LLQ_Poll
)
3812 return mStatus_PollingMode
;
3813 else if (q
->state
!= LLQ_Established
&& !q
->DuplicateOf
)
3814 return mStatus_TransientErr
;
3817 return mStatus_NoError
;
3820 mDNSlocal mStatus
UpdateLLQStatus(const mDNS
*const m
, char *buffer
, int bufsz
, const DomainAuthInfo
*const info
)
3822 mStatus status
= mStatus_NoError
;
3823 DNSQuestion
* q
, *worst_q
= mDNSNULL
;
3824 for (q
= m
->Questions
; q
; q
=q
->next
)
3825 if (q
->AuthInfo
== info
)
3827 mStatus newStatus
= CheckQuestionForStatus(q
);
3828 if (newStatus
== mStatus_NoSuchRecord
) { status
= newStatus
; worst_q
= q
; break; }
3829 else if (newStatus
== mStatus_PollingMode
) { status
= newStatus
; worst_q
= q
; }
3830 else if (newStatus
== mStatus_TransientErr
&& status
== mStatus_NoError
) { status
= newStatus
; worst_q
= q
; }
3833 if (status
== mStatus_NoError
) mDNS_snprintf(buffer
, bufsz
, "Success");
3834 else if (status
== mStatus_NoSuchRecord
) mDNS_snprintf(buffer
, bufsz
, "GetZoneData %s: %##s", worst_q
->nta
? "not yet complete" : "failed", worst_q
->qname
.c
);
3835 else if (status
== mStatus_PollingMode
) mDNS_snprintf(buffer
, bufsz
, "Query polling %##s", worst_q
->qname
.c
);
3836 else if (status
== mStatus_TransientErr
) mDNS_snprintf(buffer
, bufsz
, "Query not yet established %##s", worst_q
->qname
.c
);
3840 mDNSlocal mStatus
UpdateRRStatus(const mDNS
*const m
, char *buffer
, int bufsz
, const DomainAuthInfo
*const info
)
3844 if (info
->deltime
) return mStatus_NoError
;
3845 for (r
= m
->ResourceRecords
; r
; r
= r
->next
)
3847 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
3848 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
3849 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
3850 // has already checked
3851 const domainname
*n
= r
->resrec
.name
;
3854 DomainAuthInfo
*ptr
;
3855 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
3856 if (SameDomainName(&ptr
->domain
, n
))
3858 if (ptr
== info
&& r
->updateError
== mStatus_BadSig
)
3860 mDNS_snprintf(buffer
, bufsz
, "Resource record update failed for %##s", r
->resrec
.name
);
3861 return r
->updateError
;
3864 n
= (const domainname
*)(n
->c
+ 1 + n
->c
[0]);
3867 return mStatus_NoError
;
3870 #endif // ndef NO_SECURITYFRAMEWORK
3872 // MUST be called with lock held
3873 mDNSlocal
void UpdateAutoTunnelDomainStatus(const mDNS
*const m
, const DomainAuthInfo
*const info
)
3875 #ifdef NO_SECURITYFRAMEWORK
3879 const NATTraversalInfo
*const llq
= m
->LLQNAT
.clientContext
? &m
->LLQNAT
: mDNSNULL
;
3880 const NATTraversalInfo
*const tun
= info
->AutoTunnelNAT
.clientContext
? &info
->AutoTunnelNAT
: mDNSNULL
;
3882 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3883 CFStringRef domain
= NULL
;
3884 CFStringRef tmp
= NULL
;
3885 CFNumberRef num
= NULL
;
3886 mStatus status
= mStatus_NoError
;
3888 if (!m
->mDNS_busy
) LogMsg("UpdateAutoTunnelDomainStatus: ERROR!! Lock not held");
3889 if (!domainStatusDict
)
3891 domainStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3892 if (!domainStatusDict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
3895 if (!dict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
3897 buffer
[mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", info
->domain
.c
) - 1] = 0;
3898 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3899 if (!domain
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3901 mDNS_snprintf(buffer
, sizeof(buffer
), "%#a", &m
->Router
);
3902 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3904 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
3907 CFDictionarySetValue(dict
, CFSTR("RouterAddress"), tmp
);
3911 mDNS_snprintf(buffer
, sizeof(buffer
), "%.4a", &m
->ExternalAddress
);
3912 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3914 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
3917 CFDictionarySetValue(dict
, CFSTR("ExternalAddress"), tmp
);
3923 mDNSu32 port
= mDNSVal16(llq
->ExternalPort
);
3925 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
3927 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
3930 CFDictionarySetValue(dict
, CFSTR("LLQExternalPort"), num
);
3936 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &llq
->Result
);
3938 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
3941 CFDictionarySetValue(dict
, CFSTR("LLQNPMStatus"), num
);
3949 mDNSu32 port
= mDNSVal16(tun
->ExternalPort
);
3951 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
3953 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
3956 CFDictionarySetValue(dict
, CFSTR("AutoTunnelExternalPort"), num
);
3962 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tun
->Result
);
3964 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
3967 CFDictionarySetValue(dict
, CFSTR("AutoTunnelNPMStatus"), num
);
3974 mDNSu32 code
= m
->LastNATMapResultCode
;
3976 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &code
);
3978 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
3981 CFDictionarySetValue(dict
, CFSTR("LastNATMapResultCode"), num
);
3986 // If we have a relay address, check the LLQ status as they don't go over the relay connection.
3987 // If LLQs fail, then report failure. In future, when LLQs go over the relay connection, we don't
3989 if (!mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
))
3991 // If we have a bad signature error updating RR, it overrides any error as
3992 // the user needs to be notified immediately
3993 status
= UpdateRRStatus(m
, buffer
, sizeof(buffer
), info
);
3994 if (status
== mStatus_NoError
)
3996 status
= UpdateLLQStatus(m
, buffer
, sizeof(buffer
), info
);
3997 if (status
== mStatus_PollingMode
)
3999 // If we have a relay connection and we are in polling mode, report as success.
4000 // This normally happens when we are behind Double NAT or NAT with UPnP/NAT-PMP
4001 // disabled but we are able to successfully file share/screen share with the help
4002 // of the relay connection. As it just affects the discovery/update of the other
4003 // BTMM hosts, we consider it as minor issue and report it as success.
4004 LogInfo("UpdateAutoTunnelDomainStatus:NonzeroRelayAddress: Polling reported as success");
4005 status
= mStatus_NoError
;
4006 mDNS_snprintf(buffer
, sizeof(buffer
), "Success");
4009 LogInfo("UpdateAutoTunnelDomainStatus:NonzeroRelayAddress: Status %d, %s", status
, buffer
);
4011 else if (!llq
&& !tun
)
4013 status
= mStatus_NotInitializedErr
;
4014 mDNS_snprintf(buffer
, sizeof(buffer
), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
4016 else if ((llq
&& llq
->Result
== mStatus_DoubleNAT
) || (tun
&& tun
->Result
== mStatus_DoubleNAT
))
4018 status
= mStatus_DoubleNAT
;
4019 mDNS_snprintf(buffer
, sizeof(buffer
), "Double NAT: Router is reporting an external address");
4021 else if ((llq
&& llq
->Result
== mStatus_NATPortMappingDisabled
) || (tun
&& tun
->Result
== mStatus_NATPortMappingDisabled
) ||
4022 (m
->LastNATMapResultCode
== NATErr_Refused
&& ((llq
&& !llq
->Result
&& mDNSIPPortIsZero(llq
->ExternalPort
)) || (tun
&& !tun
->Result
&& mDNSIPPortIsZero(tun
->ExternalPort
)))))
4024 status
= mStatus_NATPortMappingDisabled
;
4025 mDNS_snprintf(buffer
, sizeof(buffer
), "NAT-PMP is disabled on the router");
4027 else if ((llq
&& llq
->Result
) || (tun
&& tun
->Result
))
4029 status
= mStatus_NATTraversal
;
4030 mDNS_snprintf(buffer
, sizeof(buffer
), "Error obtaining NAT port mapping from router");
4032 else if (m
->Router
.type
== mDNSAddrType_None
)
4034 status
= mStatus_NoRouter
;
4035 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - none");
4037 else if (m
->Router
.type
== mDNSAddrType_IPv4
&& mDNSIPv4AddressIsZero(m
->Router
.ip
.v4
))
4039 status
= mStatus_NoRouter
;
4040 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - v4 zero");
4042 else if ((llq
&& mDNSIPPortIsZero(llq
->ExternalPort
)) || (tun
&& mDNSIPPortIsZero(tun
->ExternalPort
)))
4044 status
= mStatus_NATTraversal
;
4045 mDNS_snprintf(buffer
, sizeof(buffer
), "Unable to obtain NAT port mapping from router");
4049 status
= UpdateRRStatus(m
, buffer
, sizeof(buffer
), info
);
4050 if (status
== mStatus_NoError
)
4051 status
= UpdateLLQStatus(m
, buffer
, sizeof(buffer
), info
);
4052 LogInfo("UpdateAutoTunnelDomainStatus:ZeroRelayAddress: Status %d, %s", status
, buffer
);
4055 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
);
4057 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
4060 CFDictionarySetValue(dict
, CFSTR("StatusCode"), num
);
4064 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
4066 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
4069 CFDictionarySetValue(dict
, CFSTR("StatusMessage"), tmp
);
4073 if (!CFDictionaryContainsKey(domainStatusDict
, domain
) ||
4074 !CFEqual(dict
, (CFMutableDictionaryRef
)CFDictionaryGetValue(domainStatusDict
, domain
)))
4076 CFDictionarySetValue(domainStatusDict
, domain
, dict
);
4077 if (!m
->ShutdownTime
)
4079 static char statusBuf
[16];
4080 mDNS_snprintf(statusBuf
, sizeof(statusBuf
), "%d", (int)status
);
4081 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.domainstatus", status
? "failure" : "success", statusBuf
, "");
4082 mDNSEReporterLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.domainstatus", status
, statusBuf
);
4083 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, mDNSNULL
, domainStatusDict
);
4091 debugf("UpdateAutoTunnelDomainStatus: %s", buffer
);
4092 #endif // def NO_SECURITYFRAMEWORK
4095 // MUST be called with lock held
4096 mDNSexport
void UpdateAutoTunnelDomainStatuses(const mDNS
*const m
)
4098 #ifdef NO_SECURITYFRAMEWORK
4101 if (!m
->mDNS_busy
) LogMsg("UpdateAutoTunnelDomainStatuses: ERROR!! Lock not held");
4102 DomainAuthInfo
* info
;
4103 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
4104 if (info
->AutoTunnel
&& !info
->deltime
)
4105 UpdateAutoTunnelDomainStatus(m
, info
);
4106 #endif // def NO_SECURITYFRAMEWORK
4109 // MUST be called with lock held
4110 mDNSlocal mDNSBool
TunnelServers(mDNS
*const m
)
4113 for (r
= m
->ResourceRecords
; r
; r
= r
->next
)
4114 if (r
->resrec
.rrtype
== kDNSType_SRV
)
4116 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, r
->resrec
.name
);
4117 if (AuthInfo
&& AuthInfo
->AutoTunnel
&& !AuthInfo
->deltime
) return(mDNStrue
);
4123 // MUST be called with lock held
4124 mDNSlocal mDNSBool
TunnelClients(mDNS
*const m
)
4127 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
4128 if (p
->q
.ThisQInterval
< 0)
4133 mDNSlocal
void UpdateAnonymousRacoonConfig(mDNS
*m
) // Determine whether we need racoon to accept incoming connections
4135 DomainAuthInfo
*info
;
4137 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
4138 if (info
->AutoTunnel
&& !info
->deltime
&& (!mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) || !mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
)))
4141 if (info
!= AnonymousRacoonConfig
)
4143 AnonymousRacoonConfig
= info
;
4144 // Create or revert configuration file, and start (or SIGHUP) Racoon
4145 (void)mDNSConfigureServer(AnonymousRacoonConfig
? kmDNSUp
: kmDNSDown
, AnonymousRacoonConfig
? &AnonymousRacoonConfig
->domain
: mDNSNULL
);
4149 // Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
4150 // sometimes the caller may already be holding the lock e.g., RegisterAutoTunnel6Record and sometimes
4151 // not e.g., RegisterAutoTunnelServiceRecord
4152 mDNSlocal
void RegisterAutoTunnelHostRecord(mDNS
*m
, DomainAuthInfo
*info
)
4155 mDNSBool NATProblem
;
4157 if (!m
->mDNS_busy
) LogMsg("RegisterAutoTunnelHostRecord: ERROR!! Lock not held");
4159 // We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
4160 // called at least once with some Services/Records in the domain and hence it is safe to register
4161 // records when this function is called.
4162 if (!info
->AutoTunnelNAT
.clientContext
) { LogInfo("RegisterAutoTunnelHostRecord: No services registered, not registering the record\n"); return; }
4164 // Are we behind a NAT with no NAT-PMP support or behind a Double NAT ? Double NATs may have
4165 // NAT-PMP support but it still does not provide inbound connectivity. If there is no NAT-PMP
4166 // support, ExternalPort is zero. If we are behind a Double NAT, then the NATResult is non-zero.
4168 NATProblem
= mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) || info
->AutoTunnelNAT
.Result
;
4170 if (mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
))
4172 // If we don't have a relay address, check to see if we are behind a Double NAT or NAT with no NAT-PMP
4176 LogInfo("RegisterAutoTunnelHostRecord %##s, not registering the Host Record, Neither AutoTunnel6 nor NAT is available, ClientContext %p, ExternalPort %d, NAT Result %d", info
->domain
.c
, info
->AutoTunnelNAT
.clientContext
, mDNSVal16(info
->AutoTunnelNAT
.ExternalPort
), info
->AutoTunnelNAT
.Result
);
4182 // Relay address may be non-zero but we might be going to sleep as the utun interface is not removed
4183 // when going to sleep. If we are awake, we don't care about the NATProblem as the relay connnection
4184 // is up. If we are going to sleep, we should not register the host record if we have a NAT problem.
4185 if (m
->SleepState
!= SleepState_Awake
&& NATProblem
)
4187 LogInfo("RegisterAutoTunnelHostRecord %##s, not registering the Host Record, Not in awake state(%d), and some NAT Problem, ClientContext %p, ExternalPort %d, NAT Result %d", info
->domain
.c
, m
->SleepState
, info
->AutoTunnelNAT
.clientContext
, mDNSVal16(info
->AutoTunnelNAT
.ExternalPort
), info
->AutoTunnelNAT
.Result
);
4194 // We use zero Requested port to infer that we should not be calling Register anymore as it might
4195 // be shutdown or the DomainAuthInfo is going away.
4197 // We can use a different set of state variables to track the above as the records registered in
4198 // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
4199 // reuse the NAT variables.
4201 // Set up our address record for the internal tunnel address
4202 // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
4203 if (!mDNSIPPortIsZero(info
->AutoTunnelNAT
.RequestedPort
) && info
->AutoTunnelHostRecord
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4205 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
4206 AppendDomainLabel(&info
->AutoTunnelHostRecord
.namestorage
, &m
->hostlabel
);
4207 AppendDomainName (&info
->AutoTunnelHostRecord
.namestorage
, &info
->domain
);
4208 info
->AutoTunnelHostRecord
.resrec
.rdata
->u
.ipv6
= m
->AutoTunnelHostAddr
;
4209 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4211 err
= mDNS_Register_internal(m
, &info
->AutoTunnelHostRecord
);
4213 if (err
) LogMsg("RegisterAutoTunnelHostRecord error %d registering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
4216 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
4217 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4218 LogInfo("RegisterAutoTunnelHostRecord registering AutoTunnelHostRecord %##s", info
->AutoTunnelHostRecord
.namestorage
.c
);
4221 else LogInfo("RegisterAutoTunnelHostRecord: Not registering Context %p Port %d Type %d", info
->AutoTunnelNAT
.clientContext
, mDNSVal16(info
->AutoTunnelNAT
.RequestedPort
), info
->AutoTunnelHostRecord
.resrec
.RecordType
);
4224 mDNSlocal
void DeregisterAutoTunnelHostRecord(mDNS
*m
, DomainAuthInfo
*info
)
4226 LogInfo("DeregisterAutoTunnelHostRecord %##s", info
->domain
.c
);
4228 // Don't deregister if we have the AutoTunnel6 or AutoTunnelService records are registered.
4229 // They indicate that BTMM is working
4230 if (info
->AutoTunnel6Record
.resrec
.RecordType
> kDNSRecordTypeDeregistering
||
4231 info
->AutoTunnelService
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
4233 LogInfo("DeregisterAutoTunnelHostRecord %##s, not deregistering the Host Record AutoTunnel6 RecordType:%d AutoTunnel RecordType: %d", info
->domain
.c
,
4234 info
->AutoTunnel6Record
.resrec
.RecordType
, info
->AutoTunnelService
.resrec
.RecordType
);
4238 if (info
->AutoTunnelHostRecord
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
4240 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelHostRecord
);
4243 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
4244 LogMsg("DeregisterAutoTunnelHostRecord error %d deregistering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
4246 else LogInfo("DeregisterAutoTunnelHostRecord: Deregistered AutoTunnel Host Record");
4248 else LogInfo("DeregisterAutoTunnelHostRecord: Not deregistering Host Record state:%d", info
->AutoTunnelHostRecord
.resrec
.RecordType
);
4251 mDNSlocal
void RegisterAutoTunnelServiceRecords(mDNS
*m
, DomainAuthInfo
*info
)
4255 //if (m->mDNS_busy) LogMsg("RegisterAutoTunnelServiceRecords: ERROR!! Lock already held");
4257 if (info
->AutoTunnelNAT
.clientContext
&& !info
->AutoTunnelNAT
.Result
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) && info
->AutoTunnelTarget
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4259 LogInfo("RegisterAutoTunnelServiceRecords %##s (%#s)", info
->domain
.c
, m
->hostlabel
.c
);
4261 // 1. Set up our address record for the external tunnel address
4262 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
4263 info
->AutoTunnelTarget
.namestorage
.c
[0] = 0;
4264 AppendDomainLabel(&info
->AutoTunnelTarget
.namestorage
, &m
->AutoTunnelLabel
);
4265 AppendDomainName (&info
->AutoTunnelTarget
.namestorage
, &info
->domain
);
4266 info
->AutoTunnelTarget
.resrec
.rdata
->u
.ipv4
= info
->AutoTunnelNAT
.ExternalAddress
;
4267 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4269 err
= mDNS_Register(m
, &info
->AutoTunnelTarget
);
4270 if (err
) LogMsg("RegisterAutoTunnelServiceRecords error %d registering AutoTunnelTarget %##s", err
, info
->AutoTunnelTarget
.namestorage
.c
);
4271 else LogInfo("RegisterAutoTunnelServiceRecords registering AutoTunnelTarget %##s", info
->AutoTunnelTarget
.namestorage
.c
);
4275 if (info
->AutoTunnelNAT
.clientContext
&& !info
->AutoTunnelNAT
.Result
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) && info
->AutoTunnelService
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4277 // 2. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
4278 AssignDomainName (&info
->AutoTunnelService
.namestorage
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
4279 AppendDomainLabel(&info
->AutoTunnelService
.namestorage
, &m
->hostlabel
);
4280 AppendDomainName (&info
->AutoTunnelService
.namestorage
, &info
->domain
);
4281 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.priority
= 0;
4282 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.weight
= 0;
4283 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.port
= info
->AutoTunnelNAT
.ExternalPort
;
4284 AssignDomainName(&info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.target
, &info
->AutoTunnelTarget
.namestorage
);
4285 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4286 err
= mDNS_Register(m
, &info
->AutoTunnelService
);
4287 if (err
) LogMsg("RegisterAutoTunnelServiceRecords error %d registering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
4288 else LogInfo("RegisterAutoTunnelServiceRecords registering AutoTunnelService %##s", info
->AutoTunnelService
.namestorage
.c
);
4290 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
4291 info
->AutoTunnelTarget
.namestorage
.c
, &m
->AdvertisedV4
.ip
.v4
, mDNSVal16(info
->AutoTunnelNAT
.IntPort
),
4292 info
->AutoTunnelHostRecord
.namestorage
.c
, &m
->AutoTunnelHostAddr
);
4295 RegisterAutoTunnelHostRecord(m
, info
);
4299 mDNSlocal
void DeregisterAutoTunnelServiceRecords(mDNS
*m
, DomainAuthInfo
*info
)
4301 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info
->domain
.c
);
4302 if (info
->AutoTunnelTarget
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
4304 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelTarget
);
4307 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
4308 LogMsg("DeregisterAutoTunnelServiceRecords error %d deregistering AutoTunnelTarget %##s", err
, info
->AutoTunnelTarget
.namestorage
.c
);
4310 else LogInfo("DeregisterAutoTunnelServiceRecords: Deregistered AutoTunnel Target Record");
4313 else LogInfo("DeregisterAutoTunnelServiceRecords: Not deregistering Target record state:%d", info
->AutoTunnelService
.resrec
.RecordType
);
4315 if (info
->AutoTunnelService
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
4317 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelService
);
4320 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
4321 LogMsg("DeregisterAutoTunnelServiceRecords error %d deregistering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
4323 else LogInfo("DeregisterAutoTunnelServiceRecords: Deregistered AutoTunnel Service Record");
4326 else LogInfo("DeregisterAutoTunnelServiceRecords: Not deregistering service records state:%d", info
->AutoTunnelService
.resrec
.RecordType
);
4328 DeregisterAutoTunnelHostRecord(m
, info
);
4331 // Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
4332 // sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
4333 // not e.g., AutoTunnelHostNameChanged
4334 mDNSlocal
void RegisterAutoTunnelDevInfoRecord(mDNS
*m
, DomainAuthInfo
*info
)
4338 if (!m
->mDNS_busy
) LogMsg("RegisterAutoTunnelDevInfoRecord: Lock not held");
4340 // a. We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
4341 // called at least once with some Services/Records in the domain and hence it is safe to register
4342 // records when this function is called.
4344 // b. We use zero Requested port to infer that we should not be calling Register anymore as it might
4345 // be shutdown or the DomainAuthInfo is going away.
4347 // We can use a different set of state variables to track the above as the records registered in
4348 // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
4349 // reuse the NAT variables.
4351 // Set up device info record
4352 if (info
->AutoTunnelNAT
.clientContext
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.RequestedPort
) && info
->AutoTunnelDeviceInfo
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4354 ConstructServiceName(&info
->AutoTunnelDeviceInfo
.namestorage
, &m
->nicelabel
, &DeviceInfoName
, &info
->domain
);
4355 mDNSu8 len
= m
->HIHardware
.c
[0] < 255 - 6 ? m
->HIHardware
.c
[0] : 255 - 6;
4356 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 1, "model=", 6);
4357 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 7, m
->HIHardware
.c
+ 1, len
);
4358 info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
[0] = 6 + len
; // "model=" plus the device string
4359 info
->AutoTunnelDeviceInfo
.resrec
.rdlength
= 7 + len
; // One extra for the length byte at the start of the string
4360 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4362 err
= mDNS_Register_internal(m
, &info
->AutoTunnelDeviceInfo
);
4363 if (err
) LogMsg("RegisterAutoTunnelDevInfoRecord error %d registering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
4364 else LogInfo("RegisterAutoTunnelDevInfoRecord registering AutoTunnelDeviceInfo %##s", info
->AutoTunnelDeviceInfo
.namestorage
.c
);
4368 #ifndef NO_SECURITYFRAMEWORK
4369 mDNSlocal
void DeregisterAutoTunnelDevInfoRecord(mDNS
*m
, DomainAuthInfo
*info
)
4371 LogInfo("DeregisterAutoTunnelDevInfoRecord %##s", info
->domain
.c
);
4373 if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
4375 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelDeviceInfo
);
4378 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
4379 LogMsg("DeregisterAutoTunnelDevInfoRecord error %d deregistering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
4381 else LogInfo("DeregisterAutoTunnelDevInfoRecord: Deregistered AutoTunnel Device Info");
4383 else LogInfo("DeregisterAutoTunnelDevInfoRecord: Not deregistering DeviceInfo Record state:%d", info
->AutoTunnelDeviceInfo
.resrec
.RecordType
);
4388 // Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
4389 // sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
4390 // not e.g., AutoTunnelHostNameChanged
4391 mDNSlocal
void RegisterAutoTunnel6Record(mDNS
*m
, DomainAuthInfo
*info
)
4395 if (!m
->mDNS_busy
) LogMsg("RegisterAutoTunnel6Record: ERROR!! Lock not held");
4397 // We deregister the AutoTunnel6Record during sleep and come back here (AutoTunnelRecordCallback) to
4398 // register the address if needed. During that time, we might get a network change event which finds
4399 // that the utun interface exists and tries to register the AutoTunnel6Record which should be stopped.
4400 // Also the RelayAddress is reinitialized during that process which in turn causes the AutoTunnelRecordCallback
4401 // to re-register again. To stop these, we check for the SleepState and register only if we are awake.
4402 if (m
->SleepState
!= SleepState_Awake
)
4404 LogInfo("RegisterAutoTunnel6Record: Not in awake state, SleepState %d", m
->SleepState
);
4408 // if disabled administratively, don't register
4409 // if disabled administratively, don't register
4410 if (!m
->RegisterAutoTunnel6
|| DisableInboundRelayConnection
)
4412 LogInfo("RegisterAutoTunnel6Record: registration Disabled RegisterAutoTunnel6 %d, DisableInbound %d",
4413 m
->RegisterAutoTunnel6
, DisableInboundRelayConnection
);
4417 // If we have a valid Relay address, we need to register it now. When we got a valid address, we may not
4418 // have registered it because it was waiting for at least one service to become active in the BTMM domain.
4419 // During network change event, we might be called multiple times while the "Connectivity" key did not
4420 // change, so check to see if the value has changed. This can also be zero when we are deregistering and
4421 // getting called from the AutoTunnelRecordCallback
4423 if (mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
))
4425 LogInfo("RegisterAutoTunnel6Record: Relay address is zero, not registering");
4429 if ((info
->AutoTunnel6Record
.resrec
.RecordType
> kDNSRecordTypeDeregistering
) &&
4430 (mDNSSameIPv6Address(info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
, m
->AutoTunnelRelayAddr
)))
4432 LogInfo("RegisterAutoTunnel6Record: Relay address %.16a same, not registering", &m
->AutoTunnelRelayAddr
);
4437 // a. We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
4438 // called at least once with some Services/Records in the domain and hence it is safe to register
4439 // records when this function is called.
4441 // b. We use zero Requested port to infer that we should not be calling Register anymore as it might
4442 // be shutdown or the DomainAuthInfo is going away.
4444 // We can use a different set of state variables to track the above as the records registered in
4445 // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
4446 // reuse the NAT variables.
4448 if (info
->AutoTunnelNAT
.clientContext
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.RequestedPort
) &&
4449 info
->AutoTunnel6Record
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4451 AssignDomainName (&info
->AutoTunnel6Record
.namestorage
, (const domainname
*) "\x0C" "_autotunnel6");
4452 AppendDomainLabel(&info
->AutoTunnel6Record
.namestorage
, &m
->hostlabel
);
4453 AppendDomainName (&info
->AutoTunnel6Record
.namestorage
, &info
->domain
);
4454 info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
= m
->AutoTunnelRelayAddr
;
4455 info
->AutoTunnel6Record
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
4457 err
= mDNS_Register_internal(m
, &info
->AutoTunnel6Record
);
4458 if (err
) LogMsg("RegisterAutoTunnel6Record error %d registering AutoTunnel6 Record %##s", err
, info
->AutoTunnel6Record
.namestorage
.c
);
4459 else LogInfo("RegisterAutoTunnel6Record registering AutoTunnel6 Record %##s", info
->AutoTunnel6Record
.namestorage
.c
);
4461 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
4462 info
->AutoTunnel6Record
.namestorage
.c
, &m
->AutoTunnelRelayAddr
,
4463 info
->AutoTunnelHostRecord
.namestorage
.c
, &m
->AutoTunnelHostAddr
);
4465 } else {LogInfo("RegisterAutoTunnel6Record: client context %p, RequestedPort %d, Address %.16a, record type %d", info
->AutoTunnelNAT
.clientContext
, info
->AutoTunnelNAT
.RequestedPort
, &m
->AutoTunnelRelayAddr
, info
->AutoTunnel6Record
.resrec
.RecordType
);}
4467 RegisterAutoTunnelHostRecord(m
, info
);
4468 // When the AutoTunnel6 record comes up, we need to kick racoon and update the status.
4469 // If we had a port mapping, we would have done it in RegisterAutoTunnelServiceRecords.
4470 // If we don't have a port mapping, we need to do it here.
4471 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
4472 UpdateAutoTunnelDomainStatus(m
, info
);
4475 mDNSlocal
void DeregisterAutoTunnel6Record(mDNS
*m
, DomainAuthInfo
*info
)
4477 LogInfo("DeregisterAutoTunnel6Record %##s", info
->domain
.c
);
4479 if (info
->AutoTunnel6Record
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
4481 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnel6Record
);
4484 info
->AutoTunnel6Record
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
4485 info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
= zerov6Addr
;
4486 LogMsg("DeregisterAutoTunnel6Record error %d deregistering AutoTunnel6Record %##s", err
, info
->AutoTunnel6Record
.namestorage
.c
);
4488 else LogInfo("DeregisterAutoTunnel6Record: Deregistered AutoTunnel6 Record");
4490 else LogInfo("DeregisterAutoTunnel6Record: Not deregistering AuoTunnel6 record state:%d", info
->AutoTunnel6Record
.resrec
.RecordType
);
4492 DeregisterAutoTunnelHostRecord(m
, info
);
4493 // UpdateAutoTunnelDomainStatus is careful enough not to turn it on if we don't have
4494 // a external port mapping. Otherwise, it will be turned off.
4496 UpdateAutoTunnelDomainStatus(m
, info
);
4500 mDNSlocal
void AutoTunnelRecordCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
4502 DomainAuthInfo
*info
= (DomainAuthInfo
*)rr
->RecordContext
;
4503 if (result
== mStatus_MemFree
)
4505 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m
, rr
));
4506 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
4507 if (rr
== &info
->AutoTunnelHostRecord
)
4509 rr
->namestorage
.c
[0] = 0;
4510 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4511 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m
->NextSRVUpdate
- m
->timenow
, m
->timenow
);
4513 if (m
->ShutdownTime
) {LogInfo("AutoTunnelRecordCallback: Shutdown, returning");return;}
4514 if (rr
== &info
->AutoTunnelHostRecord
)
4516 LogInfo("AutoTunnelRecordCallback: calling RegisterAutoTunnelHostRecord");
4517 RegisterAutoTunnelHostRecord(m
,info
);
4519 else if (rr
== &info
->AutoTunnelDeviceInfo
)
4521 LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnelDevInfoRecord");
4522 RegisterAutoTunnelDevInfoRecord(m
,info
);
4524 else if (rr
== &info
->AutoTunnelService
|| rr
== &info
->AutoTunnelTarget
)
4526 LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnelServiceRecords");
4527 RegisterAutoTunnelServiceRecords(m
,info
);
4529 else if (rr
== &info
->AutoTunnel6Record
)
4531 LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnel6Record");
4532 info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
= zerov6Addr
;
4533 RegisterAutoTunnel6Record(m
,info
);
4538 #ifndef NO_SECURITYFRAMEWORK
4539 mDNSlocal
void AutoTunnelDeleteAuthInfoState(mDNS
*m
, DomainAuthInfo
*info
)
4541 LogInfo("AutoTunnelDeleteAuthInfoState: Cleaning up state releated to Domain AuthInfo %##s", info
->domain
.c
);
4543 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4544 DeregisterAutoTunnelDevInfoRecord(m
, info
);
4545 DeregisterAutoTunnelServiceRecords(m
, info
);
4546 DeregisterAutoTunnel6Record(m
, info
);
4547 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
4548 UpdateAutoTunnelDomainStatus(m
, info
);
4550 #endif // ndef NO_SECURITYFRAMEWORK
4552 mDNSlocal
void AutoTunnelNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
4554 DomainAuthInfo
*info
= (DomainAuthInfo
*)n
->clientContext
;
4555 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s",
4556 n
->Result
, &n
->ExternalAddress
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->ExternalPort
), m
->hostlabel
.c
, info
->domain
.c
);
4558 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4559 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m
->NextSRVUpdate
- m
->timenow
, m
->timenow
);
4561 DeregisterAutoTunnelServiceRecords(m
, info
);
4562 RegisterAutoTunnelServiceRecords(m
, info
);
4564 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
4566 UpdateAutoTunnelDomainStatus(m
, (DomainAuthInfo
*)n
->clientContext
);
4569 mDNSlocal
void AbortDeregistration(mDNS
*const m
, AuthRecord
*rr
)
4571 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
4573 LogInfo("Aborting deregistration of %s", ARDisplayString(m
, rr
));
4574 CompleteDeregistration(m
, rr
);
4576 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnregistered
)
4577 LogMsg("AbortDeregistration ERROR RecordType %02X for %s", ARDisplayString(m
, rr
));
4580 mDNSlocal
void AutoTunnelHostNameChanged(mDNS
*m
, DomainAuthInfo
*info
)
4582 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m
->hostlabel
.c
, info
->domain
.c
);
4584 DeregisterAutoTunnelDevInfoRecord(m
, info
);
4585 DeregisterAutoTunnelServiceRecords(m
, info
);
4586 DeregisterAutoTunnel6Record(m
, info
);
4587 RegisterAutoTunnelServiceRecords(m
, info
);
4590 RegisterAutoTunnelDevInfoRecord(m
, info
);
4591 RegisterAutoTunnel6Record(m
, info
);
4592 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4596 mDNSlocal
void SetupLocalAutoTunnel6Records(mDNS
*const m
, DomainAuthInfo
*info
)
4598 AbortDeregistration(m
, &info
->AutoTunnelDeviceInfo
);
4599 AbortDeregistration(m
, &info
->AutoTunnel6Record
);
4601 // When the BTMM is turned on/off too quickly, following things happen.
4603 // 1. Turning off BTMM triggers deregistration of the DevInfo/AutoTunnel6 etc. records
4604 // 2. While (1) is in progress, the BTMM is turned on
4606 // At step (2), mDNS_SetSecretForDomain clears info->deltime indicating that the domain is valid
4607 // while we have not processed the turning off BTMM completely. Hence, we end up calling this
4608 // function to re-register the records. AbortDeregistration above aborts the Deregistration as the
4609 // records are still in Deregistering state and in AutoTunnelRecordCallback we end up registering
4610 // again. So, we have to be careful below to not call mDNS_SetupResourceRecord again which will
4611 // reset the state to Unregistered and registering again will lead to error as it is registered
4612 // and already in the list. Hence, register below only if needed.
4614 if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
||
4615 info
->AutoTunnel6Record
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
)
4617 LogInfo("SetupLocalAutoTunnel6Records: AutoTunnel Records not in Unregistered state: Device: %d, AutoTunnel6:%d",
4618 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
, info
->AutoTunnel6Record
.resrec
.RecordType
);
4621 if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4623 mDNS_SetupResourceRecord(&info
->AutoTunnelDeviceInfo
, mDNSNULL
, mDNSInterface_Any
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
4624 RegisterAutoTunnelDevInfoRecord(m
, info
);
4626 if (info
->AutoTunnel6Record
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
4628 mDNS_SetupResourceRecord(&info
->AutoTunnel6Record
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
4629 RegisterAutoTunnel6Record(m
, info
);
4632 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
4634 UpdateAutoTunnelDomainStatus(m
, info
);
4635 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
4638 // Before SetupLocalAutoTunnelInterface_internal is called,
4639 // m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
4640 // Must be called with the lock held
4641 mDNSexport
void SetupLocalAutoTunnelInterface_internal(mDNS
*const m
, mDNSBool servicesStarting
)
4643 // 1. Configure the local IPv6 ULA BTMM address
4644 if (!m
->AutoTunnelHostAddrActive
)
4646 m
->AutoTunnelHostAddrActive
= mDNStrue
;
4647 LogInfo("SetupLocalAutoTunnelInterface_internal: Setting up AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
4648 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp
, m
->AutoTunnelHostAddr
.b
);
4651 // 2. If we have at least one server (pending) listening, publish our records
4652 // The services may not be in the list when it is first trying to resolve the target of the SRV record.
4653 // servicesStarting is an indication of that. Use that instead of looking up in the list of Services/Records.
4654 if (servicesStarting
|| TunnelServers(m
))
4656 DomainAuthInfo
*info
;
4657 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
4659 if (info
->AutoTunnel
&& !info
->deltime
&& !info
->AutoTunnelNAT
.clientContext
)
4661 // If we just resurrected a DomainAuthInfo that is still deregistering, we need to abort the
4662 // deregistration process before re-using the AuthRecord memory
4664 // Note: We don't need the same caution as in SetupLocalAutoTunnel6Records (see the comments there)
4665 // as AutoTunnelRecordCallback (called as a result of AbortDeregistration) will not end up registering
4666 // the records because clientContext is still NULL
4668 AbortDeregistration(m
, &info
->AutoTunnelTarget
);
4669 AbortDeregistration(m
, &info
->AutoTunnelService
);
4670 AbortDeregistration(m
, &info
->AutoTunnelHostRecord
);
4672 mDNS_SetupResourceRecord(&info
->AutoTunnelTarget
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, kHostNameTTL
,
4673 kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
4674 mDNS_SetupResourceRecord(&info
->AutoTunnelService
, mDNSNULL
, mDNSInterface_Any
, kDNSType_SRV
, kHostNameTTL
,
4675 kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
4676 mDNS_SetupResourceRecord(&info
->AutoTunnelHostRecord
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
,
4677 kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
4679 // Try to get a NAT port mapping for the AutoTunnelService
4680 info
->AutoTunnelNAT
.clientCallback
= AutoTunnelNATCallback
;
4681 info
->AutoTunnelNAT
.clientContext
= info
;
4682 info
->AutoTunnelNAT
.Protocol
= NATOp_MapUDP
;
4683 info
->AutoTunnelNAT
.IntPort
= IPSECPort
;
4684 info
->AutoTunnelNAT
.RequestedPort
= IPSECPort
;
4685 info
->AutoTunnelNAT
.NATLease
= 0;
4686 mStatus err
= mDNS_StartNATOperation_internal(m
, &info
->AutoTunnelNAT
);
4687 if (err
) LogMsg("SetupLocalAutoTunnelInterface_internal: error %d starting NAT mapping", err
);
4689 // Register the records that can be done without communicating with the NAT
4691 // Note: This should be done after we setup the AutoTunnelNAT information
4692 // as some of the fields in that structure are used to infer other information
4693 // e.g., is it okay to register now ?
4695 SetupLocalAutoTunnel6Records(m
, info
);
4702 mDNSlocal mStatus
AutoTunnelSetKeys(ClientTunnel
*tun
, mDNSBool AddNew
)
4704 mDNSv6Addr loc_outer6
;
4705 mDNSv6Addr rmt_outer6
;
4707 // When we are tunneling over IPv6 Relay address, the port number is zero
4708 if (mDNSIPPortIsZero(tun
->rmt_outer_port
))
4710 loc_outer6
= tun
->loc_outer6
;
4711 rmt_outer6
= tun
->rmt_outer6
;
4715 loc_outer6
= zerov6Addr
;
4716 loc_outer6
.b
[0] = tun
->loc_outer
.b
[0];
4717 loc_outer6
.b
[1] = tun
->loc_outer
.b
[1];
4718 loc_outer6
.b
[2] = tun
->loc_outer
.b
[2];
4719 loc_outer6
.b
[3] = tun
->loc_outer
.b
[3];
4721 rmt_outer6
= zerov6Addr
;
4722 rmt_outer6
.b
[0] = tun
->rmt_outer
.b
[0];
4723 rmt_outer6
.b
[1] = tun
->rmt_outer
.b
[1];
4724 rmt_outer6
.b
[2] = tun
->rmt_outer
.b
[2];
4725 rmt_outer6
.b
[3] = tun
->rmt_outer
.b
[3];
4728 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
), SkipLeadingLabels(&tun
->dstname
, 1)));
4731 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
4732 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
4734 mDNSlocal
void ReissueBlockedQuestionWithType(mDNS
*const m
, domainname
*d
, mDNSBool success
, mDNSu16 qtype
)
4736 DNSQuestion
*q
= m
->Questions
;
4739 if (q
->NoAnswer
== NoAnswer_Suspended
&& q
->qtype
== qtype
&& q
->AuthInfo
&& q
->AuthInfo
->AutoTunnel
&& SameDomainName(&q
->qname
, d
))
4741 LogInfo("Restart %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4742 mDNSQuestionCallback
*tmp
= q
->QuestionCallback
;
4743 q
->QuestionCallback
= AutoTunnelCallback
; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
4744 mDNS_StopQuery(m
, q
);
4745 mDNS_StartQuery(m
, q
);
4746 q
->QuestionCallback
= tmp
; // Restore QuestionCallback back to the real value
4747 if (!success
) q
->NoAnswer
= NoAnswer_Fail
;
4748 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
4749 // In general we have to assume that the question list might have changed in arbitrary ways.
4750 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
4751 // already in use. The safest solution is just to go back to the start of the list and start again.
4752 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
4753 // just one suspended question, so it's really a 2n algorithm.
4761 mDNSlocal
void ReissueBlockedQuestions(mDNS
*const m
, domainname
*d
, mDNSBool success
)
4763 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
4764 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
4765 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
4766 // 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.
4767 // 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.
4768 ReissueBlockedQuestionWithType(m
, d
, success
, kDNSType_AAAA
);
4769 ReissueBlockedQuestionWithType(m
, d
, mDNStrue
, kDNSType_A
);
4772 mDNSlocal
void UnlinkAndReissueBlockedQuestions(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool success
)
4774 ClientTunnel
**p
= &m
->TunnelClients
;
4775 while (*p
!= tun
&& *p
) p
= &(*p
)->next
;
4776 if (*p
) *p
= tun
->next
;
4777 ReissueBlockedQuestions(m
, &tun
->dstname
, success
);
4778 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun
);
4779 freeL("ClientTunnel", tun
);
4782 mDNSlocal mDNSBool
TunnelClientDeleteMatching(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool v6Tunnel
)
4785 mDNSBool needSetKeys
= mDNStrue
;
4790 // Is this a tunnel to the same host that we are trying to setup now?
4791 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
4794 ClientTunnel
*old
= *p
;
4797 if (!mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue; }
4798 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4799 if (old
->q
.ThisQInterval
>= 0)
4801 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4802 mDNS_StopQuery(m
, &old
->q
);
4804 else if (!mDNSSameIPv6Address((*p
)->rmt_inner
, tun
->rmt_inner
) ||
4805 !mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
4806 !mDNSSameIPv6Address(old
->loc_outer6
, tun
->loc_outer6
) ||
4807 !mDNSSameIPv6Address(old
->rmt_outer6
, tun
->rmt_outer6
))
4809 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4810 // the other parameters of the tunnel are different
4811 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4812 AutoTunnelSetKeys(old
, mDNSfalse
);
4816 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4817 // as "tun" and "old" are identical
4818 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
,
4820 needSetKeys
= mDNSfalse
;
4825 if (mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue; }
4826 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4827 if (old
->q
.ThisQInterval
>= 0)
4829 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4830 mDNS_StopQuery(m
, &old
->q
);
4832 else if (!mDNSSameIPv6Address((*p
)->rmt_inner
, tun
->rmt_inner
) ||
4833 !mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
4834 !mDNSSameIPv4Address(old
->loc_outer
, tun
->loc_outer
) ||
4835 !mDNSSameIPv4Address(old
->rmt_outer
, tun
->rmt_outer
) ||
4836 !mDNSSameIPPort(old
->rmt_outer_port
, tun
->rmt_outer_port
))
4838 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4839 // the other parameters of the tunnel are different
4840 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4841 AutoTunnelSetKeys(old
, mDNSfalse
);
4845 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4846 // as "tun" and "old" are identical
4847 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
,
4849 needSetKeys
= mDNSfalse
;
4854 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old
);
4855 freeL("ClientTunnel", old
);
4861 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
4862 // tunnel will be deleted
4863 mDNSlocal
void TunnelClientDeleteAny(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool v6Tunnel
)
4870 // If there is more than one client tunnel to the same host, delete all of them.
4871 // We do this by just checking against the EUI64 rather than the full address
4872 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
4875 ClientTunnel
*old
= *p
;
4878 if (!mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue;}
4879 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4883 if (mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue;}
4884 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4886 if (old
->q
.ThisQInterval
>= 0)
4888 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4889 mDNS_StopQuery(m
, &old
->q
);
4893 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4894 AutoTunnelSetKeys(old
, mDNSfalse
);
4897 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old
);
4898 freeL("ClientTunnel", old
);
4903 mDNSlocal
void TunnelClientFinish(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
)
4905 mDNSBool needSetKeys
= mDNStrue
;
4906 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
4907 mDNSBool v6Tunnel
= mDNSfalse
;
4909 // If the port is zero, then we have a relay address of the peer
4910 if (mDNSIPPortIsZero(tun
->rmt_outer_port
))
4911 v6Tunnel
= mDNStrue
;
4915 LogInfo("TunnelClientFinish: Relay address %.16a", &answer
->rdata
->u
.ipv6
);
4916 tun
->rmt_outer6
= answer
->rdata
->u
.ipv6
;
4917 tun
->loc_outer6
= m
->AutoTunnelRelayAddr
;
4921 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer
->rdata
->u
.ipv4
);
4922 tun
->rmt_outer
= answer
->rdata
->u
.ipv4
;
4923 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
4924 tmpDst
.ip
.v4
= tun
->rmt_outer
;
4925 mDNSAddr tmpSrc
= zeroAddr
;
4926 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
4927 if (tmpSrc
.type
== mDNSAddrType_IPv4
) tun
->loc_outer
= tmpSrc
.ip
.v4
;
4928 else tun
->loc_outer
= m
->AdvertisedV4
.ip
.v4
;
4931 question
->ThisQInterval
= -1; // So we know this tunnel setup has completed
4932 tun
->loc_inner
= m
->AutoTunnelHostAddr
;
4934 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
4935 // look for existing tunnels to see whether they have the same information for our peer.
4936 // If not, delete them and need to create a new tunnel. If they are same, just use the
4937 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
4938 TunnelClientDeleteAny(m
, tun
, !v6Tunnel
);
4939 needSetKeys
= TunnelClientDeleteMatching(m
, tun
, v6Tunnel
);
4941 if (needSetKeys
) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel
? "IPv6" : "IPv4"), tun
->dstname
.c
, &tun
->rmt_inner
);
4942 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel
? "IPv6" : "IPv4"), tun
->dstname
.c
, &tun
->rmt_inner
);
4944 if (m
->AutoTunnelHostAddr
.b
[0]) { mDNS_Lock(m
); SetupLocalAutoTunnelInterface_internal(m
, mDNSfalse
); mDNS_Unlock(m
); };
4946 mStatus result
= needSetKeys
? AutoTunnelSetKeys(tun
, mDNStrue
) : mStatus_NoError
;
4947 static char msgbuf
[32];
4948 mDNS_snprintf(msgbuf
, sizeof(msgbuf
), "Client AutoTunnel setup - %d", result
);
4949 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.config", result
? "failure" : "success", msgbuf
, "");
4950 mDNSEReporterLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.config", result
, msgbuf
);
4951 // Kick off any questions that were held pending this tunnel setup
4952 ReissueBlockedQuestions(m
, &tun
->dstname
, (result
== mStatus_NoError
) ? mDNStrue
: mDNSfalse
);
4955 mDNSexport
void AutoTunnelCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
4957 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
4959 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun
, AddRecord
, answer
->rdlength
, question
->qtype
);
4961 if (!AddRecord
) return;
4962 mDNS_StopQuery(m
, question
);
4964 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
4965 // The code below will look for _autotunnel._udp SRV record followed by A record
4966 if (tun
->tc_state
!= TC_STATE_AAAA_PEER_RELAY
&& !answer
->rdlength
)
4968 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
4969 static char msgbuf
[16];
4970 mDNS_snprintf(msgbuf
, sizeof(msgbuf
), "%s lookup", DNSTypeName(question
->qtype
));
4971 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.config", "failure", msgbuf
, "");
4972 mDNSEReporterLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.config", 1, msgbuf
);
4973 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNSfalse
);
4977 switch (tun
->tc_state
)
4979 case TC_STATE_AAAA_PEER
:
4980 if (question
->qtype
!= kDNSType_AAAA
)
4982 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question
->qtype
);
4984 if (mDNSSameIPv6Address(answer
->rdata
->u
.ipv6
, m
->AutoTunnelHostAddr
))
4986 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer
->rdata
->u
.ipv6
);
4987 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNStrue
);
4990 tun
->rmt_inner
= answer
->rdata
->u
.ipv6
;
4991 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun
->rmt_inner
);
4992 if (!mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddr
))
4994 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
4995 tun
->tc_state
= TC_STATE_AAAA_PEER_RELAY
;
4996 question
->qtype
= kDNSType_AAAA
;
4997 AssignDomainName(&question
->qname
, (const domainname
*) "\x0C" "_autotunnel6");
5001 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
5002 tun
->tc_state
= TC_STATE_SRV_PEER
;
5003 question
->qtype
= kDNSType_SRV
;
5004 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
5006 AppendDomainName(&question
->qname
, &tun
->dstname
);
5007 mDNS_StartQuery(m
, &tun
->q
);
5009 case TC_STATE_AAAA_PEER_RELAY
:
5010 if (question
->qtype
!= kDNSType_AAAA
)
5012 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question
->qtype
);
5014 // If it failed, look for the SRV record.
5015 if (!answer
->rdlength
)
5017 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
5018 tun
->tc_state
= TC_STATE_SRV_PEER
;
5019 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
5020 AppendDomainName(&question
->qname
, &tun
->dstname
);
5021 question
->qtype
= kDNSType_SRV
;
5022 mDNS_StartQuery(m
, &tun
->q
);
5025 TunnelClientFinish(m
, question
, answer
);
5027 case TC_STATE_SRV_PEER
:
5028 if (question
->qtype
!= kDNSType_SRV
)
5030 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question
->qtype
);
5032 LogInfo("AutoTunnelCallback: SRV target name %##s", answer
->rdata
->u
.srv
.target
.c
);
5033 tun
->tc_state
= TC_STATE_ADDR_PEER
;
5034 AssignDomainName(&tun
->q
.qname
, &answer
->rdata
->u
.srv
.target
);
5035 tun
->rmt_outer_port
= answer
->rdata
->u
.srv
.port
;
5036 question
->qtype
= kDNSType_A
;
5037 mDNS_StartQuery(m
, &tun
->q
);
5039 case TC_STATE_ADDR_PEER
:
5040 if (question
->qtype
!= kDNSType_A
)
5042 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question
->qtype
);
5044 TunnelClientFinish(m
, question
, answer
);
5047 LogMsg("AutoTunnelCallback: Unknown question %p", question
);
5051 // Must be called with the lock held
5052 mDNSexport
void AddNewClientTunnel(mDNS
*const m
, DNSQuestion
*const q
)
5054 ClientTunnel
*p
= mallocL("ClientTunnel", sizeof(ClientTunnel
));
5056 AssignDomainName(&p
->dstname
, &q
->qname
);
5057 p
->MarkedForDeletion
= mDNSfalse
;
5058 p
->loc_inner
= zerov6Addr
;
5059 p
->loc_outer
= zerov4Addr
;
5060 p
->loc_outer6
= zerov6Addr
;
5061 p
->rmt_inner
= zerov6Addr
;
5062 p
->rmt_outer
= zerov4Addr
;
5063 p
->rmt_outer6
= zerov6Addr
;
5064 p
->rmt_outer_port
= zeroIPPort
;
5065 p
->tc_state
= TC_STATE_AAAA_PEER
;
5066 p
->next
= m
->TunnelClients
;
5067 m
->TunnelClients
= p
; // We intentionally build list in reverse order
5069 p
->q
.InterfaceID
= mDNSInterface_Any
;
5070 p
->q
.Target
= zeroAddr
;
5071 AssignDomainName(&p
->q
.qname
, &q
->qname
);
5072 p
->q
.qtype
= kDNSType_AAAA
;
5073 p
->q
.qclass
= kDNSClass_IN
;
5074 p
->q
.LongLived
= mDNSfalse
;
5075 p
->q
.ExpectUnique
= mDNStrue
;
5076 p
->q
.ForceMCast
= mDNSfalse
;
5077 p
->q
.ReturnIntermed
= mDNStrue
;
5078 p
->q
.SuppressUnusable
= mDNSfalse
;
5079 p
->q
.QuestionCallback
= AutoTunnelCallback
;
5080 p
->q
.QuestionContext
= p
;
5082 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p
, &q
->qname
.c
, DNSTypeName(q
->qtype
), q
->LongLived
? " LongLived" : "");
5083 mDNS_StartQuery_internal(m
, &p
->q
);
5086 #endif // APPLE_OSX_mDNSResponder
5088 #if COMPILER_LIKES_PRAGMA_MARK
5090 #pragma mark - Power State & Configuration Change Management
5093 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
, mDNSs32 utc
)
5095 mDNSBool foundav4
= mDNSfalse
;
5096 mDNSBool foundav6
= mDNSfalse
;
5097 struct ifaddrs
*ifa
= myGetIfAddrs(1);
5098 struct ifaddrs
*v4Loopback
= NULL
;
5099 struct ifaddrs
*v6Loopback
= NULL
;
5100 char defaultname
[64];
5102 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
5103 if (InfoSocket
< 3 && errno
!= EAFNOSUPPORT
) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
5105 if (m
->SleepState
== SleepState_Sleeping
) ifa
= NULL
;
5109 #if LIST_ALL_INTERFACES
5110 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
5111 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
5112 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5113 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
5114 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
5115 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5116 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
5117 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
5118 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5119 if (!(ifa
->ifa_flags
& IFF_UP
))
5120 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
5121 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5122 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
5123 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
5124 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5125 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
5126 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
5127 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5128 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
5129 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
5130 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
5133 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
5135 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
5136 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(m
->PrimaryMAC
) && mDNSSameEthAddress(&m
->PrimaryMAC
, &zeroEthAddr
))
5137 mDNSPlatformMemCopy(m
->PrimaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6);
5140 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
)
5141 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
5143 if (!ifa
->ifa_netmask
)
5146 SetupAddr(&ip
, ifa
->ifa_addr
);
5147 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
5148 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
5150 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
5151 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5152 else if (ifa
->ifa_netmask
->sa_family
!= ifa
->ifa_addr
->sa_family
&& ifa
->ifa_netmask
->sa_family
!= 0)
5155 SetupAddr(&ip
, ifa
->ifa_addr
);
5156 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
5157 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
5159 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
5160 else if ((int)if_nametoindex(ifa
->ifa_name
) <= 0)
5162 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
));
5166 // Make sure ifa_netmask->sa_family is set correctly
5167 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5168 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
;
5169 int ifru_flags6
= 0;
5171 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
5172 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
5174 struct in6_ifreq ifr6
;
5175 mDNSPlatformMemZero((char *)&ifr6
, sizeof(ifr6
));
5176 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
5177 ifr6
.ifr_addr
= *sin6
;
5178 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
5179 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
5180 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
5183 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
5185 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
5187 if (ifa
->ifa_addr
->sa_family
== AF_INET
) v4Loopback
= ifa
;
5189 else if (sin6
->sin6_addr
.s6_addr
[0] != 0xFD) v6Loopback
= ifa
;
5194 NetworkInterfaceInfoOSX
*i
= AddInterfaceToList(m
, ifa
, utc
);
5195 if (i
&& MulticastInterface(i
) && i
->ifinfo
.Advertise
)
5197 if (ifa
->ifa_addr
->sa_family
== AF_INET
) foundav4
= mDNStrue
;
5198 else foundav6
= mDNStrue
;
5204 ifa
= ifa
->ifa_next
;
5207 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
5208 if (!foundav4
&& v4Loopback
) AddInterfaceToList(m
, v4Loopback
, utc
);
5209 if (!foundav6
&& v6Loopback
) AddInterfaceToList(m
, v6Loopback
, utc
);
5211 // Now the list is complete, set the McastTxRx setting for each interface.
5212 NetworkInterfaceInfoOSX
*i
;
5213 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
5216 mDNSBool txrx
= MulticastInterface(i
);
5217 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
5218 txrx
= txrx
&& ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
5220 if (i
->ifinfo
.McastTxRx
!= txrx
)
5222 i
->ifinfo
.McastTxRx
= txrx
;
5223 i
->Exists
= 2; // State change; need to deregister and reregister this interface
5228 if (InfoSocket
>= 0) close(InfoSocket
);
5231 // If we haven't set up AutoTunnelHostAddr yet, do it now
5232 if (!mDNSSameEthAddress(&m
->PrimaryMAC
, &zeroEthAddr
) && m
->AutoTunnelHostAddr
.b
[0] == 0)
5234 m
->AutoTunnelHostAddr
.b
[0x0] = 0xFD; // Required prefix for "locally assigned" ULA (See RFC 4193)
5235 m
->AutoTunnelHostAddr
.b
[0x1] = mDNSRandom(255);
5236 m
->AutoTunnelHostAddr
.b
[0x2] = mDNSRandom(255);
5237 m
->AutoTunnelHostAddr
.b
[0x3] = mDNSRandom(255);
5238 m
->AutoTunnelHostAddr
.b
[0x4] = mDNSRandom(255);
5239 m
->AutoTunnelHostAddr
.b
[0x5] = mDNSRandom(255);
5240 m
->AutoTunnelHostAddr
.b
[0x6] = mDNSRandom(255);
5241 m
->AutoTunnelHostAddr
.b
[0x7] = mDNSRandom(255);
5242 m
->AutoTunnelHostAddr
.b
[0x8] = m
->PrimaryMAC
.b
[0] ^ 0x02; // See RFC 3513, Appendix A for explanation
5243 m
->AutoTunnelHostAddr
.b
[0x9] = m
->PrimaryMAC
.b
[1];
5244 m
->AutoTunnelHostAddr
.b
[0xA] = m
->PrimaryMAC
.b
[2];
5245 m
->AutoTunnelHostAddr
.b
[0xB] = 0xFF;
5246 m
->AutoTunnelHostAddr
.b
[0xC] = 0xFE;
5247 m
->AutoTunnelHostAddr
.b
[0xD] = m
->PrimaryMAC
.b
[3];
5248 m
->AutoTunnelHostAddr
.b
[0xE] = m
->PrimaryMAC
.b
[4];
5249 m
->AutoTunnelHostAddr
.b
[0xF] = m
->PrimaryMAC
.b
[5];
5250 m
->AutoTunnelLabel
.c
[0] = mDNS_snprintf((char*)m
->AutoTunnelLabel
.c
+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
5251 m
->AutoTunnelHostAddr
.b
[0x8], m
->AutoTunnelHostAddr
.b
[0x9], m
->AutoTunnelHostAddr
.b
[0xA], m
->AutoTunnelHostAddr
.b
[0xB],
5252 m
->AutoTunnelHostAddr
.b
[0xC], m
->AutoTunnelHostAddr
.b
[0xD], m
->AutoTunnelHostAddr
.b
[0xE], m
->AutoTunnelHostAddr
.b
[0xF]);
5253 LogInfo("m->AutoTunnelLabel %#s", m
->AutoTunnelLabel
.c
);
5256 mDNS_snprintf(defaultname
, sizeof(defaultname
), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen
, HINFO_HWstring
,
5257 m
->PrimaryMAC
.b
[0], m
->PrimaryMAC
.b
[1], m
->PrimaryMAC
.b
[2], m
->PrimaryMAC
.b
[3], m
->PrimaryMAC
.b
[4], m
->PrimaryMAC
.b
[5]);
5259 // Set up the nice label
5260 domainlabel nicelabel
;
5262 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
5263 if (nicelabel
.c
[0] == 0)
5265 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname
);
5266 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
5269 // Set up the RFC 1034-compliant label
5270 domainlabel hostlabel
;
5272 GetUserSpecifiedLocalHostName(&hostlabel
);
5273 if (hostlabel
.c
[0] == 0)
5275 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname
);
5276 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
5279 mDNSBool namechange
= mDNSfalse
;
5281 // We use a case-sensitive comparison here because even though changing the capitalization
5282 // of the name alone is not significant to DNS, it's still a change from the user's point of view
5283 if (SameDomainLabelCS(m
->p
->usernicelabel
.c
, nicelabel
.c
))
5284 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
5287 if (m
->p
->usernicelabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
5288 LogMsg("User updated Computer Name from “%#s” to “%#s”", m
->p
->usernicelabel
.c
, nicelabel
.c
);
5289 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
5290 namechange
= mDNStrue
;
5293 if (SameDomainLabelCS(m
->p
->userhostlabel
.c
, hostlabel
.c
))
5294 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
5297 if (m
->p
->userhostlabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
5298 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m
->p
->userhostlabel
.c
, hostlabel
.c
);
5299 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
5301 namechange
= mDNStrue
;
5304 #if APPLE_OSX_mDNSResponder
5305 if (namechange
) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
5307 DomainAuthInfo
*info
;
5308 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
5309 if (info
->AutoTunnel
) AutoTunnelHostNameChanged(m
, info
);
5311 #endif // APPLE_OSX_mDNSResponder
5313 return(mStatus_NoError
);
5316 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
5317 // Returns -1 if all the one-bits are not contiguous
5318 mDNSlocal
int CountMaskBits(mDNSAddr
*mask
)
5320 int i
= 0, bits
= 0;
5321 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
5324 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
5325 while (b
& 0x80) { bits
++; b
<<= 1; }
5328 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
5332 // returns count of non-link local V4 addresses registered
5333 mDNSlocal
int SetupActiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
5335 NetworkInterfaceInfoOSX
*i
;
5337 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
5340 NetworkInterfaceInfo
*const n
= &i
->ifinfo
;
5341 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AAAA_OVER_V4
? AF_UNSPEC
: i
->sa_family
);
5342 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifinfo
.ifname
);
5344 if (i
->Registered
&& i
->Registered
!= primary
) // Sanity check
5346 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i
->Registered
, primary
);
5347 i
->Registered
= mDNSNULL
;
5352 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5353 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5354 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it
5357 i
->Registered
= primary
;
5359 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
5360 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
5361 // 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.
5362 i
->Occulting
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->LastSeen
> 0 && utc
- i
->LastSeen
< 60);
5364 mDNS_RegisterInterface(m
, n
, i
->Flashing
&& i
->Occulting
);
5366 if (!mDNSAddressIsLinkLocal(&n
->ip
)) count
++;
5367 LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5368 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
, primary
, &n
->ip
, CountMaskBits(&n
->mask
),
5369 i
->Flashing
? " (Flashing)" : "",
5370 i
->Occulting
? " (Occulting)" : "",
5371 n
->InterfaceActive
? " (Primary)" : "");
5374 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
);
5377 if (i
->sa_family
== AF_INET
)
5380 primary
->ifa_v4addr
.s_addr
= n
->ip
.ip
.v4
.NotAnInteger
;
5381 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
5382 imr
.imr_interface
= primary
->ifa_v4addr
;
5384 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
5385 // before trying to join the group, to clear out stale kernel state which may be lingering.
5386 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
5387 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
5388 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
5389 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
5390 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
5391 // because by the time we get the configuration change notification, the interface is already gone,
5392 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
5393 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
5394 if (SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AF_INET
) == i
)
5396 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
);
5397 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, &imr
, sizeof(imr
));
5398 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
5399 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err
, errno
, strerror(errno
));
5402 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i
->ifinfo
.ifname
, i
->scope_id
, &imr
.imr_multiaddr
, &imr
.imr_interface
);
5403 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
5404 // Joining same group twice can give "Address already in use" error -- no need to report that
5405 if (err
< 0 && (errno
!= EADDRINUSE
))
5406 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err
, errno
, strerror(errno
), &imr
.imr_multiaddr
, &imr
.imr_interface
);
5409 if (i
->sa_family
== AF_INET6
)
5411 struct ipv6_mreq i6mr
;
5412 i6mr
.ipv6mr_interface
= primary
->scope_id
;
5413 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroup_v6
.ip
.v6
;
5415 if (SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AF_INET6
) == i
)
5417 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
);
5418 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
5419 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
5420 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5423 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i
->ifinfo
.ifname
, i
->scope_id
, &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5424 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
5425 // Joining same group twice can give "Address already in use" error -- no need to report that
5426 if (err
< 0 && (errno
!= EADDRINUSE
))
5427 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
5437 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
, mDNSs32 utc
)
5439 NetworkInterfaceInfoOSX
*i
;
5440 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
5442 if (i
->Exists
) i
->LastSeen
= utc
;
5443 i
->Exists
= mDNSfalse
;
5447 // returns count of non-link local V4 addresses deregistered
5448 mDNSlocal
int ClearInactiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
5451 // If an interface is going away, then deregister this from the mDNSCore.
5452 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
5453 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
5454 // it refers to has gone away we'll crash.
5455 NetworkInterfaceInfoOSX
*i
;
5457 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
5459 // If this interface is no longer active, or its InterfaceID is changing, deregister it
5460 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AAAA_OVER_V4
? AF_UNSPEC
: i
->sa_family
);
5462 if (i
->Exists
== 0 || i
->Exists
== 2 || i
->Registered
!= primary
)
5464 i
->Flashing
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->AppearanceTime
< 60);
5465 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5466 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
, primary
,
5467 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
),
5468 i
->Flashing
? " (Flashing)" : "",
5469 i
->Occulting
? " (Occulting)" : "",
5470 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
5471 mDNS_DeregisterInterface(m
, &i
->ifinfo
, i
->Flashing
&& i
->Occulting
);
5472 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
5473 i
->Registered
= mDNSNULL
;
5474 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5475 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5476 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
5478 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
5479 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
5484 // Now that everything that's going to deregister has done so, we can clean up and free the memory
5485 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
5489 // If no longer active, delete interface from list and free memory
5492 if (i
->LastSeen
== utc
) i
->LastSeen
= utc
- 1;
5493 mDNSBool
delete = (NumCacheRecordsForInterfaceID(m
, i
->ifinfo
.InterfaceID
) == 0) && (utc
- i
->LastSeen
>= 60);
5494 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
5495 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
,
5496 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), utc
- i
->LastSeen
,
5497 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
5498 #if APPLE_OSX_mDNSResponder
5499 if (i
->BPF_fd
>= 0) CloseBPF(i
);
5500 #endif // APPLE_OSX_mDNSResponder
5504 freeL("NetworkInterfaceInfoOSX", i
);
5505 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
5513 mDNSlocal
void AppendDNameListElem(DNameListElem
***List
, mDNSu32 uid
, domainname
*name
)
5515 DNameListElem
*dnle
= (DNameListElem
*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem
));
5516 if (!dnle
) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
5519 dnle
->next
= mDNSNULL
;
5521 AssignDomainName(&dnle
->name
, name
);
5523 *List
= &dnle
->next
;
5527 mDNSlocal
int compare_dns_configs(const void *aa
, const void *bb
)
5529 dns_resolver_t
*a
= *(dns_resolver_t
**)aa
;
5530 dns_resolver_t
*b
= *(dns_resolver_t
**)bb
;
5532 return (a
->search_order
< b
->search_order
) ? -1 : (a
->search_order
== b
->search_order
) ? 0 : 1;
5535 mDNSlocal
void ConfigResolvers(mDNS
*const m
, dns_config_t
*config
, mDNSBool scope
, mDNSBool setsearch
, mDNSBool setservers
)
5539 #if DNSINFO_VERSION >= 20091104
5540 dns_resolver_t
**resolver
= scope
? config
->scoped_resolver
: config
->resolver
;
5541 int nresolvers
= scope
? config
->n_scoped_resolver
: config
->n_resolver
;
5543 (void) scope
; // unused
5544 dns_resolver_t
**resolver
= config
->resolver
;
5545 int nresolvers
= config
->n_resolver
;
5548 // Currently we don't support search lists for scoped resolvers. The WAB support for this will be added later.
5549 if (setsearch
&& !scope
&& nresolvers
)
5551 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
5552 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
5553 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
5554 // instead use the search domain list as the sole authority for what domains to search and in what order
5555 // (and the domain from the "domain" field will also appear somewhere in that list).
5556 // Also, all search domains get added to the search list for resolver[0], so the domains and/or
5557 // search lists for other resolvers in the list need to be ignored.
5559 // Note: Starting DNSINFO_VERSION 20091104, search list is present only in the first resolver (resolver 0).
5560 // i.e., n_search for the first resolver is always non-zero. We don't guard it with #ifs for better readability
5562 if (resolver
[0]->n_search
== 0)
5564 LogInfo("ConfigResolvers: (%s) configuring zeroth domain as search list %s", scope
? "Scoped" : "Non-scoped", resolver
[0]->domain
);
5565 mDNS_AddSearchDomain_CString(resolver
[0]->domain
);
5569 for (i
= 0; i
< resolver
[0]->n_search
; i
++)
5571 LogInfo("ConfigResolvers: (%s) configuring search list %s", scope
? "Scoped" : "Non-scoped", resolver
[0]->search
[i
]);
5572 mDNS_AddSearchDomain_CString(resolver
[0]->search
[i
]);
5577 if (!setservers
) return;
5579 // For the "default" resolver ("resolver #1") the "domain" value is bogus and we need to ignore it.
5580 // e.g. the default resolver's "domain" value might say "apple.com", which indicates that this resolver
5581 // is only for names that fall under "apple.com", but that's not correct. Actually the default resolver is
5582 // for all names not covered by a more specific resolver (i.e. its domain should be ".", the root domain).
5584 // Note: Starting DNSINFO_VERSION 20091104, domain value of this first resolver (resolver 0) is always NULL.
5585 // We don't guard it with #ifs for better readability
5587 if ((nresolvers
!= 0) && resolver
[0]->domain
)
5588 resolver
[0]->domain
[0] = 0; // don't stop pointing at the memory, just change the first byte
5590 qsort(resolver
, nresolvers
, sizeof(dns_resolver_t
*), compare_dns_configs
);
5592 for (i
= 0; i
< nresolvers
; i
++)
5595 dns_resolver_t
*r
= resolver
[i
];
5596 mDNSInterfaceID interface
= mDNSInterface_Any
;
5599 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scope
? "Scoped" : "", i
, r
->domain
, r
->n_nameserver
);
5601 // On Tiger, dnsinfo entries for mDNS domains have port 5353, the mDNS port. Ignore them.
5602 // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
5603 // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
5604 // We also don't need to do any more work if there are no nameserver addresses
5605 if (r
->port
== 5353 || r
->n_nameserver
== 0) continue;
5607 if (!r
->domain
|| !*r
->domain
) d
.c
[0] = 0;
5608 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
))
5609 { LogMsg("ConfigResolvers: config->resolver[%d] bad domain %s", i
, r
->domain
); continue; }
5611 // DNS server option parsing
5612 if (r
->options
!= NULL
)
5614 char *nextOption
= r
->options
;
5615 char *currentOption
= NULL
;
5616 while ((currentOption
= strsep(&nextOption
, " ")) != NULL
&& currentOption
[0] != 0)
5618 // The option may be in the form of interface=xxx where xxx is an interface name.
5619 if (strncmp(currentOption
, kInterfaceSpecificOption
, sizeof(kInterfaceSpecificOption
) - 1) == 0)
5621 NetworkInterfaceInfoOSX
*ni
;
5622 char ifname
[IF_NAMESIZE
+1];
5623 mDNSu32 ifindex
= 0;
5624 // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
5625 // This allows us to block these special queries from going out on the wire.
5626 strlcpy(ifname
, currentOption
+ sizeof(kInterfaceSpecificOption
)-1, sizeof(ifname
));
5627 ifindex
= if_nametoindex(ifname
);
5628 if (ifindex
== 0) { disabled
= 1; LogMsg("ConfigResolvers: RegisterSplitDNS interface specific - interface %s not found", ifname
); continue; }
5629 LogInfo("ConfigResolvers: interface specific entry: %s on %s (%d)", r
->domain
, ifname
, ifindex
);
5630 // Find the interface. Can't use mDNSPlatformInterfaceIDFromInterfaceIndex
5631 // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
5632 for (ni
= m
->p
->InterfaceList
; ni
; ni
= ni
->next
)
5633 if (ni
->ifinfo
.InterfaceID
&& ni
->scope_id
== ifindex
) break;
5634 if (ni
!= NULL
) interface
= ni
->ifinfo
.InterfaceID
;
5635 if (interface
== mDNSNULL
)
5638 LogMsg("ConfigResolvers: RegisterSplitDNS interface specific - index %d (%s) not found", ifindex
, ifname
);
5645 // flags and if_index are defined only from this DNSINFO_VERSION onwards. Currently these
5646 // fields are zero for non-scoped resolvers. For now, these fields have non-zero values only
5647 // for scoped_resolvers.
5648 #if DNSINFO_VERSION >= 20091104
5649 if (scope
&& (r
->flags
& DNS_RESOLVER_FLAGS_SCOPED
) && (r
->if_index
!= 0))
5651 NetworkInterfaceInfoOSX
*ni
;
5652 interface
= mDNSNULL
;
5653 for (ni
= m
->p
->InterfaceList
; ni
; ni
= ni
->next
)
5654 if (ni
->ifinfo
.InterfaceID
&& ni
->scope_id
== r
->if_index
) break;
5655 if (ni
!= NULL
) interface
= ni
->ifinfo
.InterfaceID
;
5656 if (interface
== mDNSNULL
)
5659 LogMsg("ConfigResolvers: interface specific index %d not found", r
->if_index
);
5665 for (n
= 0; n
< r
->n_nameserver
; n
++)
5666 if (r
->nameserver
[n
]->sa_family
== AF_INET
|| r
->nameserver
[n
]->sa_family
== AF_INET6
)
5669 // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
5670 if (SetupAddr(&saddr
, r
->nameserver
[n
])) LogMsg("RegisterSplitDNS: bad IP address");
5673 mDNSBool scopedDNS
= mDNSfalse
;
5675 #if DNSINFO_VERSION >= 20091104
5676 // By setting scoped, this DNSServer can only be picked if the right interfaceID
5677 // is given in the question
5678 if (scope
&& (r
->flags
& DNS_RESOLVER_FLAGS_SCOPED
) && (interface
== mDNSNULL
))
5679 LogMsg("ConfigResolvers: ERROR: scoped is set but if_index %d is invalid for DNSServer %#a:%d", r
->if_index
, &saddr
, mDNSVal16(r
->port
? mDNSOpaque16fromIntVal(r
->port
) : UnicastDNSPort
));
5681 scopedDNS
= (scope
&& (r
->flags
& DNS_RESOLVER_FLAGS_SCOPED
)) ? mDNStrue
: mDNSfalse
;
5683 s
= mDNS_AddDNSServer(m
, &d
, interface
, &saddr
, r
->port
? mDNSOpaque16fromIntVal(r
->port
) : UnicastDNSPort
, scopedDNS
);
5686 if (disabled
) s
->teststate
= DNSServer_Disabled
;
5687 LogInfo("ConfigResolvers: DNS server %#a:%d for domain %##s from slot %d,%d", &s
->addr
, mDNSVal16(s
->port
), d
.c
, i
, n
);
5694 mDNSexport
void mDNSPlatformSetDNSConfig(mDNS
*const m
, mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
, DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
)
5697 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
5700 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
5701 if (fqdn
) fqdn
->c
[0] = 0;
5702 if (RegDomains
) *RegDomains
= NULL
;
5703 if (BrowseDomains
) *BrowseDomains
= NULL
;
5705 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
5706 setservers
? " setservers" : "",
5707 setsearch
? " setsearch" : "",
5708 fqdn
? " fqdn" : "",
5709 RegDomains
? " RegDomains" : "",
5710 BrowseDomains
? " BrowseDomains" : "");
5712 // Add the inferred address-based configuration discovery domains
5713 // (should really be in core code I think, not platform-specific)
5716 struct ifaddrs
*ifa
= mDNSNULL
;
5717 struct sockaddr_in saddr
;
5718 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
5719 saddr
.sin_len
= sizeof(saddr
);
5720 saddr
.sin_family
= AF_INET
;
5722 saddr
.sin_addr
.s_addr
= *(in_addr_t
*)&m
->Router
.ip
.v4
;
5724 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
5725 if (!AddrRequiresPPPConnection((struct sockaddr
*)&saddr
)) ifa
= myGetIfAddrs(1);
5730 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
5732 !(ifa
->ifa_flags
& IFF_LOOPBACK
) &&
5733 !SetupAddr(&a
, ifa
->ifa_addr
) &&
5734 !mDNSv4AddressIsLinkLocal(&a
.ip
.v4
) )
5736 // 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
5737 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5738 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
; // Make sure ifa_netmask->sa_family is set correctly
5739 SetupAddr(&n
, ifa
->ifa_netmask
);
5740 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
5741 mDNS_snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d.in-addr.arpa.", a
.ip
.v4
.b
[3] & n
.ip
.v4
.b
[3],
5742 a
.ip
.v4
.b
[2] & n
.ip
.v4
.b
[2],
5743 a
.ip
.v4
.b
[1] & n
.ip
.v4
.b
[1],
5744 a
.ip
.v4
.b
[0] & n
.ip
.v4
.b
[0]);
5745 mDNS_AddSearchDomain_CString(buf
);
5747 ifa
= ifa
->ifa_next
;
5751 #ifndef MDNS_NO_DNSINFO
5752 if (setservers
|| setsearch
)
5754 dns_config_t
*config
= dns_configuration_copy();
5757 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
5758 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
5759 // Apparently this is expected behaviour -- "not a bug".
5760 // Accordingly, we suppress syslog messages for the first three minutes after boot.
5761 // If we are still getting failures after three minutes, then we log them.
5762 if (OSXVers
> OSXVers_10_3_Panther
&& (mDNSu32
)mDNSPlatformRawTime() > (mDNSu32
)(mDNSPlatformOneSecond
* 180))
5763 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
5767 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config
->n_resolver
);
5769 #if APPLE_OSX_mDNSResponder
5770 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
5771 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
5772 if (config
->n_resolver
&& config
->resolver
[0]->domain
&& config
->resolver
[0]->n_nameserver
&& config
->resolver
[0]->nameserver
[0])
5773 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain
, config
->resolver
[0]->domain
);
5774 else ActiveDirectoryPrimaryDomain
.c
[0] = 0;
5775 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
5776 ActiveDirectoryPrimaryDomainLabelCount
= CountLabels(&ActiveDirectoryPrimaryDomain
);
5777 if (config
->n_resolver
&& config
->resolver
[0]->n_nameserver
&& SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain
, ActiveDirectoryPrimaryDomainLabelCount
- 1), &localdomain
))
5778 SetupAddr(&ActiveDirectoryPrimaryDomainServer
, config
->resolver
[0]->nameserver
[0]);
5781 AssignDomainName(&ActiveDirectoryPrimaryDomain
, (const domainname
*)"");
5782 ActiveDirectoryPrimaryDomainLabelCount
= 0;
5783 ActiveDirectoryPrimaryDomainServer
= zeroAddr
;
5787 ConfigResolvers(m
, config
, mDNSfalse
, setsearch
, setservers
);
5788 #if DNSINFO_VERSION >= 20091104
5789 ConfigResolvers(m
, config
, mDNStrue
, setsearch
, setservers
);
5791 dns_configuration_free(config
);
5792 setservers
= mDNSfalse
; // Done these now -- no need to fetch the same data from SCDynamicStore
5793 setsearch
= mDNSfalse
;
5796 #endif // MDNS_NO_DNSINFO
5798 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL
, NULL
);
5800 LogMsg("mDNSPlatformSetDNSConfig: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5803 CFDictionaryRef ddnsdict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_DynamicDNS
);
5808 CFArrayRef fqdnArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("HostNames"));
5809 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
5811 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
5812 CFDictionaryRef fqdnDict
= CFArrayGetValueAtIndex(fqdnArray
, 0);
5813 if (fqdnDict
&& DictionaryIsEnabled(fqdnDict
))
5815 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
5818 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5819 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
5820 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
5821 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
5829 CFArrayRef regArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("RegistrationDomains"));
5830 if (regArray
&& CFArrayGetCount(regArray
) > 0)
5832 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
5833 if (regDict
&& DictionaryIsEnabled(regDict
))
5835 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
5838 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5839 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
5840 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
5843 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf
);
5844 AppendDNameListElem(&RegDomains
, 0, &d
);
5853 CFArrayRef browseArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("BrowseDomains"));
5856 for (i
= 0; i
< CFArrayGetCount(browseArray
); i
++)
5858 CFDictionaryRef browseDict
= CFArrayGetValueAtIndex(browseArray
, i
);
5859 if (browseDict
&& DictionaryIsEnabled(browseDict
))
5861 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
5864 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5865 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
5866 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf
[0] ? buf
: "(unknown)");
5869 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf
);
5870 AppendDNameListElem(&BrowseDomains
, 0, &d
);
5877 CFRelease(ddnsdict
);
5882 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BackToMyMac
);
5885 CFIndex size
= CFDictionaryGetCount(btmm
);
5886 const void *key
[size
];
5887 const void *val
[size
];
5888 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
5889 for (i
= 0; i
< size
; i
++)
5891 LogInfo("BackToMyMac %d", i
);
5892 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5893 LogMsg("Can't read BackToMyMac %d key %s", i
, buf
);
5896 mDNSu32 uid
= atoi(buf
);
5897 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5898 LogMsg("Can't read BackToMyMac %d val %s", i
, buf
);
5899 else if (MakeDomainNameFromDNSNameString(&d
, buf
) && d
.c
[0])
5901 LogInfo("BackToMyMac %d %d %##s", i
, uid
, d
.c
);
5902 AppendDNameListElem(&RegDomains
, uid
, &d
);
5910 if (setservers
|| setsearch
)
5912 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_DNS
);
5917 CFArrayRef values
= CFDictionaryGetValue(dict
, kSCPropNetDNSServerAddresses
);
5920 LogInfo("DNS Server Address values: %d", (int)CFArrayGetCount(values
));
5921 for (i
= 0; i
< CFArrayGetCount(values
); i
++)
5923 CFStringRef s
= CFArrayGetValueAtIndex(values
, i
);
5924 mDNSAddr addr
= { mDNSAddrType_IPv4
, { { { 0 } } } };
5925 if (s
&& CFStringGetCString(s
, buf
, 256, kCFStringEncodingUTF8
) &&
5926 inet_aton(buf
, (struct in_addr
*) &addr
.ip
.v4
))
5928 LogInfo("Adding DNS server from dict: %s", buf
);
5929 mDNS_AddDNSServer(m
, mDNSNULL
, mDNSInterface_Any
, &addr
, UnicastDNSPort
, mDNSfalse
);
5933 else LogInfo("No DNS Server Address values");
5937 // Add the manual and/or DHCP-dicovered search domains
5938 CFArrayRef searchDomains
= CFDictionaryGetValue(dict
, kSCPropNetDNSSearchDomains
);
5941 for (i
= 0; i
< CFArrayGetCount(searchDomains
); i
++)
5943 CFStringRef s
= CFArrayGetValueAtIndex(searchDomains
, i
);
5944 if (s
&& CFStringGetCString(s
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5945 mDNS_AddSearchDomain_CString(buf
);
5948 else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
5950 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
5951 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
5952 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
5953 // instead use the search domain list as the sole authority for what domains to search and in what order
5954 // (and the domain from the "domain" field will also appear somewhere in that list).
5955 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetDNSDomainName
);
5956 if (string
&& CFStringGetCString(string
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5957 mDNS_AddSearchDomain_CString(buf
);
5967 mDNSexport mStatus
mDNSPlatformGetPrimaryInterface(mDNS
*const m
, mDNSAddr
*v4
, mDNSAddr
*v6
, mDNSAddr
*r
)
5972 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL
, NULL
);
5974 LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5977 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_IPv4
);
5980 r
->type
= mDNSAddrType_IPv4
;
5981 r
->ip
.v4
= zerov4Addr
;
5982 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
5985 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
5986 LogMsg("Could not convert router to CString");
5989 struct sockaddr_in saddr
;
5990 saddr
.sin_len
= sizeof(saddr
);
5991 saddr
.sin_family
= AF_INET
;
5993 inet_aton(buf
, &saddr
.sin_addr
);
5995 *(in_addr_t
*)&r
->ip
.v4
= saddr
.sin_addr
.s_addr
;
5999 string
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
6002 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
6003 struct ifaddrs
*ifa
= myGetIfAddrs(1);
6005 *v4
= *v6
= zeroAddr
;
6007 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
)) { LogMsg("Could not convert router to CString"); goto exit
; }
6009 // find primary interface in list
6010 while (ifa
&& (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
) || !HavePrimaryGlobalv6
))
6012 mDNSAddr tmp6
= zeroAddr
;
6013 if (!strcmp(buf
, ifa
->ifa_name
))
6015 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
6017 if (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
)) SetupAddr(v4
, ifa
->ifa_addr
);
6019 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
6021 SetupAddr(&tmp6
, ifa
->ifa_addr
);
6022 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
6023 { HavePrimaryGlobalv6
= mDNStrue
; *v6
= tmp6
; }
6028 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
6029 if (!HavePrimaryGlobalv6
&& ifa
->ifa_addr
->sa_family
== AF_INET6
&& !v6
->ip
.v6
.b
[0])
6031 SetupAddr(&tmp6
, ifa
->ifa_addr
);
6032 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) *v6
= tmp6
;
6035 ifa
= ifa
->ifa_next
;
6038 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
6039 // V4 to communicate w/ our DNS server
6047 return mStatus_NoError
;
6050 mDNSexport
void mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
6052 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status
, dname
->c
);
6053 char uname
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
6054 ConvertDomainNameToCString(dname
, uname
);
6060 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
6064 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
6065 // That single entity is a CFDictionary with name "HostNames".
6066 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
6067 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
6068 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
6069 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
6070 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
6072 const CFStringRef StateKeys
[1] = { CFSTR("HostNames") };
6073 const CFStringRef HostKeys
[1] = { CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
) };
6074 const CFStringRef StatusKeys
[1] = { CFSTR("Status") };
6075 if (!HostKeys
[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname
);
6078 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
6079 if (!StatusVals
[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status
);
6082 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
6085 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
6088 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
6091 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig
, mDNSNULL
, StateDict
);
6092 CFRelease(StateDict
);
6094 CFRelease(StateVals
[0]);
6096 CFRelease(HostVals
[0]);
6098 CFRelease(StatusVals
[0]);
6100 CFRelease(HostKeys
[0]);
6104 #if APPLE_OSX_mDNSResponder
6107 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
6108 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
6110 mDNSlocal mDNSBool
IsBTMMDomain(domainname
*d
)
6112 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:IsBTMMDomain"), NULL
, NULL
);
6115 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6118 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BackToMyMac
);
6121 CFIndex size
= CFDictionaryGetCount(btmm
);
6122 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
6123 const void *key
[size
];
6124 const void *val
[size
];
6127 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
6128 for (i
= 0; i
< size
; i
++)
6130 LogInfo("BackToMyMac %d", i
);
6131 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
6132 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i
, buf
);
6135 mDNSu32 uid
= atoi(buf
);
6136 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
6137 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i
, buf
);
6138 else if (MakeDomainNameFromDNSNameString(&dom
, buf
) && dom
.c
[0])
6140 if (SameDomainName(&dom
, d
))
6142 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d
->c
, uid
);
6153 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d
->c
);
6157 // Appends data to the buffer
6158 mDNSlocal
int AddOneItem(char *buf
, int bufsz
, char *data
, int *currlen
)
6162 len
= strlcpy(buf
+ *currlen
, data
, bufsz
- *currlen
);
6163 if (len
>= (bufsz
- *currlen
))
6165 // if we have exceeded the space in buf, it has already been NULL terminated
6166 // and we have nothing more to do. Set currlen to the last byte so that the caller
6167 // knows to do the right thing
6168 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen
, len
);
6169 *currlen
= bufsz
- 1;
6172 else { (*currlen
) += len
; }
6174 buf
[*currlen
] = ',';
6175 if (*currlen
>= bufsz
)
6177 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen
);
6178 *currlen
= bufsz
- 1;
6182 // if we have filled up the buffer exactly, then there is no more work to do
6183 if (*currlen
== bufsz
- 1) { buf
[*currlen
] = 0; return -1; }
6188 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
6189 // BTMM domains, then bring down the connection to the relay.
6190 mDNSlocal
void UpdateBTMMRelayConnection(mDNS
*const m
)
6192 DomainAuthInfo
*BTMMDomain
= mDNSNULL
;
6193 DomainAuthInfo
*FoundInList
;
6194 static mDNSBool AWACSDConnected
= mDNSfalse
;
6195 char AllUsers
[1024]; // maximum size of mach message
6196 char AllPass
[1024]; // maximum size of mach message
6197 char username
[MAX_DOMAIN_LABEL
+ 1];
6201 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
6202 // we may not be able to send the dns queries over the relay connection which may be needed
6203 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
6204 // need to make sure that we send the disconnect before attempting the next connect as the
6205 // awacs connections are redirected based on usernames.
6207 // For now we send a disconnect immediately. When we start sending dns queries over the relay
6208 // connection, we will need to fix this.
6210 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
6211 if (!FoundInList
->deltime
&& FoundInList
->AutoTunnel
&& IsBTMMDomain(&FoundInList
->domain
))
6213 // We need the passwd from the first domain.
6214 BTMMDomain
= FoundInList
;
6215 ConvertDomainLabelToCString_unescaped((domainlabel
*)BTMMDomain
->domain
.c
, username
);
6216 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username
, BTMMDomain
->domain
.c
);
6217 if (AddOneItem(AllUsers
, sizeof(AllUsers
), username
, &currulen
) == -1) break;
6218 if (AddOneItem(AllPass
, sizeof(AllPass
), BTMMDomain
->b64keydata
, &currplen
) == -1) break;
6223 // In the normal case (where we neither exceed the buffer size nor write bytes that
6224 // fit exactly into the buffer), currulen/currplen should be a different size than
6225 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
6227 if (currulen
!= (int)(sizeof(AllUsers
) - 1)) AllUsers
[currulen
- 1] = 0;
6228 if (currplen
!= (int)(sizeof(AllPass
) - 1)) AllPass
[currplen
- 1] = 0;
6230 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers
);
6231 AWACS_Connect(AllUsers
, AllPass
, "hello.connectivity.me.com");
6232 AWACSDConnected
= mDNStrue
;
6236 // Disconnect only if we connected previously
6237 if (AWACSDConnected
)
6239 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
6241 AWACSDConnected
= mDNSfalse
;
6243 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
6247 mDNSlocal
void UpdateBTMMRelayConnection(mDNS
*const m
)
6250 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
6252 #endif // ! NO_AWACS
6253 #endif // APPLE_OSX_mDNSResponder
6255 // MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
6256 mDNSexport
void SetDomainSecrets(mDNS
*m
)
6258 #ifdef NO_SECURITYFRAMEWORK
6260 LogMsg("Note: SetDomainSecrets: no keychain support");
6262 mDNSBool haveAutoTunnels
= mDNSfalse
;
6264 LogInfo("SetDomainSecrets");
6266 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
6267 // In the case where the user simultaneously removes their DDNS host name and the key
6268 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
6269 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
6270 // address records behind that we no longer have permission to delete.
6271 DomainAuthInfo
*ptr
;
6272 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
6273 ptr
->deltime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
*10);
6275 #if APPLE_OSX_mDNSResponder
6277 // Mark all TunnelClients for deletion
6278 ClientTunnel
*client
;
6279 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
6281 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client
->dstname
.c
);
6282 client
->MarkedForDeletion
= mDNStrue
;
6285 #endif // APPLE_OSX_mDNSResponder
6287 // String Array used to write list of private domains to Dynamic Store
6288 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6289 if (!sa
) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
6291 CFDataRef data
= NULL
;
6292 const int itemsPerEntry
= 3; // domain name, key name, key value
6293 CFArrayRef secrets
= NULL
;
6294 int err
= mDNSKeychainGetSecrets(&secrets
);
6295 if (err
|| !secrets
)
6296 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err
, secrets
);
6299 CFIndex ArrayCount
= CFArrayGetCount(secrets
);
6300 // Iterate through the secrets
6301 for (i
= 0; i
< ArrayCount
; ++i
)
6304 CFArrayRef entry
= CFArrayGetValueAtIndex(secrets
, i
);
6305 if (CFArrayGetTypeID() != CFGetTypeID(entry
) || itemsPerEntry
!= CFArrayGetCount(entry
))
6306 { LogMsg("SetDomainSecrets: malformed entry"); continue; }
6307 for (j
= 0; j
< CFArrayGetCount(entry
); ++j
)
6308 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry
, j
)))
6309 { LogMsg("SetDomainSecrets: malformed entry item"); continue; }
6311 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
6313 // Get DNS domain this key is for
6314 char stringbuf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal domainname as C-string, including terminating NUL
6315 data
= CFArrayGetValueAtIndex(entry
, 0);
6316 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
6317 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data
)); continue; }
6318 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
6319 stringbuf
[CFDataGetLength(data
)] = '\0';
6322 if (!MakeDomainNameFromDNSNameString(&domain
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf
); continue; }
6325 data
= CFArrayGetValueAtIndex(entry
, 1);
6326 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
6327 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data
)); continue; }
6328 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)stringbuf
);
6329 stringbuf
[CFDataGetLength(data
)] = '\0';
6332 if (!MakeDomainNameFromDNSNameString(&keyname
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf
); continue; }
6335 data
= CFArrayGetValueAtIndex(entry
, 2);
6336 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
6337 { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data
)); continue; }
6338 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
6339 stringbuf
[CFDataGetLength(data
)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
6341 DomainAuthInfo
*FoundInList
;
6342 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
6343 if (SameDomainName(&FoundInList
->domain
, &domain
)) break;
6345 #if APPLE_OSX_mDNSResponder
6348 // If any client tunnel destination is in this domain, set deletion flag to false
6349 ClientTunnel
*client
;
6350 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
6351 if (FoundInList
== GetAuthInfoForName_internal(m
, &client
->dstname
))
6353 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client
->dstname
.c
);
6354 client
->MarkedForDeletion
= mDNSfalse
;
6358 #endif // APPLE_OSX_mDNSResponder
6360 // Uncomment the line below to view the keys as they're read out of the system keychain
6361 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
6362 //LogInfo("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, stringbuf);
6364 // If didn't find desired domain in the list, make a new entry
6366 if (FoundInList
&& FoundInList
->AutoTunnel
&& haveAutoTunnels
== mDNSfalse
) haveAutoTunnels
= mDNStrue
;
6369 ptr
= (DomainAuthInfo
*)mallocL("DomainAuthInfo", sizeof(*ptr
));
6370 if (!ptr
) { LogMsg("SetDomainSecrets: No memory"); continue; }
6373 LogInfo("SetDomainSecrets: %d of %d %##s", i
, ArrayCount
, &domain
);
6374 if (mDNS_SetSecretForDomain(m
, ptr
, &domain
, &keyname
, stringbuf
, IsTunnelModeDomain(&domain
)) == mStatus_BadParamErr
)
6376 if (!FoundInList
) mDNSPlatformMemFree(ptr
); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
6380 #if APPLE_OSX_mDNSResponder
6381 if (ptr
->AutoTunnel
) UpdateAutoTunnelDomainStatus(m
, ptr
);
6382 #endif // APPLE_OSX_mDNSResponder
6384 ConvertDomainNameToCString(&domain
, stringbuf
);
6385 CFStringRef cfs
= CFStringCreateWithCString(NULL
, stringbuf
, kCFStringEncodingUTF8
);
6386 if (cfs
) { CFArrayAppendValue(sa
, cfs
); CFRelease(cfs
); }
6390 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, mDNSNULL
, sa
);
6393 #if APPLE_OSX_mDNSResponder
6395 // clean up ClientTunnels
6396 ClientTunnel
**pp
= &m
->TunnelClients
;
6399 if ((*pp
)->MarkedForDeletion
)
6401 ClientTunnel
*cur
= *pp
;
6402 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur
, cur
->dstname
.c
);
6403 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
6404 AutoTunnelSetKeys(cur
, mDNSfalse
);
6406 freeL("ClientTunnel", cur
);
6412 DomainAuthInfo
*info
= m
->AuthInfoList
;
6415 if (info
->AutoTunnel
&& info
->deltime
)
6417 if (info
->AutoTunnelNAT
.clientContext
)
6419 // stop the NAT operation
6420 mDNS_StopNATOperation_internal(m
, &info
->AutoTunnelNAT
);
6421 if (info
->AutoTunnelNAT
.clientCallback
)
6423 // Reset port and cleanup the state
6424 info
->AutoTunnelNAT
.ExternalAddress
= m
->ExternalAddress
;
6425 info
->AutoTunnelNAT
.ExternalPort
= zeroIPPort
;
6426 info
->AutoTunnelNAT
.RequestedPort
= zeroIPPort
;
6427 info
->AutoTunnelNAT
.Lifetime
= 0;
6428 info
->AutoTunnelNAT
.Result
= mStatus_NoError
;
6429 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
6430 AutoTunnelDeleteAuthInfoState(m
, info
);
6431 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
6433 info
->AutoTunnelNAT
.clientContext
= mDNSNULL
;
6435 RemoveAutoTunnelDomainStatus(m
, info
);
6440 if (!haveAutoTunnels
&& !m
->TunnelClients
&& m
->AutoTunnelHostAddrActive
)
6442 // remove interface if no autotunnel servers and no more client tunnels
6443 LogInfo("SetDomainSecrets: Bringing tunnel interface DOWN");
6444 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
6445 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
6446 mDNSPlatformMemZero(m
->AutoTunnelHostAddr
.b
, sizeof(m
->AutoTunnelHostAddr
.b
));
6449 if (m
->AutoTunnelHostAddr
.b
[0])
6450 if (TunnelClients(m
) || TunnelServers(m
))
6451 SetupLocalAutoTunnelInterface_internal(m
, mDNSfalse
);
6453 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
6454 UpdateBTMMRelayConnection(m
);
6456 #endif // APPLE_OSX_mDNSResponder
6458 CheckSuppressUnusableQuestions(m
);
6460 #endif /* NO_SECURITYFRAMEWORK */
6463 mDNSlocal
void SetLocalDomains(void)
6465 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6466 if (!sa
) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
6468 CFArrayAppendValue(sa
, CFSTR("local"));
6469 CFArrayAppendValue(sa
, CFSTR("254.169.in-addr.arpa"));
6470 CFArrayAppendValue(sa
, CFSTR("8.e.f.ip6.arpa"));
6471 CFArrayAppendValue(sa
, CFSTR("9.e.f.ip6.arpa"));
6472 CFArrayAppendValue(sa
, CFSTR("a.e.f.ip6.arpa"));
6473 CFArrayAppendValue(sa
, CFSTR("b.e.f.ip6.arpa"));
6475 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig
, mDNSNULL
, sa
);
6479 mDNSlocal
void GetCurrentPMSetting(const CFStringRef name
, mDNSs32
*val
)
6481 #if USE_IOPMCOPYACTIVEPMPREFERENCES
6482 CFTypeRef blob
= NULL
;
6483 CFStringRef str
= NULL
;
6484 CFDictionaryRef odict
= NULL
;
6485 CFDictionaryRef idict
= NULL
;
6486 CFNumberRef number
= NULL
;
6488 blob
= IOPSCopyPowerSourcesInfo();
6489 if (!blob
) { LogMsg("GetCurrentPMSetting: IOPSCopyPowerSourcesInfo failed!"); goto end
; }
6491 odict
= IOPMCopyActivePMPreferences();
6492 if (!odict
) { LogMsg("GetCurrentPMSetting: IOPMCopyActivePMPreferences failed!"); goto end
; }
6494 str
= IOPSGetProvidingPowerSourceType(blob
);
6495 if (!str
) { LogMsg("GetCurrentPMSetting: IOPSGetProvidingPowerSourceType failed!"); goto end
; }
6497 idict
= CFDictionaryGetValue(odict
, str
);
6501 if (!CFStringGetCString(str
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
6502 LogMsg("GetCurrentPMSetting: CFDictionaryGetValue (%s) failed!", buf
);
6506 number
= CFDictionaryGetValue(idict
, name
);
6507 if (!number
|| CFGetTypeID(number
) != CFNumberGetTypeID() || !CFNumberGetValue(number
, kCFNumberSInt32Type
, val
))
6510 if (blob
) CFRelease(blob
);
6511 if (odict
) CFRelease(odict
);
6515 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetCurrentPMSetting"), NULL
, NULL
);
6516 if (!store
) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6519 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_PowerSettings
);
6520 if (!dict
) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
6523 CFNumberRef number
= CFDictionaryGetValue(dict
, name
);
6524 if (!number
|| CFGetTypeID(number
) != CFNumberGetTypeID() || !CFNumberGetValue(number
, kCFNumberSInt32Type
, val
))
6534 #if APPLE_OSX_mDNSResponder
6536 static CFMutableDictionaryRef spsStatusDict
= NULL
;
6537 static const CFStringRef kMetricRef
= CFSTR("Metric");
6539 mDNSlocal
void SPSStatusPutNumber(CFMutableDictionaryRef dict
, const mDNSu8
* const ptr
, CFStringRef key
)
6541 mDNSu8 tmp
= (ptr
[0] - '0') * 10 + ptr
[1] - '0';
6542 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt8Type
, &tmp
);
6544 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
6547 CFDictionarySetValue(dict
, key
, num
);
6552 mDNSlocal CFMutableDictionaryRef
SPSCreateDict(const mDNSu8
* const ptr
)
6554 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
6555 if (!dict
) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict
; }
6558 buffer
[mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", ptr
) - 1] = 0;
6559 CFStringRef spsname
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
6560 if (!spsname
) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict
); return NULL
; }
6561 CFDictionarySetValue(dict
, CFSTR("FullName"), spsname
);
6564 if (ptr
[0] >= 2) SPSStatusPutNumber(dict
, ptr
+ 1, CFSTR("Type"));
6565 if (ptr
[0] >= 5) SPSStatusPutNumber(dict
, ptr
+ 4, CFSTR("Portability"));
6566 if (ptr
[0] >= 8) SPSStatusPutNumber(dict
, ptr
+ 7, CFSTR("MarginalPower"));
6567 if (ptr
[0] >= 11) SPSStatusPutNumber(dict
, ptr
+10, CFSTR("TotalPower"));
6569 mDNSu32 tmp
= SPSMetric(ptr
);
6570 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tmp
);
6572 LogMsg("SPSCreateDict: Could not create CFNumber");
6575 CFDictionarySetValue(dict
, kMetricRef
, num
);
6581 memcpy(buffer
, ptr
+ 13, ptr
[0] - 12);
6582 buffer
[ptr
[0] - 12] = 0;
6583 spsname
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
6584 if (!spsname
) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict
); return NULL
; }
6587 CFDictionarySetValue(dict
, CFSTR("PrettyName"), spsname
);
6595 mDNSlocal CFComparisonResult
CompareSPSEntries(const void *val1
, const void *val2
, void *context
)
6598 return CFNumberCompare((CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val1
, kMetricRef
),
6599 (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val2
, kMetricRef
),
6603 mDNSlocal
void UpdateSPSStatus(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
6605 NetworkInterfaceInfo
* info
= (NetworkInterfaceInfo
*)question
->QuestionContext
;
6606 debugf("UpdateSPSStatus: %s %##s %s %s", info
->ifname
, question
->qname
.c
, AddRecord
? "Add" : "Rmv", answer
? RRDisplayString(m
, answer
) : "<null>");
6609 mDNS_UpdateAllowSleep(m
);
6612 if (answer
&& SPSMetric(answer
->rdata
->u
.name
.c
) > 999999) return; // Ignore instances with invalid names
6616 spsStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
6617 if (!spsStatusDict
) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
6620 CFStringRef ifname
= CFStringCreateWithCString(NULL
, info
->ifname
, kCFStringEncodingUTF8
);
6621 if (!ifname
) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
6623 CFMutableArrayRef array
= NULL
;
6625 if (!CFDictionaryGetValueIfPresent(spsStatusDict
, ifname
, (const void**) &array
))
6627 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6628 if (!array
) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname
); return; }
6629 CFDictionarySetValue(spsStatusDict
, ifname
, array
);
6630 CFRelease(array
); // let go of our reference, now that the dict has one
6633 if (!array
) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info
->ifname
); CFRelease(ifname
); return; }
6635 if (!answer
) // special call that means the question has been stopped (because the interface is going away)
6636 CFArrayRemoveAllValues(array
);
6639 CFMutableDictionaryRef dict
= SPSCreateDict(answer
->rdata
->u
.name
.c
);
6640 if (!dict
) { CFRelease(ifname
); return; }
6644 if (!CFArrayContainsValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), dict
))
6647 for (i
=0; i
<CFArrayGetCount(array
); i
++)
6648 if (CompareSPSEntries(CFArrayGetValueAtIndex(array
, i
), dict
, NULL
) != kCFCompareLessThan
)
6650 CFArrayInsertValueAtIndex(array
, i
, dict
);
6652 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info
->ifname
, answer
->rdata
->u
.name
.c
);
6656 CFIndex i
= CFArrayGetFirstIndexOfValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), dict
);
6657 if (i
!= -1) CFArrayRemoveValueAtIndex(array
, i
);
6658 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info
->ifname
, answer
->rdata
->u
.name
.c
);
6664 if (!m
->ShutdownTime
) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState
, info
->ifname
, array
);
6669 mDNSlocal mDNSs32
GetSystemSleepTimerSetting(void)
6672 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL
, NULL
);
6674 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6677 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_PowerSettings
);
6680 CFNumberRef number
= CFDictionaryGetValue(dict
, CFSTR("System Sleep Timer"));
6681 if (number
) CFNumberGetValue(number
, kCFNumberSInt32Type
, &val
);
6689 mDNSlocal
void SetSPS(mDNS
*const m
)
6691 SCPreferencesSynchronize(m
->p
->SCPrefs
);
6692 CFDictionaryRef dict
= SCPreferencesGetValue(m
->p
->SCPrefs
, CFSTR("NAT"));
6693 mDNSBool natenabled
= (dict
&& (CFGetTypeID(dict
) == CFDictionaryGetTypeID()) && DictionaryIsEnabled(dict
));
6694 mDNSu8 sps
= natenabled
? 50 : (OfferSleepProxyService
&& GetSystemSleepTimerSetting() == 0) ? OfferSleepProxyService
: 0;
6696 // For devices that are not running NAT, but are set to never sleep, we may choose to act
6697 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
6698 if (sps
> 50 && SPMetricPortability
> 35) sps
= 0;
6700 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
6702 // For devices that are unable to sleep at all to save power (e.g. the current Apple TV hardware)
6703 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
6704 // We rate such a device as metric 70 ("Incidentally Available Hardware")
6705 if (SPMetricMarginalPower
== 10 && (!sps
|| sps
> 70)) sps
= 70;
6707 mDNSCoreBeSleepProxyServer(m
, sps
, SPMetricPortability
, SPMetricMarginalPower
, SPMetricTotalPower
);
6710 mDNSlocal
void InternetSharingChanged(SCPreferencesRef prefs
, SCPreferencesNotification notificationType
, void *context
)
6712 (void)prefs
; // Parameter not used
6713 (void)notificationType
; // Parameter not used
6714 mDNS
*const m
= (mDNS
*const)context
;
6718 // Tell platform layer to open or close its BPF fds
6719 if (!m
->p
->NetworkChanged
||
6720 m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2) < 0)
6722 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2);
6723 LogInfo("InternetSharingChanged: Set NetworkChanged to %d (%d)", m
->p
->NetworkChanged
- m
->timenow
, m
->p
->NetworkChanged
);
6727 KQueueUnlock(m
, "InternetSharingChanged");
6730 mDNSlocal mStatus
WatchForInternetSharingChanges(mDNS
*const m
)
6732 SCPreferencesRef SCPrefs
= SCPreferencesCreate(NULL
, CFSTR("mDNSResponder:WatchForInternetSharingChanges"), CFSTR("com.apple.nat.plist"));
6733 if (!SCPrefs
) { LogMsg("SCPreferencesCreate failed: %s", SCErrorString(SCError())); return(mStatus_NoMemoryErr
); }
6735 SCPreferencesContext context
= { 0, m
, NULL
, NULL
, NULL
};
6736 if (!SCPreferencesSetCallback(SCPrefs
, InternetSharingChanged
, &context
))
6737 { LogMsg("SCPreferencesSetCallback failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs
); return(mStatus_NoMemoryErr
); }
6739 #ifdef __LIB_DISPATCH__
6740 if (!SCPreferencesSetDispatchQueue( SCPrefs
, dispatch_get_main_queue()))
6741 { LogMsg("SCPreferencesSetDispatchQueue failed: %s", SCErrorString(SCError())); return(mStatus_NoMemoryErr
); }
6743 if (!SCPreferencesScheduleWithRunLoop(SCPrefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
))
6744 { LogMsg("SCPreferencesScheduleWithRunLoop failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs
); return(mStatus_NoMemoryErr
); }
6747 m
->p
->SCPrefs
= SCPrefs
;
6748 return(mStatus_NoError
);
6751 // The definitions below should eventually come from some externally-supplied header file.
6752 // However, since these definitions can't really be changed without breaking binary compatibility,
6753 // they should never change, so in practice it should not be a big problem to have them defined here.
6755 #define mDNS_IOREG_KEY "mDNS_KEY"
6756 #define mDNS_IOREG_VALUE "2009-07-30"
6757 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
6760 { // commands from the daemon to the driver
6761 cmd_mDNSOffloadRR
= 21, // give the mdns update buffer to the driver
6764 typedef union { void *ptr
; mDNSOpaque64 sixtyfourbits
; } FatPtr
;
6767 { // cmd_mDNSOffloadRR structure
6768 uint32_t command
; // set to OffloadRR
6769 uint32_t rrBufferSize
; // number of bytes of RR records
6770 uint32_t numUDPPorts
; // number of SRV UDP ports
6771 uint32_t numTCPPorts
; // number of SRV TCP ports
6772 uint32_t numRRRecords
; // number of RR records
6773 uint32_t compression
; // rrRecords - compression is base for compressed strings
6774 FatPtr rrRecords
; // address of array of pointers to the rr records
6775 FatPtr udpPorts
; // address of udp port list (SRV)
6776 FatPtr tcpPorts
; // address of tcp port list (SRV)
6779 #include <IOKit/IOKitLib.h>
6780 #include <dns_util.h>
6782 mDNSlocal mDNSu16
GetPortArray(mDNS
*const m
, int trans
, mDNSIPPort
*portarray
)
6784 const domainlabel
*const tp
= (trans
== mDNSTransport_UDP
) ? (const domainlabel
*)"\x4_udp" : (const domainlabel
*)"\x4_tcp";
6787 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6788 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainLabel(ThirdLabel(rr
->resrec
.name
)->c
, tp
->c
))
6790 if (portarray
) portarray
[count
] = rr
->resrec
.rdata
->u
.srv
.port
;
6794 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
6795 if (trans
== mDNSTransport_UDP
&& TunnelServers(m
))
6797 LogSPS("GetPortArray Back to My Mac at %d", count
);
6798 if (portarray
) portarray
[count
] = IPSECPort
;
6804 #define TfrRecordToNIC(RR) \
6805 (((RR)->resrec.InterfaceID && (RR)->resrec.InterfaceID != mDNSInterface_LocalOnly) || \
6806 (!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
6808 mDNSlocal mDNSu32
CountProxyRecords(mDNS
*const m
, uint32_t *const numbytes
)
6813 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6814 if (rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
6815 if (TfrRecordToNIC(rr
))
6817 *numbytes
+= DomainNameLength(rr
->resrec
.name
) + 10 + rr
->resrec
.rdestimate
;
6818 LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
6819 count
, DomainNameLength(rr
->resrec
.name
) + 10 + rr
->resrec
.rdestimate
, *numbytes
, ARDisplayString(m
,rr
));
6825 mDNSlocal
void GetProxyRecords(mDNS
*const m
, DNSMessage
*const msg
, uint32_t *const numbytes
, FatPtr
*const records
)
6827 mDNSu8
*p
= msg
->data
;
6828 const mDNSu8
*const limit
= p
+ *numbytes
;
6829 InitializeDNSMessage(&msg
->h
, zeroID
, zeroID
);
6833 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6834 if (rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
6835 if (TfrRecordToNIC(rr
))
6837 records
[count
].sixtyfourbits
= zeroOpaque64
;
6838 records
[count
].ptr
= p
;
6839 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
6840 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the 'unique' bit so PutResourceRecord will set it
6841 p
= PutResourceRecordTTLWithLimit(msg
, p
, &msg
->h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
, limit
);
6842 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear 'unique' bit back to normal state
6843 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
6844 count
, records
[count
].ptr
, p
, p
- (mDNSu8
*)records
[count
].ptr
, p
- msg
->data
, ARDisplayString(m
,rr
));
6847 *numbytes
= p
- msg
->data
;
6850 // If compiling with old headers and libraries (pre 10.5) that don't include IOConnectCallStructMethod
6851 // then we declare a dummy version here so that the code at least compiles
6852 #ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
6853 static kern_return_t
6854 IOConnectCallStructMethod(
6855 mach_port_t connection
, // In
6856 uint32_t selector
, // In
6857 const void *inputStruct
, // In
6858 size_t inputStructCnt
, // In
6859 void *outputStruct
, // Out
6860 size_t *outputStructCnt
) // In/Out
6865 (void)inputStructCnt
;
6867 (void)outputStructCnt
;
6868 LogMsg("Compiled without IOConnectCallStructMethod");
6869 return(KERN_FAILURE
);
6873 mDNSexport mStatus
ActivateLocalProxy(mDNS
*const m
, char *ifname
) // Called with the lock held
6875 mStatus result
= mStatus_UnknownErr
;
6876 io_service_t service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOBSDNameMatching(kIOMasterPortDefault
, 0, ifname
));
6877 if (!service
) { LogMsg("ActivateLocalProxy: No service for interface %s", ifname
); return(mStatus_UnknownErr
); }
6880 IOObjectGetClass(service
, n1
);
6882 kern_return_t kr
= IORegistryEntryGetParentEntry(service
, kIOServicePlane
, &parent
);
6883 if (kr
!= KERN_SUCCESS
) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", ifname
, n1
, kr
);
6886 IOObjectGetClass(parent
, n2
);
6887 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", ifname
, n1
, n2
);
6888 const CFTypeRef ref
= IORegistryEntryCreateCFProperty(parent
, CFSTR(mDNS_IOREG_KEY
), kCFAllocatorDefault
, mDNSNULL
);
6889 if (!ref
) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", ifname
, n1
, n2
);
6892 if (CFGetTypeID(ref
) != CFStringGetTypeID() || !CFEqual(ref
, CFSTR(mDNS_IOREG_VALUE
)))
6893 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
6894 ifname
, n1
, n2
, CFStringGetCStringPtr(ref
, mDNSNULL
), mDNS_IOREG_VALUE
);
6897 io_connect_t conObj
;
6898 kr
= IOServiceOpen(parent
, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE
, &conObj
);
6899 if (kr
!= KERN_SUCCESS
) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", ifname
, n1
, n2
, kr
);
6903 mDNSPlatformMemZero(&cmd
, sizeof(cmd
)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
6904 cmd
.command
= cmd_mDNSOffloadRR
;
6905 cmd
.numUDPPorts
= GetPortArray(m
, mDNSTransport_UDP
, mDNSNULL
);
6906 cmd
.numTCPPorts
= GetPortArray(m
, mDNSTransport_TCP
, mDNSNULL
);
6907 cmd
.numRRRecords
= CountProxyRecords(m
, &cmd
.rrBufferSize
);
6908 cmd
.compression
= sizeof(DNSMessageHeader
);
6910 DNSMessage
*msg
= (DNSMessage
*)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader
) + cmd
.rrBufferSize
);
6911 cmd
.rrRecords
.ptr
= mallocL("mDNSOffloadCmd rrRecords", cmd
.numRRRecords
* sizeof(FatPtr
));
6912 cmd
.udpPorts
.ptr
= mallocL("mDNSOffloadCmd udpPorts", cmd
.numUDPPorts
* sizeof(mDNSIPPort
));
6913 cmd
.tcpPorts
.ptr
= mallocL("mDNSOffloadCmd tcpPorts", cmd
.numTCPPorts
* sizeof(mDNSIPPort
));
6915 LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
6916 msg
, cmd
.rrBufferSize
,
6917 cmd
.rrRecords
.ptr
, cmd
.numRRRecords
,
6918 cmd
.udpPorts
.ptr
, cmd
.numUDPPorts
,
6919 cmd
.tcpPorts
.ptr
, cmd
.numTCPPorts
);
6921 if (!msg
|| !cmd
.rrRecords
.ptr
|| !cmd
.udpPorts
.ptr
|| !cmd
.tcpPorts
.ptr
)
6922 LogMsg("ActivateLocalProxy: Failed to allocate memory: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
6923 msg
, cmd
.rrBufferSize
,
6924 cmd
.rrRecords
.ptr
, cmd
.numRRRecords
,
6925 cmd
.udpPorts
.ptr
, cmd
.numUDPPorts
,
6926 cmd
.tcpPorts
.ptr
, cmd
.numTCPPorts
);
6929 GetProxyRecords(m
, msg
, &cmd
.rrBufferSize
, cmd
.rrRecords
.ptr
);
6930 GetPortArray(m
, mDNSTransport_UDP
, cmd
.udpPorts
.ptr
);
6931 GetPortArray(m
, mDNSTransport_TCP
, cmd
.tcpPorts
.ptr
);
6933 size_t outputDataSize
= sizeof(outputData
);
6934 kr
= IOConnectCallStructMethod(conObj
, 0, &cmd
, sizeof(cmd
), outputData
, &outputDataSize
);
6935 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", ifname
, n1
, n2
, kr
);
6936 if (kr
== KERN_SUCCESS
) result
= mStatus_NoError
;
6939 if (cmd
.tcpPorts
. ptr
) freeL("mDNSOffloadCmd udpPorts", cmd
.tcpPorts
.ptr
);
6940 if (cmd
.udpPorts
. ptr
) freeL("mDNSOffloadCmd tcpPorts", cmd
.udpPorts
.ptr
);
6941 if (cmd
.rrRecords
.ptr
) freeL("mDNSOffloadCmd rrRecords", cmd
.rrRecords
.ptr
);
6942 if (msg
) freeL("mDNSOffloadCmd msg", msg
);
6943 IOServiceClose(conObj
);
6948 IOObjectRelease(parent
);
6950 IOObjectRelease(service
);
6954 #endif // APPLE_OSX_mDNSResponder
6956 static io_service_t g_rootdomain
= MACH_PORT_NULL
;
6958 mDNSlocal mDNSBool
SystemWakeForNetworkAccess(void)
6961 CFBooleanRef clamshellStop
= NULL
;
6962 mDNSBool retnow
= mDNSfalse
;
6964 if (DisableSleepProxyClient
) { LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option"); return mDNSfalse
; }
6966 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val
);
6967 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", val
);
6968 if (!val
) return mDNSfalse
;
6970 if (!g_rootdomain
) g_rootdomain
= IORegistryEntryFromPath(MACH_PORT_NULL
, kIOPowerPlane
":/IOPowerConnection/IOPMrootDomain");
6971 if (!g_rootdomain
) { LogMsg("SystemWakeForNetworkAccess: IORegistryEntryFromPath failed; assuming no clamshell so can WOMP"); return mDNStrue
; }
6973 clamshellStop
= (CFBooleanRef
)IORegistryEntryCreateCFProperty(g_rootdomain
, CFSTR(kAppleClamshellStateKey
), kCFAllocatorDefault
, 0);
6974 if (!clamshellStop
) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue
; }
6975 retnow
= clamshellStop
== kCFBooleanFalse
;
6976 CFRelease(clamshellStop
);
6977 if (retnow
) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey is false; clamshell is open so can WOMP"); return mDNStrue
; }
6979 clamshellStop
= (CFBooleanRef
)IORegistryEntryCreateCFProperty(g_rootdomain
, CFSTR(kAppleClamshellCausesSleepKey
), kCFAllocatorDefault
, 0);
6980 if (!clamshellStop
) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue
; }
6981 retnow
= (clamshellStop
== kCFBooleanFalse
);
6982 CFRelease(clamshellStop
);
6983 if (retnow
) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey is false; clamshell is closed but can WOMP"); return mDNStrue
; }
6985 LogSPS("SystemWakeForNetworkAccess: clamshell is closed and can't WOMP");
6989 mDNSlocal mDNSBool
SystemSleepOnlyIfWakeOnLAN(void)
6992 GetCurrentPMSetting(CFSTR("Idle Sleep Requires Network Proxy"), &val
);
6993 return val
!= 0 ? mDNStrue
: mDNSfalse
;
6996 #if APPLE_OSX_mDNSResponder
6997 // If the _autotunnel6 record is still there in the list, we are waiting for the ack from
7000 // If we are behind a double-NAT or NAT with no NAT-PMP support, we should make sure that all our
7001 // BTMM records are deregistered so that it does not appear on the Finder sidebar of our peers
7002 // when we go to sleep. First _autotunnel6 and the host record gets deregistered, then SRV
7003 // (UpdateAllSrvRecords) and then PTR and TXT
7005 // Note: We wait up to a maximum of 10 seconds before we ack the sleep. So, returning "false"
7006 // here does not necessarily mean that it will be honored.
7007 mDNSexport mDNSBool
RecordReadyForSleep(mDNS
*const m
, AuthRecord
*rr
)
7009 if (!AuthRecord_uDNS(rr
)) return mDNStrue
;
7011 if (SameDomainLabel(rr
->namestorage
.c
, (const mDNSu8
*)"\x0c_autotunnel6"))
7013 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m
, rr
));
7016 // Just check for the SRV record alone as the PTR and TXT records are dependent on SRV
7017 // and will get deregistered together in a single update. We also don't check for TXT
7018 // records as _kerberos TXT record is always there even when there are no services
7019 // and we don't want to delay the sleep in that case.
7020 if (mDNSIPPortIsZero(m
->LLQNAT
.ExternalPort
) || m
->LLQNAT
.Result
)
7022 if ((rr
->resrec
.rrtype
== kDNSType_SRV
) && rr
->state
!= regState_NoTarget
&& rr
->zone
)
7024 DomainAuthInfo
*info
= GetAuthInfoForName_internal(m
, rr
->zone
);
7025 if (info
&& info
->AutoTunnel
)
7027 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m
, rr
));
7035 // Note: BTMMDict needs to be retained by the caller if needed
7036 mDNSlocal CFDictionaryRef
ParseBackToMyMacKey(CFDictionaryRef connd
)
7038 CFDictionaryRef BTMMDict
= CFDictionaryGetValue(connd
, CFSTR("BackToMyMac"));
7041 LogInfo("ParseBackToMyMacKey: CFDictionaryGetValue No value for BackToMyMac");
7045 // Non-dictionary is treated as non-existent dictionary
7046 if (CFGetTypeID(BTMMDict
) != CFDictionaryGetTypeID())
7047 {LogMsg("ERROR: ParseBackToMyMacKey: CFDictionaryGetValue BackToMyMac not a dictionary"); CFRelease(BTMMDict
); return NULL
;}
7052 mDNSlocal
void ParseBTMMInterfaceKey(CFDictionaryRef BTMMDict
, char *buf
, int buflen
)
7057 ifExists
= CFDictionaryGetValueIfPresent(BTMMDict
, CFSTR("Interface"), &string
);
7060 if (!CFStringGetCString(string
, buf
, buflen
, kCFStringEncodingUTF8
))
7062 LogMsg("ERROR: ParseBTMMInterfaceKey: Could not convert Interface to CString");
7063 if (buflen
) buf
[0] = 0;
7067 debugf("ParseBTMMInterfaceKey: Interface Key exists %s", buf
);
7071 if (buflen
) buf
[0] = 0;
7072 debugf("ParseBTMMInterfaceKey: Interface Key does not exist");
7076 mDNSexport
void RemoveAutoTunnel6Record(mDNS
*const m
)
7078 DomainAuthInfo
*info
;
7081 // Did we parse a non-empty dictionary before ?
7082 if (!m
->p
->ConndBTMMDict
|| (CFDictionaryGetCount(m
->p
->ConndBTMMDict
) == 0))
7084 LogInfo("RemoveAutoTunnel6Record: Never registered any records before, not deregistering %p", m
->p
->ConndBTMMDict
);
7088 // Did we have a non-NULL Interface name before ?
7089 ParseBTMMInterfaceKey(m
->p
->ConndBTMMDict
, buf
, sizeof(buf
));
7092 LogInfo("RemoveAutoTunnel6Record: Interface name already NULL, not deregistering");
7096 // Set the address to zero before calling DeregisterAutoTunnel6Record. If we call
7097 // Deregister too quickly before the previous Register completed (just scheduled
7098 // to be sent out) and when DeregisterAutoTunnel6Record calls mDNS_Register_internal,
7099 // it invokes the AutoTunnelRecordCallback immediately and AutoTunnelRelayAddr should
7100 // be zero so that we don't register again.
7101 m
->AutoTunnelRelayAddr
= zerov6Addr
;
7102 if (!m
->AuthInfoList
) LogInfo("RemoveAutoTunnel6Record: No Domain AuthInfo");
7103 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
7105 if (!info
->AutoTunnel
) { LogInfo("RemoveAutoTunnel6Record: Domain %##s not an AutoTunnel", info
->domain
.c
); continue;}
7107 if (info
->deltime
) {LogInfo("RemoveAutoTunnel6Record: Domain %##s about to be deleted", info
->domain
.c
); continue;}
7109 LogInfo("RemoveAutoTunnel6Record: Deregistering records for domain %##s", info
->domain
.c
);
7110 DeregisterAutoTunnel6Record(m
, info
);
7112 CFRelease(m
->p
->ConndBTMMDict
);
7113 m
->p
->ConndBTMMDict
= NULL
;
7116 // Returns zero on success
7117 mDNSlocal
int GetIPv6AddressForIfname(char *ifname
, mDNSv6Addr
*ipv6Addr
)
7119 struct ifaddrs
*ifa
;
7120 struct ifaddrs
*ifaddrs
;
7123 if (if_nametoindex(ifname
) == 0) {LogInfo("GetIPv6AddressForIfname: Invalid name %s", ifname
); return (-1);}
7125 if (getifaddrs(&ifaddrs
) < 0) {LogInfo("GetIPv6AddressForIfname: getifaddrs failed"); return (-1);}
7128 * Find the ifaddr entry corresponding to the interface name,
7129 * and return the first matching non-linklocal IPv6 address.
7131 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
7133 if (strncmp(ifa
->ifa_name
, ifname
, IFNAMSIZ
) != 0)
7135 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
&& ifa
->ifa_addr
->sa_family
== AF_INET6
)
7137 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
7138 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
))
7140 if (SetupAddr(&addr
, ifa
->ifa_addr
) != mStatus_NoError
)
7142 LogInfo("GetIPv6AddressForIfname: SetupAddr error, continuing to the next address");
7147 *ipv6Addr
= *(mDNSv6Addr
*)&addr
.ip
.v6
;
7148 LogInfo("GetIPv6AddressForIfname: Returning IPv6 address %.16a", ipv6Addr
);
7149 freeifaddrs(ifaddrs
);
7154 LogInfo("GetIPv6AddressForIfname: No Valid IPv6 address");
7155 freeifaddrs(ifaddrs
);
7159 mDNSlocal
void AddAutoTunnel6Record(mDNS
*const m
, char *ifname
, CFDictionaryRef BTMMDict
)
7162 DomainAuthInfo
*info
;
7164 if (GetIPv6AddressForIfname(ifname
, &v6addr
) != 0)
7166 LogInfo("AddAutoTunnel6Record: No Valid IPv6 addresses found for %s", ifname
);
7167 // If the interface does not exist but the dictionary has the value, we treat
7168 // this case as though the dictionary does not have the value
7169 RemoveAutoTunnel6Record(m
);
7170 // If awacsd crashes or exits for some reason, restart the relay connection
7171 UpdateBTMMRelayConnection(m
);
7175 m
->AutoTunnelRelayAddr
= v6addr
;
7177 if (!m
->AuthInfoList
) LogInfo("AddAutoTunnel6Record: No Domain AuthInfo");
7178 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
7180 // clientContext for a domain tells us that we are listening for at least one Service/Record
7181 // in a domain and SetLocalAutoTunnelInterface_internal was called
7182 if (!info
->AutoTunnel
) { LogInfo("AddAutoTunnel6Record: Domain %##s not an AutoTunnel", info
->domain
.c
); continue;}
7184 if (!info
->AutoTunnelNAT
.clientContext
) {LogInfo("AddAutoTunnel6Record: Domain %##s has no services", info
->domain
.c
); continue;}
7186 if (info
->deltime
) {LogInfo("AddAutoTunnel6Record: Domain %##s about to be deleted", info
->domain
.c
); continue;}
7188 LogInfo("AddAutoTunnel6Record: Registering records for domain %##s", info
->domain
.c
);
7190 RegisterAutoTunnel6Record(m
, info
);
7193 if (m
->p
->ConndBTMMDict
) CFRelease(m
->p
->ConndBTMMDict
);
7194 m
->p
->ConndBTMMDict
= CFRetain(BTMMDict
);
7197 mDNSlocal
void ParseBackToMyMac(mDNS
*const m
, CFDictionaryRef connd
)
7199 CFDictionaryRef BTMMDict
;
7202 BTMMDict
= ParseBackToMyMacKey(connd
);
7205 LogInfo("ParseBackToMyMac: CFDictionaryGetValue No value for BackToMyMac, Removing autotunnel6");
7206 RemoveAutoTunnel6Record(m
);
7210 ParseBTMMInterfaceKey(BTMMDict
, buf
, sizeof(buf
));
7213 LogInfo("ParseBackToMyMac: NULL value for Interface, Removing autotunnel6");
7214 RemoveAutoTunnel6Record(m
);
7215 // We don't have a utun interface, start the relay connection if possible
7216 UpdateBTMMRelayConnection(m
);
7220 LogInfo("ParseBackToMyMac: non-NULL value for Interface, Adding autotunnel6");
7221 AddAutoTunnel6Record(m
, buf
, BTMMDict
);
7225 mDNSexport
void SetupConndConfigChanges(mDNS
*const m
)
7227 CFDictionaryRef connd
;
7228 SCDynamicStoreRef store
;
7230 store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:SetupConndConfigChanges"), NULL
, NULL
);
7231 if (!store
) {LogMsg("SetupConndConfigChanges: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); return;}
7233 connd
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BTMMConnectivity
);
7235 {LogInfo("SetupConndConfigChanges: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError())); CFRelease(store
); return;}
7238 ParseBackToMyMac(m
, connd
);
7243 #endif /* APPLE_OSX_mDNSResponder */
7246 mDNSexport
void mDNSMacOSXNetworkChanged(mDNS
*const m
)
7248 LogInfo("*** Network Configuration Change *** (%d)%s",
7249 m
->p
->NetworkChanged
? mDNS_TimeNow(m
) - m
->p
->NetworkChanged
: 0,
7250 m
->p
->NetworkChanged
? "" : " (no scheduled configuration change)");
7251 m
->p
->NetworkChanged
= 0; // If we received a network change event and deferred processing, we're now dealing with it
7252 mDNSs32 utc
= mDNSPlatformUTC();
7253 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
7254 m
->SystemSleepOnlyIfWakeOnLAN
= SystemSleepOnlyIfWakeOnLAN();
7255 MarkAllInterfacesInactive(m
, utc
);
7256 UpdateInterfaceList(m
, utc
);
7257 ClearInactiveInterfaces(m
, utc
);
7258 SetupActiveInterfaces(m
, utc
);
7260 #if APPLE_OSX_mDNSResponder
7262 SetupConndConfigChanges(m
);
7264 if (m
->AutoTunnelHostAddr
.b
[0])
7267 if (TunnelClients(m
) || TunnelServers(m
))
7268 SetupLocalAutoTunnelInterface_internal(m
, mDNSfalse
);
7272 // Scan to find client tunnels whose questions have completed,
7273 // but whose local inner/outer addresses have changed since the tunnel was set up
7275 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
7276 if (p
->q
.ThisQInterval
< 0)
7278 if (!mDNSIPPortIsZero(p
->rmt_outer_port
))
7280 mDNSAddr tmpSrc
= zeroAddr
;
7281 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
7282 tmpDst
.ip
.v4
= p
->rmt_outer
;
7283 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
7284 if (!mDNSSameIPv6Address(p
->loc_inner
, m
->AutoTunnelHostAddr
) ||
7285 !mDNSSameIPv4Address(p
->loc_outer
, tmpSrc
.ip
.v4
))
7287 AutoTunnelSetKeys(p
, mDNSfalse
);
7288 p
->loc_inner
= m
->AutoTunnelHostAddr
;
7289 p
->loc_outer
= tmpSrc
.ip
.v4
;
7290 AutoTunnelSetKeys(p
, mDNStrue
);
7295 if (!mDNSSameIPv6Address(p
->loc_inner
, m
->AutoTunnelHostAddr
) ||
7296 !mDNSSameIPv6Address(p
->loc_outer6
, m
->AutoTunnelRelayAddr
))
7298 AutoTunnelSetKeys(p
, mDNSfalse
);
7299 p
->loc_inner
= m
->AutoTunnelHostAddr
;
7300 p
->loc_outer6
= m
->AutoTunnelRelayAddr
;
7301 AutoTunnelSetKeys(p
, mDNStrue
);
7309 NetworkInterfaceInfoOSX
*i
;
7310 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
7312 if (!m
->SPSSocket
) // Not being Sleep Proxy Server; close any open BPF fds
7314 if (i
->BPF_fd
>= 0 && CountProxyTargets(m
, i
, mDNSNULL
, mDNSNULL
) == 0) CloseBPF(i
);
7316 else // else, we're Sleep Proxy Server; open BPF fds
7318 if (i
->Exists
&& i
->Registered
== i
&& i
->ifinfo
.McastTxRx
&& !(i
->ifa_flags
& IFF_LOOPBACK
) && i
->BPF_fd
== -1)
7319 { LogSPS("%s requesting BPF", i
->ifinfo
.ifname
); i
->BPF_fd
= -2; mDNSRequestBPF(); }
7323 #endif // APPLE_OSX_mDNSResponder
7325 uDNS_SetupDNSConfig(m
);
7326 mDNS_ConfigChanged(m
);
7329 // Called with KQueueLock & mDNS lock
7330 mDNSlocal
void SetNetworkChanged(mDNS
*const m
, mDNSs32 delay
)
7332 if (!m
->p
->NetworkChanged
|| m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) < 0)
7334 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
7335 LogInfo("SetNetworkChanged: setting network changed to %d (%d)", delay
, m
->p
->NetworkChanged
);
7340 // Copy the fourth slash-delimited element from either:
7341 // State:/Network/Interface/<bsdname>/IPv4
7343 // Setup:/Network/Service/<servicename>/Interface
7344 mDNSlocal CFStringRef
CopyNameFromKey(CFStringRef key
)
7347 CFStringRef name
= NULL
;
7349 a
= CFStringCreateArrayBySeparatingStrings(NULL
, key
, CFSTR("/"));
7350 if (a
&& CFArrayGetCount(a
) == 5) name
= CFRetain(CFArrayGetValueAtIndex(a
, 3));
7351 if (a
!= NULL
) CFRelease(a
);
7356 // Whether a key from a network change notification corresponds to
7357 // an IP service that is explicitly configured for IPv4 Link Local
7358 mDNSlocal mDNSBool
ChangedKeysHaveIPv4LL(CFArrayRef inkeys
)
7360 SCDynamicStoreRef store
= NULL
;
7361 CFDictionaryRef dict
= NULL
;
7362 CFMutableArrayRef a
;
7363 const void **keys
= NULL
, **vals
= NULL
;
7364 CFStringRef pattern
= NULL
;
7366 mDNSBool found
= mDNSfalse
;
7368 jc
= CFArrayGetCount(inkeys
);
7371 store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:ChangedKeysHaveIPv4LL"), NULL
, NULL
);
7372 if (store
== NULL
) goto done
;
7374 a
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
7375 if (a
== NULL
) goto done
;
7377 // Setup:/Network/Service/[^/]+/Interface
7378 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetInterface
);
7379 if (pattern
== NULL
) goto done
;
7380 CFArrayAppendValue(a
, pattern
);
7383 // Setup:/Network/Service/[^/]+/IPv4
7384 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetIPv4
);
7385 if (pattern
== NULL
) goto done
;
7386 CFArrayAppendValue(a
, pattern
);
7389 dict
= SCDynamicStoreCopyMultiple(store
, NULL
, a
);
7394 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
7398 ic
= CFDictionaryGetCount(dict
);
7399 vals
= mDNSPlatformMemAllocate(sizeof (void *) * ic
);
7400 keys
= mDNSPlatformMemAllocate(sizeof (void *) * ic
);
7401 CFDictionaryGetKeysAndValues(dict
, keys
, vals
);
7403 for (j
= 0; j
< jc
&& !found
; j
++)
7405 CFStringRef key
= CFArrayGetValueAtIndex(inkeys
, j
);
7406 CFStringRef ifname
= NULL
;
7410 // It would be nice to use a regex here
7411 if (!CFStringHasPrefix(key
, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key
, kSCEntNetIPv4
)) continue;
7413 if ((ifname
= CopyNameFromKey(key
)) == NULL
) continue;
7414 if (mDNS_LoggingEnabled
)
7416 if (!CFStringGetCString(ifname
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7417 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf
);
7420 for (i
= 0; i
< ic
; i
++)
7422 CFDictionaryRef ipv4dict
;
7424 CFStringRef serviceid
;
7425 CFStringRef configmethod
;
7427 if (!CFStringHasSuffix(keys
[i
], kSCEntNetInterface
)) continue;
7429 if (CFDictionaryGetTypeID() != CFGetTypeID(vals
[i
])) continue;
7431 if ((name
= CFDictionaryGetValue(vals
[i
], kSCPropNetInterfaceDeviceName
)) == NULL
) continue;
7433 if (!CFEqual(ifname
, name
)) continue;
7435 if ((serviceid
= CopyNameFromKey(keys
[i
])) == NULL
) continue;
7436 if (mDNS_LoggingEnabled
)
7438 if (!CFStringGetCString(serviceid
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7439 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf
);
7442 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceid
, kSCEntNetIPv4
);
7443 CFRelease(serviceid
);
7444 if (pattern
== NULL
) continue;
7446 ipv4dict
= CFDictionaryGetValue(dict
, pattern
);
7448 if (!ipv4dict
|| CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict
)) continue;
7450 configmethod
= CFDictionaryGetValue(ipv4dict
, kSCPropNetIPv4ConfigMethod
);
7451 if (!configmethod
) continue;
7453 if (mDNS_LoggingEnabled
)
7455 if (!CFStringGetCString(configmethod
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7456 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf
);
7459 if (CFEqual(configmethod
, kSCValNetIPv4ConfigMethodLinkLocal
)) { found
= mDNStrue
; break; }
7466 if (vals
!= NULL
) mDNSPlatformMemFree(vals
);
7467 if (keys
!= NULL
) mDNSPlatformMemFree(keys
);
7468 if (dict
!= NULL
) CFRelease(dict
);
7469 if (store
!= NULL
) CFRelease(store
);
7474 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
7476 (void)store
; // Parameter not used
7477 mDNS
*const m
= (mDNS
*const)context
;
7481 mDNSs32 delay
= mDNSPlatformOneSecond
* 2; // Start off assuming a two-second delay
7483 int c
= CFArrayGetCount(changedKeys
); // Count changes
7484 CFRange range
= { 0, c
};
7485 int c1
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Hostnames
) != 0);
7486 int c2
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Computername
) != 0);
7487 int c3
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DynamicDNS
) != 0);
7488 int c4
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DNS
) != 0);
7489 if (c
&& c
- c1
- c2
- c3
- c4
== 0) delay
= mDNSPlatformOneSecond
/10; // If these were the only changes, shorten delay
7491 if (mDNS_LoggingEnabled
)
7497 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys
, i
), buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7498 LogInfo("*** NetworkChanged SC key: %s", buf
);
7500 LogInfo("*** NetworkChanged *** %d change%s %s%s%s%sdelay %d",
7502 c1
? "(Local Hostname) " : "",
7503 c2
? "(Computer Name) " : "",
7504 c3
? "(DynamicDNS) " : "",
7509 SetNetworkChanged(m
, delay
);
7511 // KeyChain frequently fails to notify clients of change events. To work around this
7512 // we set a timer and periodically poll to detect if any changes have occurred.
7513 // Without this Back To My Mac just does't work for a large number of users.
7514 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
7515 if (c3
|| CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_BackToMyMac
))
7517 LogInfo("*** NetworkChanged *** starting KeyChainBugTimer");
7518 m
->p
->KeyChainBugTimer
= NonZeroTime(m
->timenow
+ delay
);
7519 m
->p
->KeyChainBugInterval
= mDNSPlatformOneSecond
;
7524 // If DNS settings changed, immediately force a reconfig (esp. cache flush)
7525 // Similarly, if an interface changed that is explicitly IPv4 link local, immediately force a reconfig
7526 if (c4
|| ChangedKeysHaveIPv4LL(changedKeys
)) mDNSMacOSXNetworkChanged(m
);
7528 KQueueUnlock(m
, "NetworkChanged");
7531 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
7534 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
7535 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
7536 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
7537 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
7538 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
7539 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
7541 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
7542 if (!keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
7544 CFArrayAppendValue(keys
, NetworkChangedKey_IPv4
);
7545 CFArrayAppendValue(keys
, NetworkChangedKey_IPv6
);
7546 CFArrayAppendValue(keys
, NetworkChangedKey_Hostnames
);
7547 CFArrayAppendValue(keys
, NetworkChangedKey_Computername
);
7548 CFArrayAppendValue(keys
, NetworkChangedKey_DNS
);
7549 CFArrayAppendValue(keys
, NetworkChangedKey_DynamicDNS
);
7550 CFArrayAppendValue(keys
, NetworkChangedKey_BackToMyMac
);
7551 CFArrayAppendValue(keys
, NetworkChangedKey_PowerSettings
); // should remove as part of <rdar://problem/6751656>
7552 CFArrayAppendValue(keys
, NetworkChangedKey_BTMMConnectivity
);
7553 CFArrayAppendValue(patterns
, pattern1
);
7554 CFArrayAppendValue(patterns
, pattern2
);
7555 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
7556 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
7557 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
7559 #ifdef __LIB_DISPATCH__
7560 if (!SCDynamicStoreSetDispatchQueue(store
, dispatch_get_main_queue()))
7561 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
7563 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
7564 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
7565 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
7567 m
->p
->Store
= store
;
7572 if (store
) CFRelease(store
);
7575 if (patterns
) CFRelease(patterns
);
7576 if (pattern2
) CFRelease(pattern2
);
7577 if (pattern1
) CFRelease(pattern1
);
7578 if (keys
) CFRelease(keys
);
7583 #if 0 // <rdar://problem/6751656>
7584 mDNSlocal
void PMChanged(void *context
)
7586 mDNS
*const m
= (mDNS
*const)context
;
7591 LogSPS("PMChanged");
7593 SetNetworkChanged(m
, mDNSPlatformOneSecond
* 2);
7596 KQueueUnlock(m
, "PMChanged");
7599 mDNSlocal mStatus
WatchForPMChanges(mDNS
*const m
)
7601 m
->p
->PMRLS
= IOPMPrefsNotificationCreateRunLoopSource(PMChanged
, m
);
7602 if (!m
->p
->PMRLS
) { LogMsg("IOPMPrefsNotificationCreateRunLoopSource failed!"); return mStatus_UnknownErr
; }
7604 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PMRLS
, kCFRunLoopDefaultMode
);
7606 return mStatus_NoError
;
7610 #ifndef KEV_DL_WAKEFLAGS_CHANGED
7611 #define KEV_DL_WAKEFLAGS_CHANGED 17
7614 mDNSlocal
void SysEventCallBack(int s1
, short __unused filter
, void *context
)
7616 mDNS
*const m
= (mDNS
*const)context
;
7620 struct { struct kern_event_msg k
; char extra
[256]; } msg
;
7621 int bytes
= recv(s1
, &msg
, sizeof(msg
), 0);
7623 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes
, errno
, strerror(errno
));
7626 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
7627 bytes
, msg
.k
.total_size
,
7628 msg
.k
.vendor_code
, msg
.k
.vendor_code
== KEV_VENDOR_APPLE
? "KEV_VENDOR_APPLE" : "?",
7629 msg
.k
.kev_class
, msg
.k
.kev_class
== KEV_NETWORK_CLASS
? "KEV_NETWORK_CLASS" : "?",
7630 msg
.k
.kev_subclass
, msg
.k
.kev_subclass
== KEV_DL_SUBCLASS
? "KEV_DL_SUBCLASS" : "?",
7631 msg
.k
.id
, msg
.k
.event_code
,
7632 msg
.k
.event_code
== KEV_DL_SIFFLAGS
? "KEV_DL_SIFFLAGS" :
7633 msg
.k
.event_code
== KEV_DL_SIFMETRICS
? "KEV_DL_SIFMETRICS" :
7634 msg
.k
.event_code
== KEV_DL_SIFMTU
? "KEV_DL_SIFMTU" :
7635 msg
.k
.event_code
== KEV_DL_SIFPHYS
? "KEV_DL_SIFPHYS" :
7636 msg
.k
.event_code
== KEV_DL_SIFMEDIA
? "KEV_DL_SIFMEDIA" :
7637 msg
.k
.event_code
== KEV_DL_SIFGENERIC
? "KEV_DL_SIFGENERIC" :
7638 msg
.k
.event_code
== KEV_DL_ADDMULTI
? "KEV_DL_ADDMULTI" :
7639 msg
.k
.event_code
== KEV_DL_DELMULTI
? "KEV_DL_DELMULTI" :
7640 msg
.k
.event_code
== KEV_DL_IF_ATTACHED
? "KEV_DL_IF_ATTACHED" :
7641 msg
.k
.event_code
== KEV_DL_IF_DETACHING
? "KEV_DL_IF_DETACHING" :
7642 msg
.k
.event_code
== KEV_DL_IF_DETACHED
? "KEV_DL_IF_DETACHED" :
7643 msg
.k
.event_code
== KEV_DL_LINK_OFF
? "KEV_DL_LINK_OFF" :
7644 msg
.k
.event_code
== KEV_DL_LINK_ON
? "KEV_DL_LINK_ON" :
7645 msg
.k
.event_code
== KEV_DL_PROTO_ATTACHED
? "KEV_DL_PROTO_ATTACHED" :
7646 msg
.k
.event_code
== KEV_DL_PROTO_DETACHED
? "KEV_DL_PROTO_DETACHED" :
7647 msg
.k
.event_code
== KEV_DL_LINK_ADDRESS_CHANGED
? "KEV_DL_LINK_ADDRESS_CHANGED" :
7648 msg
.k
.event_code
== KEV_DL_WAKEFLAGS_CHANGED
? "KEV_DL_WAKEFLAGS_CHANGED" : "?");
7650 if (msg
.k
.event_code
== KEV_DL_WAKEFLAGS_CHANGED
) SetNetworkChanged(m
, mDNSPlatformOneSecond
* 2);
7656 mDNSlocal mStatus
WatchForSysEvents(mDNS
*const m
)
7658 m
->p
->SysEventNotifier
= socket(PF_SYSTEM
, SOCK_RAW
, SYSPROTO_EVENT
);
7659 if (m
->p
->SysEventNotifier
< 0)
7660 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m
->p
->SysEventNotifier
, errno
, strerror(errno
)); return(mStatus_NoMemoryErr
); }
7662 struct kev_request kev_req
= { KEV_VENDOR_APPLE
, KEV_NETWORK_CLASS
, KEV_DL_SUBCLASS
};
7663 int err
= ioctl(m
->p
->SysEventNotifier
, SIOCSKEVFILT
, &kev_req
);
7666 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err
, errno
, strerror(errno
));
7667 close(m
->p
->SysEventNotifier
);
7668 m
->p
->SysEventNotifier
= -1;
7669 return(mStatus_UnknownErr
);
7672 m
->p
->SysEventKQueue
.KQcallback
= SysEventCallBack
;
7673 m
->p
->SysEventKQueue
.KQcontext
= m
;
7674 m
->p
->SysEventKQueue
.KQtask
= "System Event Notifier";
7675 KQueueSet(m
->p
->SysEventNotifier
, EV_ADD
, EVFILT_READ
, &m
->p
->SysEventKQueue
);
7677 return(mStatus_NoError
);
7680 #ifndef NO_SECURITYFRAMEWORK
7681 mDNSlocal OSStatus
KeychainChanged(SecKeychainEvent keychainEvent
, SecKeychainCallbackInfo
*info
, void *context
)
7683 LogInfo("*** Keychain Changed ***");
7684 mDNS
*const m
= (mDNS
*const)context
;
7686 OSStatus err
= SecKeychainCopyDefault(&skc
);
7689 if (info
->keychain
== skc
)
7691 // 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
7692 mDNSBool relevant
= (keychainEvent
== kSecDeleteEvent
);
7695 UInt32 tags
[3] = { kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
};
7696 SecKeychainAttributeInfo attrInfo
= { 3, tags
, NULL
}; // Count, array of tags, array of formats
7697 SecKeychainAttributeList
*a
= NULL
;
7698 err
= SecKeychainItemCopyAttributesAndData(info
->item
, &attrInfo
, NULL
, &a
, NULL
, NULL
);
7701 relevant
= ((a
->attr
[0].length
== 4 && (!strncasecmp(a
->attr
[0].data
, "ddns", 4) || !strncasecmp(a
->attr
[0].data
, "sndd", 4))) ||
7702 (a
->attr
[1].length
>= 4 && (!strncasecmp(a
->attr
[1].data
, "dns:", 4))));
7703 SecKeychainItemFreeAttributesAndData(a
, NULL
);
7708 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
7710 keychainEvent
== kSecAddEvent
? "kSecAddEvent" :
7711 keychainEvent
== kSecDeleteEvent
? "kSecDeleteEvent" :
7712 keychainEvent
== kSecUpdateEvent
? "kSecUpdateEvent" : "<Unknown>");
7713 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
7716 SetDomainSecrets(m
);
7718 KQueueUnlock(m
, "KeychainChanged");
7728 mDNSlocal
void PowerOn(mDNS
*const m
)
7730 mDNSCoreMachineSleep(m
, false); // Will set m->SleepState = SleepState_Awake;
7731 if (m
->p
->WakeAtUTC
)
7733 long utc
= mDNSPlatformUTC();
7734 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
7735 if (m
->p
->WakeAtUTC
- utc
> 30) LogInfo("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m
->p
->WakeAtUTC
- utc
);
7736 else if (utc
- m
->p
->WakeAtUTC
> 30) LogInfo("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc
- m
->p
->WakeAtUTC
);
7740 //int result = mDNSPowerRequest(0, i);
7741 //if (result == kIOReturnNotReady) do i += (i<20) ? 1 : ((i+3)/4); while (mDNSPowerRequest(0, i) == kIOReturnNotReady);
7742 LogMsg("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in %d seconds", m
->p
->WakeAtUTC
- utc
, i
);
7743 m
->p
->RequestReSleep
= mDNS_TimeNow(m
) + i
* mDNSPlatformOneSecond
;
7748 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
7750 mDNS
*const m
= (mDNS
*const)refcon
;
7752 (void)service
; // Parameter not used
7753 debugf("PowerChanged %X %lX", messageType
, messageArgument
);
7755 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
7756 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
7760 case kIOMessageCanSystemPowerOff
: LogInfo("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
7761 case kIOMessageSystemWillPowerOff
: LogInfo("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
7762 mDNSCoreMachineSleep(m
, true);
7763 if (m
->SleepState
== SleepState_Sleeping
) mDNSMacOSXNetworkChanged(m
);
7765 case kIOMessageSystemWillNotPowerOff
: LogInfo("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
7766 case kIOMessageCanSystemSleep
: LogInfo("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
7767 case kIOMessageSystemWillSleep
: LogInfo("PowerChanged kIOMessageSystemWillSleep"); // E0000280
7768 mDNSCoreMachineSleep(m
, true);
7770 case kIOMessageSystemWillNotSleep
: LogInfo("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
7771 case kIOMessageSystemHasPoweredOn
: LogInfo("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
7772 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
7775 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m
->SleepState
);
7778 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
7779 // the System Configuration Framework "network changed" event that we expect
7780 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
7782 if (!m
->p
->NetworkChanged
||
7783 m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2) < 0)
7784 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2);
7788 case kIOMessageSystemWillRestart
: LogInfo("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
7789 case kIOMessageSystemWillPowerOn
: LogInfo("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
7791 #if ! TARGET_OS_EMBEDDED
7792 // On Leopard and earlier, on wake from sleep, instead of reporting link state down, Apple
7793 // Ethernet drivers report "hardware incapable of detecting link state", which the kernel
7794 // interprets as "should assume we have networking", which results in the first 4-5 seconds
7795 // of packets vanishing into a black hole. To work around this, on wake from sleep,
7796 // we block for five seconds to let Ethernet come up, and then resume normal operation.
7797 if (OSXVers
< OSXVers_10_6_SnowLeopard
)
7800 LogMsg("Running on Mac OS X version 10.%d earlier than 10.6; "
7801 "PowerChanged did sleep(5) to wait for Ethernet hardware", OSXVers
- OSXVers_Base
);
7805 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
7806 if (m
->SleepState
!= SleepState_Sleeping
)
7808 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m
->SleepState
);
7809 m
->SleepState
= SleepState_Sleeping
;
7810 mDNSMacOSXNetworkChanged(m
);
7814 default: LogInfo("PowerChanged unknown message %X", messageType
); break;
7817 if (messageType
== kIOMessageSystemWillSleep
) m
->p
->SleepCookie
= (long)messageArgument
;
7818 else IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
7820 KQueueUnlock(m
, "PowerChanged Sleep/Wake");
7823 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
7824 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
7825 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
7826 mDNSlocal
void SnowLeopardPowerChanged(void *refcon
, IOPMConnection connection
, IOPMConnectionMessageToken token
, IOPMSystemPowerStateCapabilities eventDescriptor
)
7828 mDNS
*const m
= (mDNS
*const)refcon
;
7830 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
7831 connection
, token
, eventDescriptor
,
7832 eventDescriptor
& kIOPMSystemPowerStateCapabilityCPU
? " CPU" : "",
7833 eventDescriptor
& kIOPMSystemPowerStateCapabilityVideo
? " Video" : "",
7834 eventDescriptor
& kIOPMSystemPowerStateCapabilityAudio
? " Audio" : "",
7835 eventDescriptor
& kIOPMSystemPowerStateCapabilityNetwork
? " Network" : "",
7836 eventDescriptor
& kIOPMSystemPowerStateCapabilityDisk
? " Disk" : "");
7838 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
7839 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
7841 if (eventDescriptor
& kIOPMSystemPowerStateCapabilityCPU
)
7843 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
7844 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
7845 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
7846 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
7849 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m
->SleepLimit
, m
->SleepState
);
7850 IOPMConnectionAcknowledgeEvent(connection
, m
->p
->SleepCookie
);
7853 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m
->SleepLimit
, m
->SleepState
);
7854 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
7855 if (m
->SleepState
!= SleepState_Awake
) PowerOn(m
);
7856 IOPMConnectionAcknowledgeEvent(connection
, token
);
7860 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
7861 // we should hear nothing more until we're told that the CPU has started executing again.
7862 if (m
->SleepState
) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor
, m
->SleepState
);
7864 //mDNSMacOSXNetworkChanged(m);
7865 mDNSCoreMachineSleep(m
, true);
7866 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
7867 m
->p
->SleepCookie
= token
;
7870 KQueueUnlock(m
, "SnowLeopardPowerChanged Sleep/Wake");
7874 #if COMPILER_LIKES_PRAGMA_MARK
7876 #pragma mark - Initialization & Teardown
7879 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
7880 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
7881 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
7882 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
7884 // Major version 6 is 10.2.x (Jaguar)
7885 // Major version 7 is 10.3.x (Panther)
7886 // Major version 8 is 10.4.x (Tiger)
7887 // Major version 9 is 10.5.x (Leopard)
7888 // Major version 10 is 10.6.x (SnowLeopard)
7889 mDNSexport
int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
7891 int major
= 0, minor
= 0;
7892 char letter
= 0, prodname
[256]="<Unknown>", prodvers
[256]="<Unknown>", buildver
[256]="<Unknown>";
7893 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
7896 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
7897 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
7898 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
7899 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
7900 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
7901 if (cfbuildver
&& CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
))
7902 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
7905 if (!major
) { major
=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
7906 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, STRINGIFY(mDNSResponderVersion
));
7910 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
7911 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
7912 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
7913 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
7916 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
7918 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
7921 struct sockaddr_in s5353
;
7922 s5353
.sin_family
= AF_INET
;
7923 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
7924 s5353
.sin_addr
.s_addr
= 0;
7925 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
7929 if (err
) LogMsg("No unicast UDP responses");
7930 else debugf("Unicast UDP responses okay");
7934 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
7935 // 1) query for b._dns-sd._udp.local on LocalOnly interface
7936 // (.local manually generated via explicit callback)
7937 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
7938 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
7939 // 4) result above should generate a callback from question in (1). result added to global list
7940 // 5) global list delivered to client via GetSearchDomainList()
7941 // 6) client calls to enumerate domains now go over LocalOnly interface
7942 // (!!!KRS may add outgoing interface in addition)
7944 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
7947 m
->p
->CFRunLoop
= CFRunLoopGetCurrent();
7949 char HINFO_SWstring
[256] = "";
7950 OSXVers
= mDNSMacOSXSystemBuildNumber(HINFO_SWstring
);
7952 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
7953 // 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.
7955 for (i
=0; i
<100; i
++)
7957 domainlabel testlabel
;
7959 GetUserSpecifiedLocalHostName(&testlabel
);
7960 if (testlabel
.c
[0]) break;
7964 m
->hostlabel
.c
[0] = 0;
7966 int get_model
[2] = { CTL_HW
, HW_MODEL
};
7967 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
7969 // Normal Apple model names are of the form "iPhone2,1", and
7970 // internal code names are strings containing no commas, e.g. "N88AP".
7971 // We used to ignore internal code names, but Apple now uses these internal code names
7972 // even in released shipping products, so we no longer ignore strings containing no commas.
7973 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
7974 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
7975 HINFO_HWstring
= HINFO_HWstring_buffer
;
7976 HINFO_HWstring_prefixlen
= strcspn(HINFO_HWstring
, "0123456789");
7978 if (OSXVers
< OSXVers_10_3_Panther
) m
->KnownBugs
|= mDNS_KnownBug_PhantomInterfaces
;
7979 if (OSXVers
<= OSXVers_10_6_SnowLeopard
) m
->KnownBugs
|= mDNS_KnownBug_LimitedIPv6
;
7980 if (OSXVers
>= OSXVers_10_6_SnowLeopard
) m
->KnownBugs
|= mDNS_KnownBug_LossySyslog
;
7981 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
7983 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
7984 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
7985 if (hlen
+ slen
< 254)
7987 m
->HIHardware
.c
[0] = hlen
;
7988 m
->HISoftware
.c
[0] = slen
;
7989 mDNSPlatformMemCopy(&m
->HIHardware
.c
[1], HINFO_HWstring
, hlen
);
7990 mDNSPlatformMemCopy(&m
->HISoftware
.c
[1], HINFO_SWstring
, slen
);
7993 m
->p
->permanentsockets
.port
= MulticastDNSPort
;
7994 m
->p
->permanentsockets
.m
= m
;
7995 m
->p
->permanentsockets
.sktv4
= -1;
7996 m
->p
->permanentsockets
.kqsv4
.KQcallback
= myKQSocketCallBack
;
7997 m
->p
->permanentsockets
.kqsv4
.KQcontext
= &m
->p
->permanentsockets
;
7998 m
->p
->permanentsockets
.kqsv4
.KQtask
= "UDP packet reception";
8000 m
->p
->permanentsockets
.sktv6
= -1;
8001 m
->p
->permanentsockets
.kqsv6
.KQcallback
= myKQSocketCallBack
;
8002 m
->p
->permanentsockets
.kqsv6
.KQcontext
= &m
->p
->permanentsockets
;
8003 m
->p
->permanentsockets
.kqsv6
.KQtask
= "UDP packet reception";
8006 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET
, mDNSNULL
);
8008 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET6
, mDNSNULL
);
8011 struct sockaddr_in s4
;
8012 socklen_t n4
= sizeof(s4
);
8013 if (getsockname(m
->p
->permanentsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0) LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
8014 else m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
8016 if (m
->p
->permanentsockets
.sktv6
>= 0)
8018 struct sockaddr_in6 s6
;
8019 socklen_t n6
= sizeof(s6
);
8020 if (getsockname(m
->p
->permanentsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
8021 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
8025 m
->p
->InterfaceList
= mDNSNULL
;
8026 m
->p
->userhostlabel
.c
[0] = 0;
8027 m
->p
->usernicelabel
.c
[0] = 0;
8028 m
->p
->prevoldnicelabel
.c
[0] = 0;
8029 m
->p
->prevnewnicelabel
.c
[0] = 0;
8030 m
->p
->prevoldhostlabel
.c
[0] = 0;
8031 m
->p
->prevnewhostlabel
.c
[0] = 0;
8032 m
->p
->NotifyUser
= 0;
8033 m
->p
->KeyChainBugTimer
= 0;
8034 m
->p
->WakeAtUTC
= 0;
8035 m
->p
->RequestReSleep
= 0;
8037 #if APPLE_OSX_mDNSResponder
8038 uuid_generate(m
->asl_uuid
);
8041 m
->AutoTunnelHostAddr
.b
[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
8042 m
->AutoTunnelRelayAddr
= zerov6Addr
;
8044 NetworkChangedKey_IPv4
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
8045 NetworkChangedKey_IPv6
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
8046 NetworkChangedKey_Hostnames
= SCDynamicStoreKeyCreateHostNames(NULL
);
8047 NetworkChangedKey_Computername
= SCDynamicStoreKeyCreateComputerName(NULL
);
8048 NetworkChangedKey_DNS
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
8049 if (!NetworkChangedKey_IPv4
|| !NetworkChangedKey_IPv6
|| !NetworkChangedKey_Hostnames
|| !NetworkChangedKey_Computername
|| !NetworkChangedKey_DNS
)
8050 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr
); }
8052 err
= WatchForNetworkChanges(m
);
8053 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err
); return(err
); }
8055 #if 0 // <rdar://problem/6751656>
8056 err
= WatchForPMChanges(m
);
8057 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForPMChanges failed %d", err
); return(err
); }
8060 err
= WatchForSysEvents(m
);
8061 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err
); return(err
); }
8063 mDNSs32 utc
= mDNSPlatformUTC();
8064 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
8065 UpdateInterfaceList(m
, utc
);
8066 SetupActiveInterfaces(m
, utc
);
8068 // Explicitly ensure that our Keychain operations utilize the system domain.
8069 #ifndef NO_SECURITYFRAMEWORK
8070 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
8074 SetDomainSecrets(m
);
8078 #ifndef NO_SECURITYFRAMEWORK
8079 err
= SecKeychainAddCallback(KeychainChanged
, kSecAddEventMask
|kSecDeleteEventMask
|kSecUpdateEventMask
, m
);
8080 if (err
) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err
); return(err
); }
8083 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
8084 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
8087 IOReturn iopmerr
= IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU
, &c
);
8088 if (iopmerr
) LogMsg("IOPMConnectionCreate failed %d", iopmerr
);
8091 iopmerr
= IOPMConnectionSetNotification(c
, m
, SnowLeopardPowerChanged
);
8092 if (iopmerr
) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr
);
8095 iopmerr
= IOPMConnectionScheduleWithRunLoop(c
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
);
8096 if (iopmerr
) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr
);
8099 m
->p
->IOPMConnection
= iopmerr
? mDNSNULL
: c
;
8100 if (iopmerr
) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
8101 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
8103 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &m
->p
->PowerPortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
8104 if (!m
->p
->PowerConnection
) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
8107 #ifdef __LIB_DISPATCH__
8108 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, dispatch_get_main_queue());
8110 CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
8111 #endif /* __LIB_DISPATCH__ */
8115 #if APPLE_OSX_mDNSResponder
8116 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
8117 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
8118 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
8119 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
8120 if (!strncasecmp(HINFO_HWstring
, "Xserve", 6)) { SPMetricPortability
= 25 /* 30kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
8121 else if (!strncasecmp(HINFO_HWstring
, "RackMac", 7)) { SPMetricPortability
= 25 /* 30kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
8122 else if (!strncasecmp(HINFO_HWstring
, "MacPro", 6)) { SPMetricPortability
= 27 /* 20kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
8123 else if (!strncasecmp(HINFO_HWstring
, "PowerMac", 8)) { SPMetricPortability
= 27 /* 20kg */; SPMetricMarginalPower
= 82 /* 160W */; SPMetricTotalPower
= 83 /* 200W */; }
8124 else if (!strncasecmp(HINFO_HWstring
, "iMac", 4)) { SPMetricPortability
= 30 /* 10kg */; SPMetricMarginalPower
= 77 /* 50W */; SPMetricTotalPower
= 78 /* 60W */; }
8125 else if (!strncasecmp(HINFO_HWstring
, "Macmini", 7)) { SPMetricPortability
= 33 /* 5kg */; SPMetricMarginalPower
= 73 /* 20W */; SPMetricTotalPower
= 74 /* 25W */; }
8126 else if (!strncasecmp(HINFO_HWstring
, "TimeCapsule", 11)) { SPMetricPortability
= 34 /* 4kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 70 /* 13W */; }
8127 else if (!strncasecmp(HINFO_HWstring
, "AirPort", 7)) { SPMetricPortability
= 35 /* 3kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 70 /* 12W */; }
8128 else if (!strncasecmp(HINFO_HWstring
, "AppleTV", 7)) { SPMetricPortability
= 35 /* 3kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 73 /* 20W */; }
8129 else if (!strncasecmp(HINFO_HWstring
, "MacBook", 7)) { SPMetricPortability
= 37 /* 2kg */; SPMetricMarginalPower
= 71 /* 13W */; SPMetricTotalPower
= 72 /* 15W */; }
8130 else if (!strncasecmp(HINFO_HWstring
, "PowerBook", 9)) { SPMetricPortability
= 37 /* 2kg */; SPMetricMarginalPower
= 71 /* 13W */; SPMetricTotalPower
= 72 /* 15W */; }
8131 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d",
8132 HINFO_HWstring_prefixlen
, HINFO_HWstring
, HINFO_HWstring
, SPMetricPortability
, SPMetricMarginalPower
, SPMetricTotalPower
);
8134 err
= WatchForInternetSharingChanges(m
);
8135 if (err
) { LogMsg("WatchForInternetSharingChanges failed %d", err
); return(err
); }
8137 m
->p
->ConndBTMMDict
= mDNSNULL
;
8138 #endif // APPLE_OSX_mDNSResponder
8140 #ifdef __LIB_DISPATCH__
8141 // Currently this is not defined. SSL code will eventually fix this. If it becomes
8142 // critical, we will define this to workaround the bug in SSL.
8143 #ifdef __SSL_NEEDS_SERIALIZATION__
8144 SSLqueue
= dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL
);
8146 SSLqueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
8148 if (SSLqueue
== mDNSNULL
) LogMsg("dispatch_queue_create: SSL queue NULL");
8150 return(mStatus_NoError
);
8153 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
8156 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
8159 // Adding interfaces will use this flag, so set it now.
8160 m
->DivertMulticastAdvertisements
= !m
->AdvertiseLocalAddresses
;
8162 #if APPLE_OSX_mDNSResponder
8163 m
->SPSBrowseCallback
= UpdateSPSStatus
;
8164 #endif // APPLE_OSX_mDNSResponder
8166 mStatus result
= mDNSPlatformInit_setup(m
);
8168 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
8169 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
8170 if (result
== mStatus_NoError
)
8172 mDNSCoreInitComplete(m
, mStatus_NoError
);
8175 // We only initialize if mDNSCore successfully initialized.
8176 CHECK_D2D_FUNCTION(D2DInitialize
)
8178 D2DStatus ds
= D2DInitialize(m
->p
->CFRunLoop
, xD2DServiceCallback
, m
) ;
8179 if (ds
!= kD2DSuccess
)
8180 LogMsg("D2DInitialiize failed: %d", ds
);
8182 LogMsg("D2DInitialize succeeded");
8190 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
8192 if (m
->p
->PowerConnection
)
8194 #ifdef __LIB_DISPATCH__
8195 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, NULL
);
8197 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
8199 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
8200 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
8201 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
8202 IOServiceClose ( m
->p
->PowerConnection
);
8203 IONotificationPortDestroy ( m
->p
->PowerPortRef
);
8204 m
->p
->PowerConnection
= 0;
8209 #ifdef __LIB_DISPATCH__
8210 if (!SCDynamicStoreSetDispatchQueue(m
->p
->Store
, NULL
))
8211 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
8213 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
8214 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
8215 CFRelease(m
->p
->StoreRLS
);
8216 m
->p
->StoreRLS
= NULL
;
8218 CFRelease(m
->p
->Store
);
8224 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PMRLS
, kCFRunLoopDefaultMode
);
8225 CFRunLoopSourceInvalidate(m
->p
->PMRLS
);
8226 CFRelease(m
->p
->PMRLS
);
8230 if (m
->p
->SysEventNotifier
>= 0) { close(m
->p
->SysEventNotifier
); m
->p
->SysEventNotifier
= -1; }
8233 CHECK_D2D_FUNCTION(D2DTerminate
)
8235 D2DStatus ds
= D2DTerminate();
8236 if (ds
!= kD2DSuccess
)
8237 LogMsg("D2DTerminate failed: %d", ds
);
8239 LogMsg("D2DTerminate succeeded");
8243 mDNSs32 utc
= mDNSPlatformUTC();
8244 MarkAllInterfacesInactive(m
, utc
);
8245 ClearInactiveInterfaces(m
, utc
);
8246 CloseSocketSet(&m
->p
->permanentsockets
);
8248 #if APPLE_OSX_mDNSResponder
8250 while (m
->TunnelClients
)
8252 ClientTunnel
*cur
= m
->TunnelClients
;
8253 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur
, cur
->dstname
.c
);
8254 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
8255 AutoTunnelSetKeys(cur
, mDNSfalse
);
8256 m
->TunnelClients
= cur
->next
;
8257 freeL("ClientTunnel", cur
);
8260 if (AnonymousRacoonConfig
)
8262 AnonymousRacoonConfig
= mDNSNULL
;
8263 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel");
8264 (void)mDNSConfigureServer(kmDNSDown
, mDNSNULL
);
8267 if (m
->AutoTunnelHostAddrActive
&& m
->AutoTunnelHostAddr
.b
[0])
8269 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
8270 LogInfo("mDNSPlatformClose: Removing AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
8271 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
8273 if (m
->p
->ConndBTMMDict
) CFRelease(m
->p
->ConndBTMMDict
);
8274 #endif // APPLE_OSX_mDNSResponder
8277 #if COMPILER_LIKES_PRAGMA_MARK
8279 #pragma mark - General Platform Support Layer functions
8282 mDNSexport mDNSu32
mDNSPlatformRandomNumber(void)
8284 return(arc4random());
8287 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
8288 mDNSexport mDNSu32 mDNSPlatformClockDivisor
= 0;
8290 mDNSexport mStatus
mDNSPlatformTimeInit(void)
8292 // Notes: Typical values for mach_timebase_info:
8293 // tbi.numer = 1000 million
8294 // tbi.denom = 33 million
8295 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
8296 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
8297 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
8298 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
8299 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
8301 // Arithmetic notes:
8302 // tbi.denom is at least 1, and not more than 2^32-1.
8303 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
8304 // tbi.denom is at least 1, and not more than 2^32-1.
8305 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
8306 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
8307 // which is unlikely on any current or future Macintosh.
8308 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
8309 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
8310 struct mach_timebase_info tbi
;
8311 kern_return_t result
= mach_timebase_info(&tbi
);
8312 if (result
== KERN_SUCCESS
) mDNSPlatformClockDivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
8316 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
8318 if (mDNSPlatformClockDivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
8320 static uint64_t last_mach_absolute_time
= 0;
8321 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
8322 uint64_t this_mach_absolute_time
= mach_absolute_time();
8323 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
8325 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
8326 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
8327 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
8328 last_mach_absolute_time
= this_mach_absolute_time
;
8329 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later.
8330 // (This bug happens all the time on 10.3, and we know that's not going to be fixed.)
8331 if (OSXVers
>= OSXVers_10_4_Tiger
)
8332 NotifyOfElusiveBug("mach_absolute_time went backwards!",
8333 "This error occurs from time to time, often on newly released hardware, "
8334 "and usually the exact cause is different in each instance.\r\r"
8335 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
8336 "and assign it to Radar Component “Kernel” Version “X”.");
8338 last_mach_absolute_time
= this_mach_absolute_time
;
8340 return((mDNSs32
)(this_mach_absolute_time
/ mDNSPlatformClockDivisor
));
8343 mDNSexport mDNSs32
mDNSPlatformUTC(void)
8348 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
8349 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
8350 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
8351 mDNSexport
void mDNSPlatformStrCopy( void *dst
, const void *src
) { strcpy((char *)dst
, (char *)src
); }
8352 mDNSexport mDNSu32
mDNSPlatformStrLen ( const void *src
) { return(strlen((char*)src
)); }
8353 mDNSexport
void mDNSPlatformMemCopy( void *dst
, const void *src
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
8354 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *dst
, const void *src
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
8355 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { memset(dst
, 0, len
); }
8356 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
8357 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
8359 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }
8361 mDNSexport
void mDNSPlatformSetAllowSleep(mDNS
*const m
, mDNSBool allowSleep
)
8363 if (allowSleep
&& m
->p
->IOPMAssertion
)
8365 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__
);
8366 IOPMAssertionRelease(m
->p
->IOPMAssertion
);
8367 m
->p
->IOPMAssertion
= 0;
8369 else if (!allowSleep
&& m
->p
->IOPMAssertion
== 0)
8371 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep
, kIOPMAssertionLevelOn
, CFSTR("mDNSResponder"), &m
->p
->IOPMAssertion
);
8372 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__
);