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"
53 #include <stdarg.h> // For va_list support
54 #include <stdlib.h> // For arc4random
56 #include <net/if_types.h> // For IFT_ETHER
57 #include <net/if_dl.h>
58 #include <net/bpf.h> // For BIOCSETIF etc.
60 #include <sys/param.h>
61 #include <sys/socket.h>
62 #include <sys/sysctl.h>
63 #include <sys/event.h>
65 #include <sys/ioctl.h>
66 #include <time.h> // platform support for UTC time
67 #include <arpa/inet.h> // for inet_aton
70 #include <netinet/in.h> // For IP_RECVTTL
72 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
75 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
76 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
77 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
78 #include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
80 #if TARGET_OS_EMBEDDED
81 #define NO_SECURITYFRAMEWORK 1
82 #define NO_CFUSERNOTIFICATION 1
85 #ifndef NO_SECURITYFRAMEWORK
86 #include <Security/SecureTransport.h>
87 #include <Security/Security.h>
88 #endif /* NO_SECURITYFRAMEWORK */
90 #include <DebugServices.h>
93 // Code contributed by Dave Heller:
94 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
95 // work on Mac OS X 10.1, which does not have the getifaddrs call.
96 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
97 #if RUN_ON_PUMA_WITHOUT_IFADDRS
98 #include "mDNSMacOSXPuma.c"
103 #include <IOKit/IOKitLib.h>
104 #include <IOKit/IOMessage.h>
106 #ifdef __LIB_DISPATCH__
107 // This is currently defined in IOKit/PrivateHeaders/IOKitLibPrivate.h. Till it becomes an Public
108 // API, we will have our own declaration
109 void IONotificationPortSetDispatchQueue(IONotificationPortRef notify
, dispatch_queue_t queue
);
112 #if USE_IOPMCOPYACTIVEPMPREFERENCES
113 #include <IOKit/ps/IOPowerSources.h>
114 #include <IOKit/ps/IOPowerSourcesPrivate.h>
117 #include <mach/mach_error.h>
118 #include <mach/mach_port.h>
119 #include <mach/mach_time.h>
124 #if APPLE_OSX_mDNSResponder
125 #include <DeviceToDeviceManager/DeviceToDeviceManager.h>
129 D2DStatus
D2DInitialize(CFRunLoopRef runLoop
, D2DServiceCallback serviceCallback
, void* userData
) __attribute__((weak_import
));
130 D2DStatus
D2DTerminate() __attribute__((weak_import
));
131 D2DStatus
D2DStartAdvertisingPair(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
) __attribute__((weak_import
));
132 D2DStatus
D2DStopAdvertisingPair(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
) __attribute__((weak_import
));
133 D2DStatus
D2DStartBrowsingForKey(const Byte
*key
, const size_t keySize
) __attribute__((weak_import
));
134 D2DStatus
D2DStopBrowsingForKey(const Byte
*key
, const size_t keySize
) __attribute__((weak_import
));
135 void D2DStartResolvingPair(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
) __attribute__((weak_import
));
136 void D2DStopResolvingPair(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
) __attribute__((weak_import
));
137 D2DStatus
D2DRetain(D2DServiceInstance instanceHandle
, D2DTransportType transportType
) __attribute__((weak_import
));
138 D2DStatus
D2DRelease(D2DServiceInstance instanceHandle
, D2DTransportType transportType
) __attribute__((weak_import
));
140 #define CHECK_D2D_FUNCTION(X) if (X)
147 #endif // APPLE_OSX_mDNSResponder
149 #define kInterfaceSpecificOption "interface="
151 // ***************************************************************************
154 #if COMPILER_LIKES_PRAGMA_MARK
155 #pragma mark - Globals
158 // By default we don't offer sleep proxy service
159 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
160 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
161 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
162 mDNSexport
int OfferSleepProxyService
= 0;
163 mDNSexport
int DisableSleepProxyClient
= 0;
165 // We disable inbound relay connection if this value is set to true (typically via command-line switch).
166 mDNSBool DisableInboundRelayConnection
= mDNSfalse
;
167 mDNSexport
int OSXVers
;
168 mDNSexport
int KQueueFD
;
170 #ifndef NO_SECURITYFRAMEWORK
171 static CFArrayRef ServerCerts
;
172 OSStatus
SSLSetAllowAnonymousCiphers(SSLContextRef context
, Boolean enable
);
173 #endif /* NO_SECURITYFRAMEWORK */
175 static CFStringRef NetworkChangedKey_IPv4
;
176 static CFStringRef NetworkChangedKey_IPv6
;
177 static CFStringRef NetworkChangedKey_Hostnames
;
178 static CFStringRef NetworkChangedKey_Computername
;
179 static CFStringRef NetworkChangedKey_DNS
;
180 static CFStringRef NetworkChangedKey_DynamicDNS
= CFSTR("Setup:/Network/DynamicDNS");
181 static CFStringRef NetworkChangedKey_BackToMyMac
= CFSTR("Setup:/Network/BackToMyMac");
182 static CFStringRef NetworkChangedKey_BTMMConnectivity
= CFSTR("State:/Network/Connectivity");
183 static CFStringRef NetworkChangedKey_PowerSettings
= CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
185 static char HINFO_HWstring_buffer
[32];
186 static char *HINFO_HWstring
= "Device";
187 static int HINFO_HWstring_prefixlen
= 6;
189 mDNSexport
int WatchDogReportingThreshold
= 250;
191 #ifdef __LIB_DISPATCH__
192 dispatch_queue_t SSLqueue
;
195 #if APPLE_OSX_mDNSResponder
196 static mDNSu8 SPMetricPortability
= 99;
197 static mDNSu8 SPMetricMarginalPower
= 99;
198 static mDNSu8 SPMetricTotalPower
= 99;
199 mDNSexport domainname ActiveDirectoryPrimaryDomain
;
200 mDNSexport
int ActiveDirectoryPrimaryDomainLabelCount
;
201 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer
;
202 #endif // APPLE_OSX_mDNSResponder
204 // ***************************************************************************
205 #if COMPILER_LIKES_PRAGMA_MARK
207 #pragma mark - D2D Support
212 // Name compression items for fake packet version number 1
213 static const mDNSu8 compression_packet_v1
= 0x01;
215 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" };
216 static mDNSu8
*const compression_limit
= (mDNSu8
*) &compression_base_msg
+ sizeof(DNSMessage
);
217 static mDNSu8
*const compression_lhs
= (mDNSu8
*const) compression_base_msg
.data
+ 27;
219 mDNSlocal
void FreeD2DARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
220 mDNSlocal
void PrintHex(mDNSu8
*data
, mDNSu16 len
);
222 static ARListElem
*D2DRecords
= NULL
; // List of locally-generated PTR records to records found via D2D
224 typedef struct D2DBrowseListElem
226 struct D2DBrowseListElem
*next
;
229 unsigned int refCount
;
232 D2DBrowseListElem
* D2DBrowseList
= NULL
;
234 mDNSlocal mDNSu8
*putVal16(mDNSu8
*ptr
, mDNSu16 val
)
236 ptr
[0] = (mDNSu8
)((val
>> 8 ) & 0xFF);
237 ptr
[1] = (mDNSu8
)((val
) & 0xFF);
238 return ptr
+ sizeof(mDNSu16
);
241 mDNSlocal mDNSu8
*putVal32(mDNSu8
*ptr
, mDNSu32 val
)
243 ptr
[0] = (mDNSu8
)((val
>> 24) & 0xFF);
244 ptr
[1] = (mDNSu8
)((val
>> 16) & 0xFF);
245 ptr
[2] = (mDNSu8
)((val
>> 8) & 0xFF);
246 ptr
[3] = (mDNSu8
)((val
) & 0xFF);
247 return ptr
+ sizeof(mDNSu32
);
250 mDNSlocal
void DomainnameToLower(const domainname
* const in
, domainname
* const out
)
252 const mDNSu8
* const start
= (const mDNSu8
* const)in
;
253 mDNSu8
*ptr
= (mDNSu8
*)start
;
257 out
->c
[ptr
-start
] = *ptr
;
259 for (;c
;c
--,ptr
++) out
->c
[ptr
-start
] = mDNSIsUpperCase(*ptr
) ? (*ptr
- 'A' + 'a') : *ptr
;
261 out
->c
[ptr
-start
] = *ptr
;
264 mDNSlocal mStatus
DNSNameCompressionParseBytes(mDNS
*const m
, const mDNSu8
*const lhs
, const mDNSu16 lhs_len
, const mDNSu8
*const rhs
, const mDNSu16 rhs_len
, AuthRecord
*rr
)
266 if (mDNS_LoggingEnabled
)
268 LogInfo("%s", __func__
);
269 LogInfo(" Static Bytes: ");
270 PrintHex((mDNSu8
*)&compression_base_msg
, compression_lhs
- (mDNSu8
*)&compression_base_msg
);
273 mDNSu8
*ptr
= compression_lhs
; // pointer to the end of our fake packet
275 // Check to make sure we're not going to go past the end of the DNSMessage data
276 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
277 if (ptr
+ lhs_len
- 7 + rhs_len
>= compression_limit
) return mStatus_NoMemoryErr
;
279 // Copy the LHS onto our fake wire packet
280 mDNSPlatformMemCopy(ptr
, lhs
, lhs_len
);
283 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
284 if (*ptr
!= compression_packet_v1
) return mStatus_Incompatible
;
286 // two bytes of CLASS
287 ptr
= putVal16(ptr
, kDNSClass_IN
| kDNSClass_UniqueRRSet
);
290 ptr
= putVal32(ptr
, 120);
292 // Copy the RHS length into the RDLENGTH of our fake wire packet
293 ptr
= putVal16(ptr
, rhs_len
);
295 // Copy the RHS onto our fake wire packet
296 mDNSPlatformMemCopy(ptr
, rhs
, rhs_len
);
299 if (mDNS_LoggingEnabled
)
301 LogInfo(" Our Bytes %d: ", __LINE__
);
302 PrintHex(compression_lhs
, ptr
- compression_lhs
);
305 ptr
= (mDNSu8
*) GetLargeResourceRecord(m
, &compression_base_msg
, compression_lhs
, ptr
, mDNSInterface_Any
, kDNSRecordTypePacketAns
, &m
->rec
);
306 if (!ptr
|| m
->rec
.r
.resrec
.RecordType
== kDNSRecordTypePacketNegative
)
307 { LogMsg("DNSNameCompressionParseBytes: failed to get large RR"); m
->rec
.r
.resrec
.RecordType
= 0; return mStatus_UnknownErr
; }
308 else LogInfo("DNSNameCompressionParseBytes: got rr: %s", CRDisplayString(m
, &m
->rec
.r
));
310 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_P2P
, m
->rec
.r
.resrec
.rrtype
, 7200, kDNSRecordTypeShared
, FreeD2DARElemCallback
, NULL
);
311 AssignDomainName(&rr
->namestorage
, &m
->rec
.namestorage
);
312 rr
->resrec
.rdlength
= m
->rec
.r
.resrec
.rdlength
;
313 rr
->resrec
.rdata
->MaxRDLength
= m
->rec
.r
.resrec
.rdlength
;
314 mDNSPlatformMemCopy(rr
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdlength
);
315 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
316 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
318 m
->rec
.r
.resrec
.RecordType
= 0; // Mark m->rec as no longer in use
320 return mStatus_NoError
;
323 mDNSlocal mDNSu8
* DNSNameCompressionBuildLHS(const domainname
const *typeDomain
, DNS_TypeValues qtype
)
325 mDNSu8
*ptr
= putDomainNameAsLabels(&compression_base_msg
, compression_lhs
, compression_limit
, typeDomain
);
326 if (!ptr
) return ptr
;
327 *ptr
= (qtype
>> 8) & 0xff;
331 *ptr
= compression_packet_v1
;
335 mDNSlocal mDNSu8
* DNSNameCompressionBuildRHS(mDNSu8
*start
, const ResourceRecord
*const resourceRecord
)
337 return putRData(&compression_base_msg
, start
, compression_limit
, resourceRecord
);
340 mDNSlocal
void PrintHex(mDNSu8
*data
, mDNSu16 len
)
342 mDNSu8
*end
= data
+ len
;
343 char buffer
[49] = {0};
344 char *bufend
= buffer
+ sizeof(buffer
);
348 for(; data
< end
&& ptr
< bufend
-1; ptr
+=3,data
++)
349 mDNS_snprintf(ptr
, bufend
- ptr
, "%02X ", *data
);
350 LogInfo(" %s", buffer
);
354 mDNSlocal
void PrintHelper(const char *const tag
, mDNSu8
*lhs
, mDNSu16 lhs_len
, mDNSu8
*rhs
, mDNSu16 rhs_len
)
356 if (!mDNS_LoggingEnabled
) return;
360 PrintHex(lhs
, lhs_len
);
365 PrintHex(rhs
, rhs_len
);
368 mDNSlocal
void FreeD2DARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
371 if (result
== mStatus_MemFree
)
373 ARListElem
**ptr
= &D2DRecords
;
375 while (*ptr
&& &(*ptr
)->ar
!= rr
) ptr
= &(*ptr
)->next
;
376 if (!*ptr
) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m
, rr
)); return; }
377 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m
, rr
));
380 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
381 mDNSPlatformMemFree(tmp
);
385 mDNSlocal
void xD2DClearCache(mDNS
*const m
, const domainname
*regType
)
387 ARListElem
*ptr
= D2DRecords
;
388 for ( ; ptr
; ptr
= ptr
->next
)
390 if (SameDomainName(&ptr
->ar
.namestorage
, regType
))
392 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
393 mDNS_Deregister(m
, &ptr
->ar
);
394 ConvertDomainNameToCString(regType
, buffer
);
395 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", buffer
);
400 mDNSlocal D2DBrowseListElem
** D2DFindInBrowseList(const domainname
*const name
, mDNSu16 type
)
402 D2DBrowseListElem
**ptr
= &D2DBrowseList
;
404 for ( ; *ptr
; ptr
= &(*ptr
)->next
)
405 if ((*ptr
)->type
== type
&& SameDomainName(&(*ptr
)->name
, name
))
411 mDNSlocal
unsigned int D2DBrowseListRefCount(const domainname
*const name
, mDNSu16 type
)
413 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
414 return *ptr
? (*ptr
)->refCount
: 0;
417 mDNSlocal
void D2DBrowseListRetain(const domainname
*const name
, mDNSu16 type
)
419 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
423 *ptr
= mDNSPlatformMemAllocate(sizeof(**ptr
));
424 mDNSPlatformMemZero(*ptr
, sizeof(**ptr
));
426 AssignDomainName(&(*ptr
)->name
, name
);
428 (*ptr
)->refCount
+= 1;
430 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
433 mDNSlocal
void D2DBrowseListRelease(const domainname
*const name
, mDNSu16 type
)
435 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
437 if (!*ptr
) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name
->c
, DNSTypeName(type
)); return; }
439 (*ptr
)->refCount
-= 1;
441 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
443 if (!(*ptr
)->refCount
)
445 D2DBrowseListElem
*tmp
= *ptr
;
447 mDNSPlatformMemFree(tmp
);
451 mDNSlocal mStatus
xD2DParse(mDNS
*const m
, const mDNSu8
* const lhs
, const mDNSu16 lhs_len
, const mDNSu8
* const rhs
, const mDNSu16 rhs_len
, AuthRecord
*rr
)
453 if (*(lhs
+ (lhs_len
- 1)) == compression_packet_v1
)
454 return DNSNameCompressionParseBytes(m
, lhs
, lhs_len
, rhs
, rhs_len
, rr
);
456 return mStatus_Incompatible
;
459 mDNSlocal
void xD2DAddToCache(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
461 (void)transportType
; // We don't care about this, yet.
462 (void)instanceHandle
; // We don't care about this, yet.
464 if (result
== kD2DSuccess
)
466 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
469 ARListElem
*ptr
= mDNSPlatformMemAllocate(sizeof(ARListElem
) + (valueSize
< sizeof(RData
) ? 0 : valueSize
- sizeof(RData
)));
471 if (ptr
== NULL
) { LogMsg("xD2DAddToCache: memory allocation failure"); return; }
473 err
= xD2DParse(m
, (const mDNSu8
* const)key
, (const mDNSu16
)keySize
, (const mDNSu8
* const)value
, (const mDNSu16
)valueSize
, &ptr
->ar
);
476 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err
);
477 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
478 mDNSPlatformMemFree(ptr
);
482 err
= mDNS_Register(m
, &ptr
->ar
);
485 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err
, ARDisplayString(m
, &ptr
->ar
));
486 mDNSPlatformMemFree(ptr
);
490 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m
, &ptr
->ar
));
491 ptr
->next
= D2DRecords
;
495 LogMsg("xD2DAddToCache: Unexpected result %d", result
);
498 mDNSlocal ARListElem
* xD2DFindInList(mDNS
*const m
, const Byte
*const key
, const size_t keySize
, const Byte
*const value
, const size_t valueSize
)
500 ARListElem
*ptr
= D2DRecords
;
503 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL
; }
505 arptr
= mDNSPlatformMemAllocate(sizeof(ARListElem
) + (valueSize
< sizeof(RData
) ? 0 : valueSize
- sizeof(RData
)));
506 if (arptr
== NULL
) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL
; }
508 if (xD2DParse(m
, (const mDNSu8
*const)key
, (const mDNSu16
)keySize
, (const mDNSu8
*const)value
, (const mDNSu16
)valueSize
, &arptr
->ar
) != mStatus_NoError
)
510 LogMsg("xD2DFindInList: xD2DParse failed for key: %p (%u) value: %p (%u)", key
, keySize
, value
, valueSize
);
511 mDNSPlatformMemFree(arptr
);
517 if (IdenticalResourceRecord(&arptr
->ar
.resrec
, &ptr
->ar
.resrec
)) break;
521 if (!ptr
) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(m
, &arptr
->ar
));
522 mDNSPlatformMemFree(arptr
);
526 mDNSlocal
void xD2DRemoveFromCache(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
528 (void)transportType
; // We don't care about this, yet.
529 (void)instanceHandle
; // We don't care about this, yet.
531 if (result
== kD2DSuccess
)
533 ARListElem
*ptr
= xD2DFindInList(m
, key
, keySize
, value
, valueSize
);
536 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m
, &ptr
->ar
));
537 mDNS_Deregister(m
, &ptr
->ar
);
541 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result
);
544 mDNSlocal
void xD2DServiceResolved(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
552 if (result
== kD2DSuccess
)
554 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle
);
555 CHECK_D2D_FUNCTION(D2DRetain
) D2DRetain(instanceHandle
, transportType
);
557 else LogMsg("xD2DServiceResolved: Unexpected result %d", result
);
560 mDNSlocal
void xD2DRetainHappened(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
563 (void)instanceHandle
;
570 if (result
== kD2DSuccess
) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle
);
571 else LogMsg("xD2DRetainHappened: Unexpected result %d", result
);
574 mDNSlocal
void xD2DReleaseHappened(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
577 (void)instanceHandle
;
584 if (result
== kD2DSuccess
) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle
);
585 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result
);
588 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
)
590 mDNS
*m
= (mDNS
*) userData
;
591 const char *eventString
= "unknown";
595 if (keySize
> 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize
);
596 if (valueSize
> 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize
);
600 case D2DServiceFound
:
601 eventString
= "D2DServiceFound";
604 eventString
= "D2DServiceLost";
606 case D2DServiceResolved
:
607 eventString
= "D2DServiceResolved";
609 case D2DServiceRetained
:
610 eventString
= "D2DServiceRetained";
612 case D2DServiceReleased
:
613 eventString
= "D2DServiceReleased";
619 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
);
620 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
624 case D2DServiceFound
:
625 xD2DAddToCache(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
628 xD2DRemoveFromCache(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
630 case D2DServiceResolved
:
631 xD2DServiceResolved(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
633 case D2DServiceRetained
:
634 xD2DRetainHappened(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
636 case D2DServiceReleased
:
637 xD2DReleaseHappened(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
643 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
644 KQueueUnlock(m
, "xD2DServiceCallback");
647 mDNSexport
void external_start_browsing_for_service(mDNS
*const m
, const domainname
*const typeDomain
, DNS_TypeValues qtype
)
652 if (qtype
== kDNSServiceType_A
|| qtype
== kDNSServiceType_AAAA
)
654 LogInfo("external_start_browsing_for_service: ignoring address record");
658 DomainnameToLower(typeDomain
, &lower
);
660 if (!D2DBrowseListRefCount(&lower
, qtype
))
662 LogInfo("external_start_browsing_for_service: Starting browse for: %##s %s", lower
.c
, DNSTypeName(qtype
));
663 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
664 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
665 CHECK_D2D_FUNCTION(D2DStartBrowsingForKey
) D2DStartBrowsingForKey(compression_lhs
, end
- compression_lhs
);
667 D2DBrowseListRetain(&lower
, qtype
);
670 mDNSexport
void external_stop_browsing_for_service(mDNS
*const m
, const domainname
*const typeDomain
, DNS_TypeValues qtype
)
674 if (qtype
== kDNSServiceType_A
|| qtype
== kDNSServiceType_AAAA
)
676 LogInfo("external_stop_browsing_for_service: ignoring address record");
680 DomainnameToLower(typeDomain
, &lower
);
682 D2DBrowseListRelease(&lower
, qtype
);
683 if (!D2DBrowseListRefCount(&lower
, qtype
))
685 LogInfo("external_stop_browsing_for_service: Stopping browse for: %##s %s", lower
.c
, DNSTypeName(qtype
));
686 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
687 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
688 CHECK_D2D_FUNCTION(D2DStopBrowsingForKey
) D2DStopBrowsingForKey(compression_lhs
, end
- compression_lhs
);
689 xD2DClearCache(m
, &lower
);
693 mDNSexport
void external_start_advertising_service(const ResourceRecord
*const resourceRecord
)
698 DomainnameToLower(resourceRecord
->name
, &lower
);
700 LogInfo("external_start_advertising_service: %s", RRDisplayString(&mDNSStorage
, resourceRecord
));
701 if (resourceRecord
->rrtype
== kDNSServiceType_A
|| resourceRecord
->rrtype
== kDNSServiceType_AAAA
)
703 LogInfo("external_start_advertising_service: ignoring address record");
706 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
707 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
708 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
709 CHECK_D2D_FUNCTION(D2DStartAdvertisingPair
) D2DStartAdvertisingPair(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
712 mDNSexport
void external_stop_advertising_service(const ResourceRecord
*const resourceRecord
)
717 DomainnameToLower(resourceRecord
->name
, &lower
);
719 LogInfo("external_stop_advertising_service: %s", RRDisplayString(&mDNSStorage
, resourceRecord
));
720 if (resourceRecord
->rrtype
== kDNSServiceType_A
|| resourceRecord
->rrtype
== kDNSServiceType_AAAA
)
722 LogInfo("external_stop_advertising_service: ignoring address record");
725 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
726 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
727 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
728 CHECK_D2D_FUNCTION(D2DStopAdvertisingPair
) D2DStopAdvertisingPair(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
731 mDNSexport
void external_start_resolving_service(const domainname
*const fqdn
)
736 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
738 LogInfo("external_start_resolving_service: %##s", fqdn
->c
);
739 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
740 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
741 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
742 CHECK_D2D_FUNCTION(D2DStartResolvingPair
) D2DStartResolvingPair(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
745 mDNSexport
void external_stop_resolving_service(const domainname
*const fqdn
)
750 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
752 LogInfo("external_stop_resolving_service: %##s", fqdn
->c
);
753 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
754 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
755 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
756 CHECK_D2D_FUNCTION(D2DStopResolvingPair
) D2DStopResolvingPair(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
759 #elif APPLE_OSX_mDNSResponder
761 mDNSexport
void external_start_browsing_for_service(mDNS
*const m
, const domainname
*const type
, DNS_TypeValues qtype
) { (void)m
; (void)type
; (void)qtype
; }
762 mDNSexport
void external_stop_browsing_for_service(mDNS
*const m
, const domainname
*const type
, DNS_TypeValues qtype
) { (void)m
; (void)type
; (void)qtype
; }
763 mDNSexport
void external_start_advertising_service(const ResourceRecord
*const resourceRecord
) { (void)resourceRecord
; }
764 mDNSexport
void external_stop_advertising_service(const ResourceRecord
*const resourceRecord
) { (void)resourceRecord
; }
765 mDNSexport
void external_start_resolving_service(const domainname
*const fqdn
) { (void)fqdn
; }
766 mDNSexport
void external_stop_resolving_service(const domainname
*const fqdn
) { (void)fqdn
; }
770 // ***************************************************************************
773 #if COMPILER_LIKES_PRAGMA_MARK
775 #pragma mark - Utility Functions
778 // We only attempt to send and receive multicast packets on interfaces that are
779 // (a) flagged as multicast-capable
780 // (b) *not* flagged as point-to-point (e.g. modem)
781 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
782 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
783 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
784 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
786 mDNSexport
void NotifyOfElusiveBug(const char *title
, const char *msg
) // Both strings are UTF-8 text
788 static int notifyCount
= 0;
789 if (notifyCount
) return;
791 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
792 // To avoid this, we don't try to display alerts in the first three minutes after boot.
793 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return;
795 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
798 // Determine if we're at Apple (17.*.*.*)
799 extern mDNS mDNSStorage
;
800 NetworkInterfaceInfoOSX
*i
;
801 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
802 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& i
->ifinfo
.ip
.ip
.v4
.b
[0] == 17)
804 if (!i
) return; // If not at Apple, don't show the alert
810 // Display a notification to the user
813 #ifndef NO_CFUSERNOTIFICATION
814 mDNSNotify(title
, msg
);
815 #endif /* NO_CFUSERNOTIFICATION */
818 mDNSlocal
struct ifaddrs
*myGetIfAddrs(int refresh
)
820 static struct ifaddrs
*ifa
= NULL
;
828 if (ifa
== NULL
) getifaddrs(&ifa
);
833 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
834 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, const char *ifname
, int type
)
836 NetworkInterfaceInfoOSX
*i
;
837 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
838 if (i
->Exists
&& !strcmp(i
->ifinfo
.ifname
, ifname
) &&
839 ((type
== AF_UNSPEC
) ||
840 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
841 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
))) return(i
);
845 mDNSlocal
int myIfIndexToName(u_short ifindex
, char *name
)
848 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
849 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
850 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== ifindex
)
851 { strlcpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
855 mDNSexport NetworkInterfaceInfoOSX
*IfindexToInterfaceInfoOSX(const mDNS
*const m
, mDNSInterfaceID ifindex
)
857 mDNSu32 scope_id
= (mDNSu32
)(uintptr_t)ifindex
;
858 NetworkInterfaceInfoOSX
*i
;
860 // Don't get tricked by inactive interfaces
861 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
862 if (i
->Registered
&& i
->scope_id
== scope_id
) return(i
);
867 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS
*const m
, mDNSu32 ifindex
)
869 if (ifindex
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
870 if (ifindex
== kDNSServiceInterfaceIndexP2P
) return(mDNSInterface_P2P
);
871 if (ifindex
== kDNSServiceInterfaceIndexAny
) return(mDNSNULL
);
873 NetworkInterfaceInfoOSX
* ifi
= IfindexToInterfaceInfoOSX(m
, (mDNSInterfaceID
)(uintptr_t)ifindex
);
876 // Not found. Make sure our interface list is up to date, then try again.
877 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex
);
878 mDNSMacOSXNetworkChanged(m
);
879 ifi
= IfindexToInterfaceInfoOSX(m
, (mDNSInterfaceID
)(uintptr_t)ifindex
);
882 if (!ifi
) return(mDNSNULL
);
884 return(ifi
->ifinfo
.InterfaceID
);
888 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS
*const m
, mDNSInterfaceID id
)
890 NetworkInterfaceInfoOSX
*i
;
891 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
892 if (id
== mDNSInterface_P2P
) return(kDNSServiceInterfaceIndexP2P
);
893 if (id
== mDNSInterface_Any
) return(0);
895 mDNSu32 scope_id
= (mDNSu32
)(uintptr_t)id
;
897 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
898 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
899 if (i
->scope_id
== scope_id
) return(i
->scope_id
);
901 // Not found. Make sure our interface list is up to date, then try again.
902 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id
);
903 mDNSMacOSXNetworkChanged(m
);
904 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
905 if (i
->scope_id
== scope_id
) return(i
->scope_id
);
910 #if APPLE_OSX_mDNSResponder
911 mDNSexport
void mDNSASLLog(uuid_t
*uuid
, const char *subdomain
, const char *result
, const char *signature
, const char *fmt
, ...)
913 if (OSXVers
< OSXVers_10_6_SnowLeopard
) return;
915 static char buffer
[512];
916 aslmsg asl_msg
= asl_new(ASL_TYPE_MSG
);
918 if (!asl_msg
) { LogMsg("mDNSASLLog: asl_new failed"); return; }
922 uuid_unparse(*uuid
, uuidStr
);
923 asl_set (asl_msg
, "com.apple.message.uuid", uuidStr
);
926 static char domainBase
[] = "com.apple.mDNSResponder.%s";
927 mDNS_snprintf (buffer
, sizeof(buffer
), domainBase
, subdomain
);
928 asl_set (asl_msg
, "com.apple.message.domain", buffer
);
930 if (result
) asl_set(asl_msg
, "com.apple.message.result", result
);
931 if (signature
) asl_set(asl_msg
, "com.apple.message.signature", signature
);
935 mDNS_vsnprintf(buffer
, sizeof(buffer
), fmt
, ptr
);
938 int old_filter
= asl_set_filter(NULL
,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
));
939 asl_log(NULL
, asl_msg
, ASL_LEVEL_DEBUG
, "%s", buffer
);
940 asl_set_filter(NULL
, old_filter
);
943 #endif // APPLE_OSX_mDNSResponder
945 #if COMPILER_LIKES_PRAGMA_MARK
947 #pragma mark - UDP & TCP send & receive
950 mDNSlocal mDNSBool
AddrRequiresPPPConnection(const struct sockaddr
*addr
)
952 mDNSBool result
= mDNSfalse
;
953 SCNetworkConnectionFlags flags
;
954 SCNetworkReachabilityRef ReachRef
= NULL
;
956 ReachRef
= SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault
, addr
);
957 if (!ReachRef
) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end
; }
958 if (!SCNetworkReachabilityGetFlags(ReachRef
, &flags
)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end
; }
959 result
= flags
& kSCNetworkFlagsConnectionRequired
;
962 if (ReachRef
) CFRelease(ReachRef
);
966 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
967 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
968 // OR send via our primary v4 unicast socket
969 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
970 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
971 mDNSInterfaceID InterfaceID
, UDPSocket
*src
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
973 NetworkInterfaceInfoOSX
*info
= mDNSNULL
;
974 struct sockaddr_storage to
;
976 mStatus result
= mStatus_NoError
;
980 info
= IfindexToInterfaceInfoOSX(m
, InterfaceID
);
983 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID
);
984 return mStatus_BadParamErr
;
988 char *ifa_name
= InterfaceID
? info
->ifinfo
.ifname
: "unicast";
990 if (dst
->type
== mDNSAddrType_IPv4
)
992 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
993 sin_to
->sin_len
= sizeof(*sin_to
);
994 sin_to
->sin_family
= AF_INET
;
995 sin_to
->sin_port
= dstPort
.NotAnInteger
;
996 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
997 s
= (src
? src
->ss
: m
->p
->permanentsockets
).sktv4
;
999 if (info
) // Specify outgoing interface
1001 if (!mDNSAddrIsDNSMulticast(dst
))
1004 if (info
->scope_id
== 0)
1005 LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info
, ifa_name
);
1007 setsockopt(s
, IPPROTO_IP
, IP_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1010 static int displayed
= 0;
1011 if (displayed
< 1000)
1014 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
1020 #ifdef IP_MULTICAST_IFINDEX
1022 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IFINDEX
, &info
->scope_id
, sizeof(info
->scope_id
));
1023 // We get an error when we compile on a machine that supports this option and run the binary on
1024 // a different machine that does not support it
1027 if (errno
!= ENOPROTOOPT
) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno
);
1028 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
1029 if (err
< 0 && !m
->p
->NetworkChanged
)
1030 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
1035 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
1036 if (err
< 0 && !m
->p
->NetworkChanged
)
1037 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
1044 else if (dst
->type
== mDNSAddrType_IPv6
)
1046 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
1047 sin6_to
->sin6_len
= sizeof(*sin6_to
);
1048 sin6_to
->sin6_family
= AF_INET6
;
1049 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
1050 sin6_to
->sin6_flowinfo
= 0;
1051 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1052 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
1053 s
= (src
? src
->ss
: m
->p
->permanentsockets
).sktv6
;
1054 if (info
&& mDNSAddrIsDNSMulticast(dst
)) // Specify outgoing interface
1056 err
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1057 if (err
< 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err
, errno
, strerror(errno
));
1063 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1067 return mStatus_BadParamErr
;
1071 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1072 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
1074 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1075 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
1077 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1078 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1079 if (s
< 0) return(mStatus_Invalid
);
1081 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
1084 static int MessageCount
= 0;
1085 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1086 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
1087 if (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== EHOSTUNREACH
|| errno
== ENETUNREACH
) return(mStatus_TransientErr
);
1088 // Don't report EHOSTUNREACH in the first three minutes after boot
1089 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1090 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1091 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(mStatus_TransientErr
);
1092 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1093 if (errno
== EADDRNOTAVAIL
&& m
->p
->NetworkChanged
) return(mStatus_TransientErr
);
1094 if (MessageCount
< 1000)
1097 if (errno
== EHOSTUNREACH
|| errno
== EADDRNOTAVAIL
|| errno
== ENETDOWN
)
1098 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1099 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
1101 LogMsg("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1102 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
1104 result
= mStatus_UnknownErr
;
1108 if (dst
->type
== mDNSAddrType_IPv4
&& info
&& !mDNSAddrIsDNSMulticast(dst
))
1110 static const mDNSu32 ifindex
= 0;
1111 setsockopt(s
, IPPROTO_IP
, IP_BOUND_IF
, &ifindex
, sizeof(ifindex
));
1118 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
1119 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
1121 static unsigned int numLogMessages
= 0;
1122 struct iovec databuffers
= { (char *)buffer
, max
};
1125 struct cmsghdr
*cmPtr
;
1126 char ancillary
[1024];
1128 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1130 // Set up the message
1131 msg
.msg_name
= (caddr_t
)from
;
1132 msg
.msg_namelen
= *fromlen
;
1133 msg
.msg_iov
= &databuffers
;
1135 msg
.msg_control
= (caddr_t
)&ancillary
;
1136 msg
.msg_controllen
= sizeof(ancillary
);
1140 n
= recvmsg(s
, &msg
, 0);
1143 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
1146 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
1148 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1149 s
, n
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
1152 if (msg
.msg_flags
& MSG_CTRUNC
)
1154 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
1158 *fromlen
= msg
.msg_namelen
;
1160 // Parse each option out of the ancillary data.
1161 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
1163 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1164 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
1166 dstaddr
->type
= mDNSAddrType_IPv4
;
1167 dstaddr
->ip
.v4
= *(mDNSv4Addr
*)CMSG_DATA(cmPtr
);
1168 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
1170 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
1172 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
1173 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
1175 mDNSPlatformMemCopy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
1176 ifname
[sdl
->sdl_nlen
] = 0;
1177 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1180 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
1181 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
1182 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
1184 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
1185 dstaddr
->type
= mDNSAddrType_IPv6
;
1186 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
1187 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
1189 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
1190 *ttl
= *(int*)CMSG_DATA(cmPtr
);
1196 mDNSlocal
void myKQSocketCallBack(int s1
, short filter
, void *context
)
1198 KQSocketSet
*const ss
= (KQSocketSet
*)context
;
1199 mDNS
*const m
= ss
->m
;
1200 int err
= 0, count
= 0, closed
= 0;
1202 if (filter
!= EVFILT_READ
)
1203 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter
, EVFILT_READ
);
1211 LogMsg("myKQSocketCallBack: native socket %d", s1
);
1212 LogMsg("myKQSocketCallBack: sktv4 %d", ss
->sktv4
);
1214 LogMsg("myKQSocketCallBack: sktv6 %d", ss
->sktv6
);
1220 mDNSAddr senderAddr
, destAddr
;
1221 mDNSIPPort senderPort
;
1222 struct sockaddr_storage from
;
1223 size_t fromlen
= sizeof(from
);
1224 char packetifname
[IF_NAMESIZE
] = "";
1226 err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
1230 if (from
.ss_family
== AF_INET
)
1232 struct sockaddr_in
*s
= (struct sockaddr_in
*)&from
;
1233 senderAddr
.type
= mDNSAddrType_IPv4
;
1234 senderAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
1235 senderPort
.NotAnInteger
= s
->sin_port
;
1236 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1238 else if (from
.ss_family
== AF_INET6
)
1240 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
1241 senderAddr
.type
= mDNSAddrType_IPv6
;
1242 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
1243 senderPort
.NotAnInteger
= sin6
->sin6_port
;
1244 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1248 LogMsg("myKQSocketCallBack from is unknown address family %d", from
.ss_family
);
1252 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1253 mDNSInterfaceID InterfaceID
= mDNSNULL
;
1254 //NetworkInterfaceInfo *intf = m->HostInterfaces;
1255 //while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
1257 NetworkInterfaceInfoOSX
*intf
= m
->p
->InterfaceList
;
1258 while (intf
&& strcmp(intf
->ifinfo
.ifname
, packetifname
)) intf
= intf
->next
;
1260 // When going to sleep we deregister all our interfaces, but if the machine
1261 // takes a few seconds to sleep we may continue to receive multicasts
1262 // during that time, which would confuse mDNSCoreReceive, because as far
1263 // as it's concerned, we should have no active interfaces any more.
1264 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1265 if (intf
) InterfaceID
= intf
->ifinfo
.InterfaceID
;
1266 else if (mDNSAddrIsDNSMulticast(&destAddr
)) continue;
1268 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1269 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
1271 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
1272 // loop when that happens, or we may try to read from an invalid FD. We do this by
1273 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
1274 // if it closes the socketset.
1275 ss
->closeFlag
= &closed
;
1277 mDNSCoreReceive(m
, &m
->imsg
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, ss
->port
, InterfaceID
);
1279 // if we didn't close, we can safely dereference the socketset, and should to
1280 // reset the closeFlag, since it points to something on the stack
1281 if (!closed
) ss
->closeFlag
= mDNSNULL
;
1284 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
1286 // Something is busted here.
1287 // kqueue says there is a packet, but myrecvfrom says there is not.
1288 // Try calling select() to get another opinion.
1289 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1290 // All of this is racy, as data may have arrived after the call to select()
1291 static unsigned int numLogMessages
= 0;
1292 int save_errno
= errno
;
1296 socklen_t solen
= sizeof(int);
1298 struct timeval timeout
;
1301 FD_SET(s1
, &readfds
);
1303 timeout
.tv_usec
= 0;
1304 selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
1305 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
1306 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
1307 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
1308 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
1309 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
1310 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno
);
1311 if (numLogMessages
++ < 100)
1312 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1313 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
1314 if (numLogMessages
> 5)
1315 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1316 "Congratulations, you've reproduced an elusive bug.\r"
1317 "Please contact the current assignee of <rdar://problem/3375328>.\r"
1318 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1319 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1321 sleep(1); // After logging this error, rate limit so we don't flood syslog
1325 // TCP socket support
1330 handshake_in_progress
,
1331 handshake_completed
,
1332 handshake_to_be_closed
1335 struct TCPSocket_struct
1337 TCPSocketFlags flags
; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
1338 TCPConnectionCallback callback
;
1340 KQueueEntry
*kqEntry
;
1342 #ifndef NO_SECURITYFRAMEWORK
1343 SSLContextRef tlsContext
;
1344 pthread_t handshake_thread
;
1345 #endif /* NO_SECURITYFRAMEWORK */
1346 domainname hostname
;
1350 handshakeStatus handshake
;
1351 mDNS
*m
; // So we can call KQueueLock from the SSLHandshake thread
1355 mDNSlocal
void doTcpSocketCallback(TCPSocket
*sock
)
1357 mDNSBool c
= !sock
->connected
;
1358 sock
->connected
= mDNStrue
;
1359 sock
->callback(sock
, sock
->context
, c
, sock
->err
);
1360 // Note: the callback may call CloseConnection here, which frees the context structure!
1363 #ifndef NO_SECURITYFRAMEWORK
1365 mDNSlocal OSStatus
tlsWriteSock(SSLConnectionRef connection
, const void *data
, size_t *dataLength
)
1367 int ret
= send(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1368 if (ret
>= 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1369 if (ret
>= 0) { *dataLength
= ret
; return(noErr
); }
1371 if (errno
== EAGAIN
) return(errSSLWouldBlock
);
1372 if (errno
== ENOENT
) return(errSSLClosedGraceful
);
1373 if (errno
== EPIPE
|| errno
== ECONNRESET
) return(errSSLClosedAbort
);
1374 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket
*)connection
)->fd
, errno
, strerror(errno
));
1375 return(errSSLClosedAbort
);
1378 mDNSlocal OSStatus
tlsReadSock(SSLConnectionRef connection
, void *data
, size_t *dataLength
)
1380 int ret
= recv(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1381 if (ret
> 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1382 if (ret
> 0) { *dataLength
= ret
; return(noErr
); }
1384 if (ret
== 0 || errno
== ENOENT
) return(errSSLClosedGraceful
);
1385 if ( errno
== EAGAIN
) return(errSSLWouldBlock
);
1386 if ( errno
== ECONNRESET
) return(errSSLClosedAbort
);
1387 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno
, strerror(errno
));
1388 return(errSSLClosedAbort
);
1391 mDNSlocal OSStatus
tlsSetupSock(TCPSocket
*sock
, mDNSBool server
)
1393 char domname_cstr
[MAX_ESCAPED_DOMAIN_NAME
];
1395 mStatus err
= SSLNewContext(server
, &sock
->tlsContext
);
1396 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err
); return(err
); }
1398 err
= SSLSetIOFuncs(sock
->tlsContext
, tlsReadSock
, tlsWriteSock
);
1399 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err
); return(err
); }
1401 err
= SSLSetConnection(sock
->tlsContext
, (SSLConnectionRef
) sock
);
1402 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err
); return(err
); }
1404 // Instead of listing all the acceptable ciphers, we just disable the bad ciphers. It does not disable
1405 // all the bad ciphers like RC4_MD5, but it assumes that the servers don't offer them.
1406 err
= SSLSetAllowAnonymousCiphers(sock
->tlsContext
, 0);
1407 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err
); return(err
); }
1409 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
1410 // (error not in OSStatus space) is okay.
1411 if (!sock
->hostname
.c
[0]) {LogMsg("ERROR: tlsSetupSock: hostname NULL"); return -1; }
1413 ConvertDomainNameToCString(&sock
->hostname
, domname_cstr
);
1414 err
= SSLSetPeerDomainName(sock
->tlsContext
, domname_cstr
, strlen(domname_cstr
));
1415 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr
, err
); return(err
); }
1420 #ifdef __LIB_DISPATCH__
1421 mDNSlocal
void doSSLHandshake(void *ctx
)
1423 TCPSocket
*sock
= (TCPSocket
*)ctx
;
1424 mStatus err
= SSLHandshake(sock
->tlsContext
);
1426 //Can't have multiple threads in mDNS core. When __LIB_DISPATCH__ is
1427 //defined, KQueueLock is a noop. Hence we need to serialize here
1429 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
1430 //We need the rest of the logic also. Otherwise, we can enable the READ
1431 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
1432 //ConnFailed which means we are going to free the tcpInfo. While it
1433 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
1434 //and potentially call doTCPCallback with error which can close the fd and free the
1435 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
1438 dispatch_async(dispatch_get_main_queue(), ^{
1440 LogInfo("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
1442 if (sock
->handshake
== handshake_to_be_closed
)
1444 LogInfo("SSLHandshake completed after close");
1445 mDNSPlatformTCPCloseConnection(sock
);
1449 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1450 else LogMsg("doSSLHandshake: sock->fd is -1");
1452 if (err
== errSSLWouldBlock
)
1453 sock
->handshake
= handshake_required
;
1458 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
1459 SSLDisposeContext(sock
->tlsContext
);
1460 sock
->tlsContext
= NULL
;
1463 sock
->err
= err
? mStatus_ConnFailed
: 0;
1464 sock
->handshake
= handshake_completed
;
1466 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
1467 doTcpSocketCallback(sock
);
1471 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
1476 mDNSlocal
void *doSSLHandshake(void *ctx
)
1478 // Warning: Touching sock without the kqueue lock!
1479 // We're protected because sock->handshake == handshake_in_progress
1480 TCPSocket
*sock
= (TCPSocket
*)ctx
;
1481 mDNS
* const m
= sock
->m
; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
1482 mStatus err
= SSLHandshake(sock
->tlsContext
);
1485 debugf("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
1487 if (sock
->handshake
== handshake_to_be_closed
)
1489 LogInfo("SSLHandshake completed after close");
1490 mDNSPlatformTCPCloseConnection(sock
);
1494 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1495 else LogMsg("doSSLHandshake: sock->fd is -1");
1497 if (err
== errSSLWouldBlock
)
1498 sock
->handshake
= handshake_required
;
1503 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
1504 SSLDisposeContext(sock
->tlsContext
);
1505 sock
->tlsContext
= NULL
;
1508 sock
->err
= err
? mStatus_ConnFailed
: 0;
1509 sock
->handshake
= handshake_completed
;
1511 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
1512 doTcpSocketCallback(sock
);
1516 debugf("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
1517 KQueueUnlock(m
, "doSSLHandshake");
1522 mDNSlocal mStatus
spawnSSLHandshake(TCPSocket
* sock
)
1524 debugf("spawnSSLHandshake %p: entry", sock
);
1527 if (sock
->handshake
!= handshake_required
) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock
->handshake
);
1528 sock
->handshake
= handshake_in_progress
;
1529 KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_READ
, sock
->kqEntry
);
1530 #ifdef __LIB_DISPATCH__
1532 // Dispatch it on a separate serial queue to avoid deadlocks with threads running on main queue
1533 dispatch_async(SSLqueue
, ^{doSSLHandshake(sock
);});
1536 pthread_attr_t attr
;
1537 pthread_attr_init(&attr
);
1538 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
1539 err
= pthread_create(&sock
->handshake_thread
, &attr
, doSSLHandshake
, sock
);
1540 pthread_attr_destroy(&attr
);
1543 LogMsg("Could not start SSLHandshake thread: (%d) %s", err
, strerror(err
));
1544 sock
->handshake
= handshake_completed
;
1546 KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1549 debugf("spawnSSLHandshake %p: done for %d", sock
, sock
->fd
);
1553 mDNSlocal mDNSBool
IsTunnelModeDomain(const domainname
*d
)
1555 static const domainname
*mmc
= (const domainname
*) "\x7" "members" "\x3" "mac" "\x3" "com";
1556 const domainname
*d1
= mDNSNULL
; // TLD
1557 const domainname
*d2
= mDNSNULL
; // SLD
1558 const domainname
*d3
= mDNSNULL
;
1559 while (d
->c
[0]) { d3
= d2
; d2
= d1
; d1
= d
; d
= (const domainname
*)(d
->c
+ 1 + d
->c
[0]); }
1560 return(d3
&& SameDomainName(d3
, mmc
));
1563 #endif /* NO_SECURITYFRAMEWORK */
1565 mDNSlocal
void tcpKQSocketCallback(__unused
int fd
, short filter
, void *context
)
1567 TCPSocket
*sock
= context
;
1568 sock
->err
= mStatus_NoError
;
1570 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1571 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1572 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1573 if (filter
== EVFILT_WRITE
) KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_WRITE
, sock
->kqEntry
);
1575 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1577 #ifndef NO_SECURITYFRAMEWORK
1578 if (!sock
->setup
) { sock
->setup
= mDNStrue
; tlsSetupSock(sock
, mDNSfalse
); }
1580 if (sock
->handshake
== handshake_required
) { if (spawnSSLHandshake(sock
) == 0) return; }
1581 else if (sock
->handshake
== handshake_in_progress
|| sock
->handshake
== handshake_to_be_closed
) return;
1582 else if (sock
->handshake
!= handshake_completed
)
1584 if (!sock
->err
) sock
->err
= mStatus_UnknownErr
;
1585 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock
->handshake
);
1588 sock
->err
= mStatus_UnsupportedErr
;
1589 #endif /* NO_SECURITYFRAMEWORK */
1592 doTcpSocketCallback(sock
);
1595 #ifdef __LIB_DISPATCH__
1596 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, KQueueEntry
*const entryRef
)
1598 dispatch_queue_t queue
= dispatch_get_main_queue();
1599 dispatch_source_t source
;
1600 if (flags
== EV_DELETE
)
1602 if (filter
== EVFILT_READ
)
1604 dispatch_source_cancel(entryRef
->readSource
);
1605 dispatch_release(entryRef
->readSource
);
1606 entryRef
->readSource
= mDNSNULL
;
1607 debugf("KQueueSet: source cancel for read %p, %p", entryRef
->readSource
, entryRef
->writeSource
);
1609 else if (filter
== EVFILT_WRITE
)
1611 dispatch_source_cancel(entryRef
->writeSource
);
1612 dispatch_release(entryRef
->writeSource
);
1613 entryRef
->writeSource
= mDNSNULL
;
1614 debugf("KQueueSet: source cancel for write %p, %p", entryRef
->readSource
, entryRef
->writeSource
);
1617 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter
);
1620 if (flags
!= EV_ADD
) LogMsg("KQueueSet: Invalid flags %d", flags
);
1622 if (filter
== EVFILT_READ
)
1624 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, fd
, 0, queue
);
1626 else if (filter
== EVFILT_WRITE
)
1628 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE
, fd
, 0, queue
);
1632 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter
);
1635 if (!source
) return -1;
1636 dispatch_source_set_event_handler(source
, ^{
1638 mDNSs32 stime
= mDNSPlatformRawTime();
1639 entryRef
->KQcallback(fd
, filter
, entryRef
->KQcontext
);
1640 mDNSs32 etime
= mDNSPlatformRawTime();
1641 if (etime
- stime
>= WatchDogReportingThreshold
)
1642 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime
- stime
);
1644 // Trigger the event delivery to the application. Even though we trigger the
1645 // event completion after handling every event source, these all will hopefully
1647 TriggerEventCompletion();
1650 dispatch_source_set_cancel_handler(source
, ^{
1651 if (entryRef
->fdClosed
)
1653 //LogMsg("CancelHandler: closing fd %d", fd);
1657 dispatch_resume(source
);
1658 if (filter
== EVFILT_READ
)
1659 entryRef
->readSource
= source
;
1661 entryRef
->writeSource
= source
;
1666 mDNSexport
void KQueueLock(mDNS
*const m
)
1670 mDNSexport
void KQueueUnlock(mDNS
*const m
, const char const *task
)
1673 (void)task
; //unused
1676 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, const KQueueEntry
*const entryRef
)
1678 struct kevent new_event
;
1679 EV_SET(&new_event
, fd
, filter
, flags
, 0, 0, (void*)entryRef
);
1680 return (kevent(KQueueFD
, &new_event
, 1, NULL
, 0, NULL
) < 0) ? errno
: 0;
1683 mDNSexport
void KQueueLock(mDNS
*const m
)
1685 pthread_mutex_lock(&m
->p
->BigMutex
);
1686 m
->p
->BigMutexStartTime
= mDNSPlatformRawTime();
1689 mDNSexport
void KQueueUnlock(mDNS
*const m
, const char const *task
)
1691 mDNSs32 end
= mDNSPlatformRawTime();
1693 if (end
- m
->p
->BigMutexStartTime
>= WatchDogReportingThreshold
)
1694 LogInfo("WARNING: %s took %dms to complete", task
, end
- m
->p
->BigMutexStartTime
);
1696 pthread_mutex_unlock(&m
->p
->BigMutex
);
1699 if (send(m
->p
->WakeKQueueLoopFD
, &wake
, sizeof(wake
), 0) == -1)
1700 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno
, strerror(errno
));
1704 mDNSexport
void mDNSPlatformCloseFD(KQueueEntry
*kq
, int fd
)
1706 #ifdef __LIB_DISPATCH__
1710 dispatch_source_cancel(kq
->readSource
);
1711 kq
->readSource
= mDNSNULL
;
1713 if (kq
->writeSource
)
1715 dispatch_source_cancel(kq
->writeSource
);
1716 kq
->writeSource
= mDNSNULL
;
1718 // Close happens in the cancellation handler
1719 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd
);
1720 kq
->fdClosed
= mDNStrue
;
1727 mDNSlocal mStatus
SetupTCPSocket(TCPSocket
*sock
, u_short sa_family
, mDNSIPPort
*port
)
1729 KQSocketSet
*cp
= &sock
->ss
;
1731 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1732 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1734 int *s
= &cp
->sktv4
;
1735 KQueueEntry
*k
= &cp
->kqsv4
;
1737 const int on
= 1; // "on" for setsockopt
1740 int skt
= socket(sa_family
, SOCK_STREAM
, IPPROTO_TCP
);
1741 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
1742 if (sa_family
== AF_INET
)
1745 struct sockaddr_in addr
;
1746 mDNSPlatformMemZero(&addr
, sizeof(addr
));
1747 addr
.sin_family
= AF_INET
;
1748 addr
.sin_port
= port
->NotAnInteger
;
1749 err
= bind(skt
, (struct sockaddr
*) &addr
, sizeof(addr
));
1750 if (err
< 0) { LogMsg("ERROR: bind %s", strerror(errno
)); return err
; }
1752 // Receive interface identifiers
1753 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1754 if (err
< 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
)); return err
; }
1756 mDNSPlatformMemZero(&addr
, sizeof(addr
));
1757 socklen_t len
= sizeof(addr
);
1758 err
= getsockname(skt
, (struct sockaddr
*) &addr
, &len
);
1759 if (err
< 0) { LogMsg("getsockname - %s", strerror(errno
)); return err
; }
1761 port
->NotAnInteger
= addr
.sin_port
;
1766 struct sockaddr_in6 addr6
;
1767 mDNSPlatformMemZero(&addr6
, sizeof(addr6
));
1768 addr6
.sin6_family
= AF_INET6
;
1769 addr6
.sin6_port
= port
->NotAnInteger
;
1770 err
= bind(skt
, (struct sockaddr
*) &addr6
, sizeof(addr6
));
1771 if (err
< 0) { LogMsg("ERROR: bind6 %s", strerror(errno
)); return err
; }
1773 // We want to receive destination addresses and receive interface identifiers
1774 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
1775 if (err
< 0) { LogMsg("ERROR: setsockopt IPV6_PKTINFO %s", strerror(errno
)); return err
; }
1777 mDNSPlatformMemZero(&addr6
, sizeof(addr6
));
1778 socklen_t len
= sizeof(addr6
);
1779 err
= getsockname(skt
, (struct sockaddr
*) &addr6
, &len
);
1780 if (err
< 0) { LogMsg("getsockname6 - %s", strerror(errno
)); return err
; }
1782 port
->NotAnInteger
= addr6
.sin6_port
;
1786 k
->KQcallback
= tcpKQSocketCallback
;
1787 k
->KQcontext
= sock
;
1788 k
->KQtask
= "mDNSPlatformTCPSocket";
1789 #ifdef __LIB_DISPATCH__
1790 k
->readSource
= mDNSNULL
;
1791 k
->writeSource
= mDNSNULL
;
1792 k
->fdClosed
= mDNSfalse
;
1794 return mStatus_NoError
;
1797 mDNSexport TCPSocket
*mDNSPlatformTCPSocket(mDNS
*const m
, TCPSocketFlags flags
, mDNSIPPort
*port
)
1802 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket
));
1803 if (!sock
) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL
); }
1805 mDNSPlatformMemZero(sock
, sizeof(TCPSocket
));
1808 sock
->ss
.sktv4
= -1;
1810 sock
->ss
.sktv6
= -1;
1812 err
= SetupTCPSocket(sock
, AF_INET
, port
);
1816 err
= SetupTCPSocket(sock
, AF_INET6
, port
);
1817 if (err
) { mDNSPlatformCloseFD(&sock
->ss
.kqsv4
, sock
->ss
.sktv4
); sock
->ss
.sktv4
= -1; }
1822 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock
->fd
, errno
, strerror(errno
));
1823 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1827 sock
->callback
= mDNSNULL
;
1828 sock
->flags
= flags
;
1829 sock
->context
= mDNSNULL
;
1830 sock
->setup
= mDNSfalse
;
1831 sock
->connected
= mDNSfalse
;
1832 sock
->handshake
= handshake_required
;
1834 sock
->err
= mStatus_NoError
;
1839 mDNSexport mStatus
mDNSPlatformTCPConnect(TCPSocket
*sock
, const mDNSAddr
*dst
, mDNSOpaque16 dstport
, domainname
*hostname
, mDNSInterfaceID InterfaceID
, TCPConnectionCallback callback
, void *context
)
1841 KQSocketSet
*cp
= &sock
->ss
;
1843 int *s
= (dst
->type
== mDNSAddrType_IPv4
) ? &cp
->sktv4
: &cp
->sktv6
;
1844 KQueueEntry
*k
= (dst
->type
== mDNSAddrType_IPv4
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1846 int *s
= &cp
->sktv4
;
1847 KQueueEntry
*k
= &cp
->kqsv4
;
1849 mStatus err
= mStatus_NoError
;
1850 struct sockaddr_storage ss
;
1852 sock
->callback
= callback
;
1853 sock
->context
= context
;
1854 sock
->setup
= mDNSfalse
;
1855 sock
->connected
= mDNSfalse
;
1856 sock
->handshake
= handshake_required
;
1857 sock
->err
= mStatus_NoError
;
1859 if (hostname
) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname
->c
); AssignDomainName(&sock
->hostname
, hostname
); }
1861 if (dst
->type
== mDNSAddrType_IPv4
)
1863 struct sockaddr_in
*saddr
= (struct sockaddr_in
*)&ss
;
1864 mDNSPlatformMemZero(saddr
, sizeof(*saddr
));
1865 saddr
->sin_family
= AF_INET
;
1866 saddr
->sin_port
= dstport
.NotAnInteger
;
1867 saddr
->sin_len
= sizeof(*saddr
);
1868 saddr
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1872 struct sockaddr_in6
*saddr6
= (struct sockaddr_in6
*)&ss
;
1873 mDNSPlatformMemZero(saddr6
, sizeof(*saddr6
));
1874 saddr6
->sin6_family
= AF_INET6
;
1875 saddr6
->sin6_port
= dstport
.NotAnInteger
;
1876 saddr6
->sin6_len
= sizeof(*saddr6
);
1877 saddr6
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1880 // Watch for connect complete (write is ready)
1881 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1882 if (KQueueSet(*s
, EV_ADD
/* | EV_ONESHOT */, EVFILT_WRITE
, k
))
1884 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1888 // Watch for incoming data
1889 if (KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
))
1891 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1895 if (fcntl(*s
, F_SETFL
, fcntl(*s
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
1897 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1898 return mStatus_UnknownErr
;
1901 // We bind to the interface and all subsequent packets including the SYN will be sent out
1902 // on this interface
1904 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
1905 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
1906 if (InterfaceID
&& InterfaceID
!= mDNSInterface_Unicast
)
1908 extern mDNS mDNSStorage
;
1909 NetworkInterfaceInfoOSX
*info
= IfindexToInterfaceInfoOSX(&mDNSStorage
, InterfaceID
);
1910 if (dst
->type
== mDNSAddrType_IPv4
)
1913 if (info
) setsockopt(*s
, IPPROTO_IP
, IP_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1914 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID
); return mStatus_BadParamErr
; }
1916 (void)InterfaceID
; // Unused
1917 (void)info
; // Unused
1922 #ifdef IPV6_BOUND_IF
1923 if (info
) setsockopt(*s
, IPPROTO_IPV6
, IPV6_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1924 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID
); return mStatus_BadParamErr
; }
1926 (void)InterfaceID
; // Unused
1927 (void)info
; // Unused
1932 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
1933 // from which we can infer the destination address family. Hence we need to remember that here.
1934 // Instead of remembering the address family, we remember the right fd.
1937 // initiate connection wth peer
1938 if (connect(*s
, (struct sockaddr
*)&ss
, ss
.ss_len
) < 0)
1940 if (errno
== EINPROGRESS
) return mStatus_ConnPending
;
1941 if (errno
== EHOSTUNREACH
|| errno
== EADDRNOTAVAIL
|| errno
== ENETDOWN
)
1942 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock
->fd
, errno
, strerror(errno
));
1944 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock
->fd
, errno
, strerror(errno
), ss
.ss_len
);
1945 return mStatus_ConnFailed
;
1948 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1949 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1953 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1954 mDNSexport TCPSocket
*mDNSPlatformTCPAccept(TCPSocketFlags flags
, int fd
)
1956 mStatus err
= mStatus_NoError
;
1958 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket
));
1959 if (!sock
) return(mDNSNULL
);
1961 mDNSPlatformMemZero(sock
, sizeof(*sock
));
1963 sock
->flags
= flags
;
1965 if (flags
& kTCPSocketFlags_UseTLS
)
1967 #ifndef NO_SECURITYFRAMEWORK
1968 if (!ServerCerts
) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err
= mStatus_UnknownErr
; goto exit
; }
1970 err
= tlsSetupSock(sock
, mDNStrue
);
1971 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err
); goto exit
; }
1973 err
= SSLSetCertificate(sock
->tlsContext
, ServerCerts
);
1974 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err
); goto exit
; }
1976 err
= mStatus_UnsupportedErr
;
1977 #endif /* NO_SECURITYFRAMEWORK */
1979 #ifndef NO_SECURITYFRAMEWORK
1983 if (err
) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock
); return(mDNSNULL
); }
1987 mDNSlocal
void CloseSocketSet(KQSocketSet
*ss
)
1989 if (ss
->sktv4
!= -1)
1991 mDNSPlatformCloseFD(&ss
->kqsv4
, ss
->sktv4
);
1995 if (ss
->sktv6
!= -1)
1997 mDNSPlatformCloseFD(&ss
->kqsv6
, ss
->sktv6
);
2001 if (ss
->closeFlag
) *ss
->closeFlag
= 1;
2004 mDNSexport
void mDNSPlatformTCPCloseConnection(TCPSocket
*sock
)
2008 #ifndef NO_SECURITYFRAMEWORK
2009 if (sock
->tlsContext
)
2011 if (sock
->handshake
== handshake_in_progress
) // SSLHandshake thread using this sock (esp. tlsContext)
2013 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
2014 sock
->handshake
= handshake_to_be_closed
;
2016 if (sock
->handshake
== handshake_to_be_closed
)
2019 SSLClose(sock
->tlsContext
);
2020 SSLDisposeContext(sock
->tlsContext
);
2021 sock
->tlsContext
= NULL
;
2023 #endif /* NO_SECURITYFRAMEWORK */
2024 if (sock
->ss
.sktv4
!= -1) shutdown(sock
->ss
.sktv4
, 2);
2026 if (sock
->ss
.sktv6
!= -1) shutdown(sock
->ss
.sktv6
, 2);
2028 CloseSocketSet(&sock
->ss
);
2031 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock
);
2035 mDNSexport
long mDNSPlatformReadTCP(TCPSocket
*sock
, void *buf
, unsigned long buflen
, mDNSBool
*closed
)
2038 *closed
= mDNSfalse
;
2040 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
2042 #ifndef NO_SECURITYFRAMEWORK
2043 if (sock
->handshake
== handshake_required
) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
2044 else if (sock
->handshake
== handshake_in_progress
) return 0;
2045 else if (sock
->handshake
!= handshake_completed
) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock
->handshake
);
2047 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
2048 mStatus err
= SSLRead(sock
->tlsContext
, buf
, buflen
, &nread
);
2049 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
2050 if (err
== errSSLClosedGraceful
) { nread
= 0; *closed
= mDNStrue
; }
2051 else if (err
&& err
!= errSSLWouldBlock
)
2052 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err
); nread
= -1; *closed
= mDNStrue
; }
2056 #endif /* NO_SECURITYFRAMEWORK */
2060 static int CLOSEDcount
= 0;
2061 static int EAGAINcount
= 0;
2062 nread
= recv(sock
->fd
, buf
, buflen
, 0);
2064 if (nread
> 0) { CLOSEDcount
= 0; EAGAINcount
= 0; } // On success, clear our error counters
2065 else if (nread
== 0)
2068 if ((++CLOSEDcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock
->fd
, CLOSEDcount
); sleep(1); }
2070 // else nread is negative -- see what kind of error we got
2071 else if (errno
== ECONNRESET
) { nread
= 0; *closed
= mDNStrue
; }
2072 else if (errno
!= EAGAIN
) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno
, strerror(errno
)); nread
= -1; }
2073 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
2076 if ((++EAGAINcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock
->fd
, EAGAINcount
); sleep(1); }
2083 mDNSexport
long mDNSPlatformWriteTCP(TCPSocket
*sock
, const char *msg
, unsigned long len
)
2087 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
2089 #ifndef NO_SECURITYFRAMEWORK
2091 if (sock
->handshake
== handshake_required
) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
2092 if (sock
->handshake
== handshake_in_progress
) return 0;
2093 else if (sock
->handshake
!= handshake_completed
) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock
->handshake
);
2095 mStatus err
= SSLWrite(sock
->tlsContext
, msg
, len
, &processed
);
2097 if (!err
) nsent
= (int) processed
;
2098 else if (err
== errSSLWouldBlock
) nsent
= 0;
2099 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err
); nsent
= -1; }
2102 #endif /* NO_SECURITYFRAMEWORK */
2106 nsent
= send(sock
->fd
, msg
, len
, 0);
2109 if (errno
== EAGAIN
) nsent
= 0;
2110 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno
)); nsent
= -1; }
2117 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
2122 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
2123 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
2124 mDNSlocal mStatus
SetupSocket(KQSocketSet
*cp
, const mDNSIPPort port
, u_short sa_family
, mDNSIPPort
*const outport
)
2127 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
2128 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
2130 int *s
= &cp
->sktv4
;
2131 KQueueEntry
*k
= &cp
->kqsv4
;
2134 const int twofivefive
= 255;
2135 mStatus err
= mStatus_NoError
;
2136 char *errstr
= mDNSNULL
;
2139 if (sa_family
!= AF_INET
) return -1;
2142 cp
->closeFlag
= mDNSNULL
;
2144 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
2145 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
2147 // ... with a shared UDP port, if it's for multicast receiving
2148 if (mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSSameIPPort(port
, NATPMPAnnouncementPort
)) err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
2149 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
2151 if (sa_family
== AF_INET
)
2153 // We want to receive destination addresses
2154 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
2155 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
2157 // We want to receive interface identifiers
2158 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
2159 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
2161 // We want to receive packet TTL value so we can check it
2162 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
2163 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
2165 // Send unicast packets with TTL 255
2166 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
2167 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
2169 // And multicast packets with TTL 255 too
2170 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
2171 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
2173 // And start listening for packets
2174 struct sockaddr_in listening_sockaddr
;
2175 listening_sockaddr
.sin_family
= AF_INET
;
2176 listening_sockaddr
.sin_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
2177 listening_sockaddr
.sin_addr
.s_addr
= mDNSSameIPPort(port
, NATPMPAnnouncementPort
) ? AllHosts_v4
.NotAnInteger
: 0;
2178 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
2179 if (err
) { errstr
= "bind"; goto fail
; }
2180 if (outport
) outport
->NotAnInteger
= listening_sockaddr
.sin_port
;
2183 else if (sa_family
== AF_INET6
)
2185 // NAT-PMP Announcements make no sense on IPv6, so bail early w/o error
2186 if (mDNSSameIPPort(port
, NATPMPAnnouncementPort
)) { if (outport
) *outport
= zeroIPPort
; return mStatus_NoError
; }
2188 // We want to receive destination addresses and receive interface identifiers
2189 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
2190 if (err
< 0) { errstr
= "setsockopt - IPV6_PKTINFO"; goto fail
; }
2192 // We want to receive packet hop count value so we can check it
2193 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
2194 if (err
< 0) { errstr
= "setsockopt - IPV6_HOPLIMIT"; goto fail
; }
2196 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
2197 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
2198 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
2199 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
2201 // Send unicast packets with TTL 255
2202 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
2203 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
2205 // And multicast packets with TTL 255 too
2206 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
2207 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
2209 // Want to receive our own packets
2210 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
2211 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
2213 // And start listening for packets
2214 struct sockaddr_in6 listening_sockaddr6
;
2215 mDNSPlatformMemZero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
2216 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
2217 listening_sockaddr6
.sin6_family
= AF_INET6
;
2218 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
2219 listening_sockaddr6
.sin6_flowinfo
= 0;
2220 listening_sockaddr6
.sin6_addr
= in6addr_any
; // Want to receive multicasts AND unicasts on this socket
2221 listening_sockaddr6
.sin6_scope_id
= 0;
2222 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
2223 if (err
) { errstr
= "bind"; goto fail
; }
2224 if (outport
) outport
->NotAnInteger
= listening_sockaddr6
.sin6_port
;
2228 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
2229 fcntl(skt
, F_SETFD
, 1); // set close-on-exec
2231 k
->KQcallback
= myKQSocketCallBack
;
2233 k
->KQtask
= "UDP packet reception";
2234 #ifdef __LIB_DISPATCH__
2235 k
->readSource
= mDNSNULL
;
2236 k
->writeSource
= mDNSNULL
;
2237 k
->fdClosed
= mDNSfalse
;
2239 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
2244 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
2245 if (strcmp(errstr
, "bind") || mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSIPPortIsZero(port
))
2246 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr
, skt
, mDNSVal16(port
), err
, errno
, strerror(errno
));
2248 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
2249 if (!strcmp(errstr
, "bind") && errno
== EADDRINUSE
)
2252 if (mDNSSameIPPort(port
, MulticastDNSPort
))
2253 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
2254 "Congratulations, you've reproduced an elusive bug.\r"
2255 "Please contact the current assignee of <rdar://problem/3814904>.\r"
2256 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2257 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2260 mDNSPlatformCloseFD(k
, skt
);
2264 mDNSexport UDPSocket
*mDNSPlatformUDPSocket(mDNS
*const m
, const mDNSIPPort requestedport
)
2267 mDNSIPPort port
= requestedport
;
2268 mDNSBool randomizePort
= mDNSIPPortIsZero(requestedport
);
2269 int i
= 10000; // Try at most 10000 times to get a unique random port
2270 UDPSocket
*p
= mallocL("UDPSocket", sizeof(UDPSocket
));
2271 if (!p
) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL
); }
2272 mDNSPlatformMemZero(p
, sizeof(UDPSocket
));
2273 p
->ss
.port
= zeroIPPort
;
2282 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
2283 if (randomizePort
) port
= mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
2284 err
= SetupSocket(&p
->ss
, port
, AF_INET
, &p
->ss
.port
);
2288 err
= SetupSocket(&p
->ss
, port
, AF_INET6
, &p
->ss
.port
);
2289 if (err
) { mDNSPlatformCloseFD(&p
->ss
.kqsv4
, p
->ss
.sktv4
); p
->ss
.sktv4
= -1; }
2293 } while (err
== EADDRINUSE
&& randomizePort
&& i
);
2297 // In customer builds we don't want to log failures with port 5351, because this is a known issue
2298 // of failing to bind to this port when Internet Sharing has already bound to it
2299 // We also don't want to log about port 5350, due to a known bug when some other
2300 // process is bound to it.
2301 if (mDNSSameIPPort(requestedport
, NATPMPPort
) || mDNSSameIPPort(requestedport
, NATPMPAnnouncementPort
))
2302 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
2303 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
2304 freeL("UDPSocket", p
);
2310 mDNSexport
void mDNSPlatformUDPClose(UDPSocket
*sock
)
2312 CloseSocketSet(&sock
->ss
);
2313 freeL("UDPSocket", sock
);
2316 #if COMPILER_LIKES_PRAGMA_MARK
2318 #pragma mark - BPF Raw packet sending/receiving
2321 #if APPLE_OSX_mDNSResponder
2323 mDNSexport
void mDNSPlatformSendRawPacket(const void *const msg
, const mDNSu8
*const end
, mDNSInterfaceID InterfaceID
)
2325 if (!InterfaceID
) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2326 NetworkInterfaceInfoOSX
*info
;
2328 extern mDNS mDNSStorage
;
2329 info
= IfindexToInterfaceInfoOSX(&mDNSStorage
, InterfaceID
);
2332 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID
);
2335 if (info
->BPF_fd
< 0)
2336 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info
->ifinfo
.ifname
, info
->BPF_fd
);
2339 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
2340 if (write(info
->BPF_fd
, msg
, end
- (mDNSu8
*)msg
) < 0)
2341 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info
->BPF_fd
, errno
, strerror(errno
));
2345 mDNSexport
void mDNSPlatformSetLocalAddressCacheEntry(mDNS
*const m
, const mDNSAddr
*const tpa
, const mDNSEthAddr
*const tha
, mDNSInterfaceID InterfaceID
)
2347 if (!InterfaceID
) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
2348 NetworkInterfaceInfoOSX
*info
;
2349 info
= IfindexToInterfaceInfoOSX(m
, InterfaceID
);
2350 if (info
== NULL
) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID
); return; }
2351 // Manually inject an entry into our local ARP cache.
2352 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
2353 if (!mDNS_AddressIsLocalSubnet(m
, InterfaceID
, tpa
))
2354 LogSPS("Don't need address cache entry for %s %#a %.6a", info
->ifinfo
.ifname
, tpa
, tha
);
2357 int result
= mDNSSetLocalAddressCacheEntry(info
->scope_id
, tpa
->type
, tpa
->ip
.v6
.b
, tha
->b
);
2358 if (result
) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info
->ifinfo
.ifname
, tpa
, tha
, result
);
2359 else LogSPS("Set local address cache entry for %s %#a %.6a", info
->ifinfo
.ifname
, tpa
, tha
);
2363 mDNSlocal
void CloseBPF(NetworkInterfaceInfoOSX
*const i
)
2365 LogSPS("%s closing BPF fd %d", i
->ifinfo
.ifname
, i
->BPF_fd
);
2366 #ifdef __LIB_DISPATCH__
2367 // close will happen in the cancel handler
2368 dispatch_source_cancel(i
->BPF_source
);
2371 // Note: MUST NOT close() the underlying native BSD sockets.
2372 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
2373 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
2374 CFRunLoopRemoveSource(i
->m
->p
->CFRunLoop
, i
->BPF_rls
, kCFRunLoopDefaultMode
);
2375 CFRelease(i
->BPF_rls
);
2376 CFSocketInvalidate(i
->BPF_cfs
);
2377 CFRelease(i
->BPF_cfs
);
2380 if (i
->BPF_mcfd
>= 0) { close(i
->BPF_mcfd
); i
->BPF_mcfd
= -1; }
2383 mDNSlocal
void bpf_callback_common(NetworkInterfaceInfoOSX
*info
)
2385 KQueueLock(info
->m
);
2387 // 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
2388 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
2389 if (info
->BPF_fd
< 0) goto exit
;
2391 ssize_t n
= read(info
->BPF_fd
, &info
->m
->imsg
, info
->BPF_len
);
2392 const mDNSu8
*ptr
= (const mDNSu8
*)&info
->m
->imsg
;
2393 const mDNSu8
*end
= (const mDNSu8
*)&info
->m
->imsg
+ n
;
2394 debugf("%3d: bpf_callback got %d bytes on %s", info
->BPF_fd
, n
, info
->ifinfo
.ifname
);
2398 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info
->ifinfo
.ifname
, info
->BPF_fd
, errno
, strerror(errno
));
2405 const struct bpf_hdr
*const bh
= (const struct bpf_hdr
*)ptr
;
2406 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
2407 info
->BPF_fd
, ptr
, bh
->bh_hdrlen
, ptr
+ bh
->bh_hdrlen
, bh
->bh_caplen
, bh
->bh_datalen
,
2408 ptr
+ BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
), end
- (ptr
+ BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
)));
2409 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
2410 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
2411 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
2412 mDNSCoreReceiveRawPacket(info
->m
, ptr
+ bh
->bh_hdrlen
, ptr
+ bh
->bh_hdrlen
+ bh
->bh_caplen
, info
->ifinfo
.InterfaceID
);
2413 ptr
+= BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
);
2416 KQueueUnlock(info
->m
, "bpf_callback");
2418 #ifdef __LIB_DISPATCH__
2419 mDNSlocal
void bpf_callback_dispatch(NetworkInterfaceInfoOSX
*const info
)
2421 bpf_callback_common(info
);
2424 mDNSlocal
void bpf_callback(const CFSocketRef cfs
, const CFSocketCallBackType CallBackType
, const CFDataRef address
, const void *const data
, void *const context
)
2430 bpf_callback_common((NetworkInterfaceInfoOSX
*)context
);
2434 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2436 mDNSlocal
int CountProxyTargets(mDNS
*const m
, NetworkInterfaceInfoOSX
*x
, int *p4
, int *p6
)
2438 int numv4
= 0, numv6
= 0;
2441 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2442 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2444 if (p4
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv4
, &rr
->AddressProxy
.ip
.v4
);
2448 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2449 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
2451 if (p6
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv6
, &rr
->AddressProxy
.ip
.v6
);
2455 if (p4
) *p4
= numv4
;
2456 if (p6
) *p6
= numv6
;
2457 return(numv4
+ numv6
);
2460 mDNSexport
void mDNSPlatformUpdateProxyList(mDNS
*const m
, const mDNSInterfaceID InterfaceID
)
2462 NetworkInterfaceInfoOSX
*x
;
2464 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
2465 for (x
= m
->p
->InterfaceList
; x
; x
= x
->next
) if (x
->ifinfo
.InterfaceID
== InterfaceID
) break;
2467 if (!x
) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID
); return; }
2469 #define MAX_BPF_ADDRS 250
2470 int numv4
= 0, numv6
= 0;
2472 if (CountProxyTargets(m
, x
, &numv4
, &numv6
) > MAX_BPF_ADDRS
)
2474 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4
, numv6
);
2475 if (numv4
> MAX_BPF_ADDRS
) numv4
= MAX_BPF_ADDRS
;
2476 numv6
= MAX_BPF_ADDRS
- numv4
;
2479 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x
->BPF_fd
, x
->ifinfo
.ifname
, &x
->ifinfo
.MAC
, numv4
, numv6
);
2481 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
2482 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
2483 static struct bpf_insn filter
[17 + MAX_BPF_ADDRS
] =
2485 BPF_STMT(BPF_LD
+ BPF_H
+ BPF_ABS
, 12), // 0 Read Ethertype (bytes 12,13)
2487 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
2488 BPF_STMT(BPF_RET
+ BPF_K
, 42), // 2 Return 42-byte ARP
2490 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
2492 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
2493 BPF_STMT(BPF_LD
+ BPF_H
+ BPF_ABS
, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
2494 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
2495 BPF_STMT(BPF_RET
+ BPF_K
, 86), // 7 Return 86-byte ND
2497 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
2498 BPF_STMT(BPF_LD
+ BPF_W
+ BPF_ABS
, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
2501 struct bpf_insn
*pc
= &filter
[9];
2502 struct bpf_insn
*chk6
= pc
+ numv4
+ 1; // numv4 address checks, plus a "return 0"
2503 struct bpf_insn
*fail
= chk6
+ 1 + numv6
; // Get v6 Dst LSW, plus numv6 address checks
2504 struct bpf_insn
*ret4
= fail
+ 1;
2505 struct bpf_insn
*ret6
= ret4
+ 4;
2507 static const struct bpf_insn rf
= BPF_STMT(BPF_RET
+ BPF_K
, 0); // No match: Return nothing
2509 static const struct bpf_insn g6
= BPF_STMT(BPF_LD
+ BPF_W
+ BPF_ABS
, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
2511 static const struct bpf_insn r4a
= BPF_STMT(BPF_LDX
+ BPF_B
+ BPF_MSH
, 14); // Get IP Header length (normally 20)
2512 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)
2513 static const struct bpf_insn r4c
= BPF_STMT(BPF_ALU
+ BPF_ADD
+ BPF_X
, 0); // A += IP Header length
2514 static const struct bpf_insn r4d
= BPF_STMT(BPF_RET
+ BPF_A
, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
2516 static const struct bpf_insn r6a
= BPF_STMT(BPF_RET
+ BPF_K
, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
2518 BPF_SetOffset(&filter
[4], jf
, fail
); // If Ethertype not ARP, IPv4, or IPv6, fail
2519 BPF_SetOffset(&filter
[6], jf
, chk6
); // If IPv6 but not ICMPv6, go to IPv6 address list check
2521 // BPF Byte-Order Note
2522 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
2523 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
2524 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
2525 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
2526 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
2527 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
2528 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
2529 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
2530 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
2531 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
2533 // IPSEC capture size notes:
2534 // 8 bytes UDP header
2535 // 4 bytes Non-ESP Marker
2536 // 28 bytes IKE Header
2538 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
2541 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2542 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2544 mDNSv4Addr a
= rr
->AddressProxy
.ip
.v4
;
2545 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
2546 BPF_SetOffset(pc
, jt
, ret4
);
2548 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];
2553 if (pc
!= chk6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc
, chk6
);
2554 *pc
++ = g6
; // chk6 points here
2556 // First cancel any previous ND group memberships we had, then create a fresh socket
2557 if (x
->BPF_mcfd
>= 0) close(x
->BPF_mcfd
);
2558 x
->BPF_mcfd
= socket(AF_INET6
, SOCK_DGRAM
, 0);
2560 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2561 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
2563 const mDNSv6Addr
*const a
= &rr
->AddressProxy
.ip
.v6
;
2564 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
2565 BPF_SetOffset(pc
, jt
, ret6
);
2567 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];
2570 struct ipv6_mreq i6mr
;
2571 i6mr
.ipv6mr_interface
= x
->scope_id
;
2572 i6mr
.ipv6mr_multiaddr
= *(const struct in6_addr
*)&NDP_prefix
;
2573 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xD] = a
->b
[0xD];
2574 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xE] = a
->b
[0xE];
2575 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xF] = a
->b
[0xF];
2577 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
2578 mStatus err
= setsockopt(x
->BPF_mcfd
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
2579 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
2580 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2582 err
= setsockopt(x
->BPF_mcfd
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
2583 if (err
< 0 && (errno
!= EADDRINUSE
)) // Joining same group twice can give "Address already in use" error -- no need to report that
2584 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2586 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr
.ipv6mr_multiaddr
, a
);
2589 if (pc
!= fail
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc
, fail
);
2590 *pc
++ = rf
; // fail points here
2592 if (pc
!= ret4
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc
, ret4
);
2593 *pc
++ = r4a
; // ret4 points here
2598 if (pc
!= ret6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc
, ret6
);
2599 *pc
++ = r6a
; // ret6 points here
2601 struct bpf_program prog
= { pc
- filter
, filter
};
2604 // For debugging BPF filter program
2606 for (q
=0; q
<prog
.bf_len
; q
++)
2607 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
);
2610 if (!numv4
&& !numv6
)
2612 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
2613 if (m
->timenow
== 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
2614 // Schedule check to see if we can close this BPF_fd now
2615 if (!m
->p
->NetworkChanged
) m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2);
2616 // prog.bf_len = 0; This seems to panic the kernel
2617 if (x
->BPF_fd
< 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
2620 if (ioctl(x
->BPF_fd
, BIOCSETF
, &prog
) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETF(%d) failed %d (%s)", prog
.bf_len
, errno
, strerror(errno
));
2621 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETF(%d) successful", prog
.bf_len
);
2624 mDNSexport
void mDNSPlatformReceiveBPF_fd(mDNS
*const m
, int fd
)
2628 NetworkInterfaceInfoOSX
*i
;
2629 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
) if (i
->BPF_fd
== -2) break;
2630 if (!i
) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd
); close(fd
); }
2633 LogSPS("%s using BPF fd %d", i
->ifinfo
.ifname
, fd
);
2635 struct bpf_version v
;
2636 if (ioctl(fd
, BIOCVERSION
, &v
) < 0)
2637 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2638 else if (BPF_MAJOR_VERSION
!= v
.bv_major
|| BPF_MINOR_VERSION
!= v
.bv_minor
)
2639 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
2640 fd
, i
->ifinfo
.ifname
, BPF_MAJOR_VERSION
, BPF_MINOR_VERSION
, v
.bv_major
, v
.bv_minor
);
2642 if (ioctl(fd
, BIOCGBLEN
, &i
->BPF_len
) < 0)
2643 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2645 if (i
->BPF_len
> sizeof(m
->imsg
))
2647 i
->BPF_len
= sizeof(m
->imsg
);
2648 if (ioctl(fd
, BIOCSBLEN
, &i
->BPF_len
) < 0)
2649 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2650 else LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", i
->BPF_len
);
2653 static const u_int opt_one
= 1;
2654 if (ioctl(fd
, BIOCIMMEDIATE
, &opt_one
) < 0)
2655 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2657 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
2658 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2660 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
2661 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2664 mDNSPlatformMemZero(&ifr
, sizeof(ifr
));
2665 strlcpy(ifr
.ifr_name
, i
->ifinfo
.ifname
, sizeof(ifr
.ifr_name
));
2666 if (ioctl(fd
, BIOCSETIF
, &ifr
) < 0)
2667 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
)); i
->BPF_fd
= -3; }
2670 #ifdef __LIB_DISPATCH__
2672 i
->BPF_source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, fd
, 0, dispatch_get_main_queue());
2673 if (!i
->BPF_source
) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed");return;}
2674 dispatch_source_set_event_handler(i
->BPF_source
, ^{bpf_callback_dispatch(i
);});
2675 dispatch_source_set_cancel_handler(i
->BPF_source
, ^{close(fd
);});
2676 dispatch_resume(i
->BPF_source
);
2678 CFSocketContext myCFSocketContext
= { 0, i
, NULL
, NULL
, NULL
};
2680 i
->BPF_cfs
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
, bpf_callback
, &myCFSocketContext
);
2681 i
->BPF_rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, i
->BPF_cfs
, 0);
2682 CFRunLoopAddSource(i
->m
->p
->CFRunLoop
, i
->BPF_rls
, kCFRunLoopDefaultMode
);
2684 mDNSPlatformUpdateProxyList(m
, i
->ifinfo
.InterfaceID
);
2691 #endif // APPLE_OSX_mDNSResponder
2693 #if COMPILER_LIKES_PRAGMA_MARK
2695 #pragma mark - Key Management
2698 #ifndef NO_SECURITYFRAMEWORK
2699 mDNSlocal CFArrayRef
GetCertChain(SecIdentityRef identity
)
2701 CFMutableArrayRef certChain
= NULL
;
2702 if (!identity
) { LogMsg("getCertChain: identity is NULL"); return(NULL
); }
2703 SecCertificateRef cert
;
2704 OSStatus err
= SecIdentityCopyCertificate(identity
, &cert
);
2705 if (err
|| !cert
) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err
);
2708 SecPolicySearchRef searchRef
;
2709 err
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, &CSSMOID_APPLE_X509_BASIC
, NULL
, &searchRef
);
2710 if (err
|| !searchRef
) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err
);
2713 SecPolicyRef policy
;
2714 err
= SecPolicySearchCopyNext(searchRef
, &policy
);
2715 if (err
|| !policy
) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err
);
2718 CFArrayRef wrappedCert
= CFArrayCreate(NULL
, (const void**) &cert
, 1, &kCFTypeArrayCallBacks
);
2719 if (!wrappedCert
) LogMsg("getCertChain: wrappedCert is NULL");
2723 err
= SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
);
2724 if (err
|| !trust
) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err
);
2727 err
= SecTrustEvaluate(trust
, NULL
);
2728 if (err
) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err
);
2731 CFArrayRef rawCertChain
;
2732 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
2733 err
= SecTrustGetResult(trust
, NULL
, &rawCertChain
, &statusChain
);
2734 if (err
|| !rawCertChain
|| !statusChain
) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err
);
2737 certChain
= CFArrayCreateMutableCopy(NULL
, 0, rawCertChain
);
2738 if (!certChain
) LogMsg("getCertChain: certChain is NULL");
2741 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
2742 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
2743 CFArraySetValueAtIndex(certChain
, 0, identity
);
2744 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
2745 if (CFArrayGetCount(certChain
) > 1) CFArrayRemoveValueAtIndex(certChain
, CFArrayGetCount(certChain
) - 1);
2747 CFRelease(rawCertChain
);
2748 // Do not free statusChain:
2749 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
2750 // certChain: Call the CFRelease function to release this object when you are finished with it.
2751 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
2756 CFRelease(wrappedCert
);
2760 CFRelease(searchRef
);
2766 #endif /* NO_SECURITYFRAMEWORK */
2768 mDNSexport mStatus
mDNSPlatformTLSSetupCerts(void)
2770 #ifdef NO_SECURITYFRAMEWORK
2771 return mStatus_UnsupportedErr
;
2773 SecIdentityRef identity
= nil
;
2774 SecIdentitySearchRef srchRef
= nil
;
2777 // search for "any" identity matching specified key use
2778 // In this app, we expect there to be exactly one
2779 err
= SecIdentitySearchCreate(NULL
, CSSM_KEYUSE_DECRYPT
, &srchRef
);
2780 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err
); return err
; }
2782 err
= SecIdentitySearchCopyNext(srchRef
, &identity
);
2783 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err
); return err
; }
2785 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
2786 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr
; }
2788 // Found one. Call getCertChain to create the correct certificate chain.
2789 ServerCerts
= GetCertChain(identity
);
2790 if (ServerCerts
== nil
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr
; }
2792 return mStatus_NoError
;
2793 #endif /* NO_SECURITYFRAMEWORK */
2796 mDNSexport
void mDNSPlatformTLSTearDownCerts(void)
2798 #ifndef NO_SECURITYFRAMEWORK
2799 if (ServerCerts
) { CFRelease(ServerCerts
); ServerCerts
= NULL
; }
2800 #endif /* NO_SECURITYFRAMEWORK */
2803 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
2804 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
2806 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
2807 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
2810 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
2815 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
2816 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
2818 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
2821 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
2826 mDNSexport mDNSBool
DictionaryIsEnabled(CFDictionaryRef dict
)
2829 CFNumberRef state
= (CFNumberRef
)CFDictionaryGetValue(dict
, CFSTR("Enabled"));
2830 if (!state
) return mDNSfalse
;
2831 if (!CFNumberGetValue(state
, kCFNumberSInt32Type
, &val
))
2832 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse
; }
2833 return val
? mDNStrue
: mDNSfalse
;
2836 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
2838 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
2840 if (sa
->sa_family
== AF_INET
)
2842 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
2843 ip
->type
= mDNSAddrType_IPv4
;
2844 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
2845 return(mStatus_NoError
);
2848 if (sa
->sa_family
== AF_INET6
)
2850 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
2851 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
2852 // value into the second word of the IPv6 link-local address, so they can just
2853 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
2854 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
2855 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
2856 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
2857 ip
->type
= mDNSAddrType_IPv6
;
2858 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
2859 return(mStatus_NoError
);
2862 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
2863 return(mStatus_Invalid
);
2866 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
2868 mDNSEthAddr eth
= zeroEthAddr
;
2869 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetBSSID"), NULL
, NULL
);
2871 LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
2874 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
2877 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, entityname
);
2880 CFRange range
= { 0, 6 }; // Offset, length
2881 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
2882 if (data
&& CFDataGetLength(data
) == 6) CFDataGetBytes(data
, range
, eth
.b
);
2885 CFRelease(entityname
);
2892 mDNSlocal
int GetMAC(mDNSEthAddr
*eth
, u_short ifindex
)
2894 struct ifaddrs
*ifa
;
2895 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
2896 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2898 const struct sockaddr_dl
*const sdl
= (const struct sockaddr_dl
*)ifa
->ifa_addr
;
2899 if (sdl
->sdl_index
== ifindex
)
2900 { mDNSPlatformMemCopy(eth
->b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6); return 0; }
2906 #ifndef SIOCGIFWAKEFLAGS
2907 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
2910 #ifndef IF_WAKE_ON_MAGIC_PACKET
2911 #define IF_WAKE_ON_MAGIC_PACKET 0x01
2914 #ifndef ifr_wake_flags
2915 #define ifr_wake_flags ifr_ifru.ifru_intval
2918 mDNSlocal mDNSBool
NetWakeInterface(NetworkInterfaceInfoOSX
*i
)
2920 if (!MulticastInterface(i
) ) return(mDNSfalse
); // We only use Sleep Proxy Service on multicast-capable interfaces
2921 if (i
->ifa_flags
& IFF_LOOPBACK
) return(mDNSfalse
); // except loopback
2923 int s
= socket(AF_INET
, SOCK_DGRAM
, 0);
2924 if (s
< 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i
->ifinfo
.ifname
, s
, errno
, strerror(errno
)); return(mDNSfalse
); }
2927 strlcpy(ifr
.ifr_name
, i
->ifinfo
.ifname
, sizeof(ifr
.ifr_name
));
2928 if (ioctl(s
, SIOCGIFWAKEFLAGS
, &ifr
) < 0)
2930 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
2931 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
2932 // error code is being returned from the kernel, we need to use the kernel version.
2933 #define KERNEL_EOPNOTSUPP 102
2934 if (errno
!= KERNEL_EOPNOTSUPP
) // "Operation not supported on socket", the expected result on Leopard and earlier
2935 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i
->ifinfo
.ifname
, errno
, strerror(errno
));
2936 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
2937 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
2938 ifr
.ifr_wake_flags
= (errno
== KERNEL_EOPNOTSUPP
&& !(i
)->BSSID
.l
[0] && i
->m
->SystemWakeOnLANEnabled
) ? IF_WAKE_ON_MAGIC_PACKET
: 0;
2943 // 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
2945 LogSPS("%-6s %#-14a %s WOMP", i
->ifinfo
.ifname
, &i
->ifinfo
.ip
, (ifr
.ifr_wake_flags
& IF_WAKE_ON_MAGIC_PACKET
) ? "supports" : "no");
2947 return((ifr
.ifr_wake_flags
& IF_WAKE_ON_MAGIC_PACKET
) != 0);
2950 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
2951 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
2952 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
2953 // (e.g. sa_family not AF_INET or AF_INET6)
2954 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
, mDNSs32 utc
)
2956 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
2957 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
2960 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
2961 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
2963 NetworkInterfaceInfoOSX
**p
;
2964 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
2965 if (scope_id
== (*p
)->scope_id
&&
2966 mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) &&
2967 mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
2969 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, *p
);
2970 (*p
)->Exists
= mDNStrue
;
2971 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
2972 if ((*p
)->LastSeen
!= utc
) (*p
)->AppearanceTime
= utc
;
2974 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
2975 // we may need to start or stop or sleep proxy browse operation
2976 const mDNSBool NetWake
= NetWakeInterface(*p
);
2977 if ((*p
)->ifinfo
.NetWake
!= NetWake
)
2979 (*p
)->ifinfo
.NetWake
= NetWake
;
2980 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
2981 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
2982 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
2983 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
2984 if ((*p
)->Registered
)
2987 if (NetWake
) mDNS_ActivateNetWake_internal (m
, &(*p
)->ifinfo
);
2988 else mDNS_DeactivateNetWake_internal(m
, &(*p
)->ifinfo
);
2996 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
2997 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
2998 if (!i
) return(mDNSNULL
);
2999 mDNSPlatformMemZero(i
, sizeof(NetworkInterfaceInfoOSX
));
3000 i
->ifinfo
.InterfaceID
= (mDNSInterfaceID
)(uintptr_t)scope_id
;
3002 i
->ifinfo
.mask
= mask
;
3003 strlcpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
3004 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
3005 // We can be configured to disable multicast advertisement, but we want to to support
3006 // local-only services, which need a loopback address record.
3007 i
->ifinfo
.Advertise
= m
->DivertMulticastAdvertisements
? ((ifa
->ifa_flags
& IFF_LOOPBACK
) ? mDNStrue
: mDNSfalse
) : m
->AdvertiseLocalAddresses
;
3008 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
3012 i
->Exists
= mDNStrue
;
3013 i
->Flashing
= mDNSfalse
;
3014 i
->Occulting
= mDNSfalse
;
3015 i
->AppearanceTime
= utc
; // Brand new interface; AppearanceTime is now
3017 i
->ifa_flags
= ifa
->ifa_flags
;
3018 i
->scope_id
= scope_id
;
3020 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
3024 i
->Registered
= mDNSNULL
;
3026 // Do this AFTER i->BSSID has been set up
3027 i
->ifinfo
.NetWake
= NetWakeInterface(i
);
3028 GetMAC(&i
->ifinfo
.MAC
, scope_id
);
3029 if (i
->ifinfo
.NetWake
&& !i
->ifinfo
.MAC
.l
[0])
3030 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i
->ifinfo
.MAC
, scope_id
, i
->ifinfo
.ifname
, &ip
);
3036 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
3037 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
3039 NetworkInterfaceInfoOSX
*i
;
3040 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
3041 if (i
->Exists
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
3042 if (!mDNSv4AddressIsLinkLocal(&i
->ifinfo
.ip
.ip
.v4
))
3048 #if APPLE_OSX_mDNSResponder
3050 #if COMPILER_LIKES_PRAGMA_MARK
3052 #pragma mark - AutoTunnel
3055 #define kRacoonPort 4500
3057 static DomainAuthInfo
* AnonymousRacoonConfig
= mDNSNULL
;
3059 #ifndef NO_SECURITYFRAMEWORK
3061 static CFMutableDictionaryRef domainStatusDict
= NULL
;
3063 // MUST be called with lock held
3064 mDNSlocal
void RemoveAutoTunnelDomainStatus(const mDNS
*const m
, const DomainAuthInfo
*const info
)
3069 LogInfo("RemoveAutoTunnelDomainStatus: %##s", info
->domain
.c
);
3071 if (!domainStatusDict
) { LogMsg("RemoveAutoTunnelDomainStatus: No domainStatusDict"); return; }
3073 buffer
[mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", info
->domain
.c
) - 1] = 0;
3074 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3075 if (!domain
) { LogMsg("RemoveAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3077 if (CFDictionaryContainsKey(domainStatusDict
, domain
))
3079 CFDictionaryRemoveValue(domainStatusDict
, domain
);
3080 if (!m
->ShutdownTime
) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, mDNSNULL
, domainStatusDict
);
3085 mDNSlocal mStatus
CheckQuestionForStatus(const DNSQuestion
*const q
)
3089 if (q
->servAddr
.type
== mDNSAddrType_IPv4
&& mDNSIPv4AddressIsOnes(q
->servAddr
.ip
.v4
))
3090 return mStatus_NoSuchRecord
;
3091 else if (q
->state
== LLQ_Poll
)
3092 return mStatus_PollingMode
;
3093 else if (q
->state
!= LLQ_Established
&& !q
->DuplicateOf
)
3094 return mStatus_TransientErr
;
3097 return mStatus_NoError
;
3100 mDNSlocal mStatus
UpdateLLQStatus(const mDNS
*const m
, char *buffer
, int bufsz
, const DomainAuthInfo
*const info
)
3102 mStatus status
= mStatus_NoError
;
3103 DNSQuestion
* q
, *worst_q
= mDNSNULL
;
3104 for (q
= m
->Questions
; q
; q
=q
->next
)
3105 if (q
->AuthInfo
== info
)
3107 mStatus newStatus
= CheckQuestionForStatus(q
);
3108 if (newStatus
== mStatus_NoSuchRecord
) { status
= newStatus
; worst_q
= q
; break; }
3109 else if (newStatus
== mStatus_PollingMode
) { status
= newStatus
; worst_q
= q
; }
3110 else if (newStatus
== mStatus_TransientErr
&& status
== mStatus_NoError
) { status
= newStatus
; worst_q
= q
; }
3113 if (status
== mStatus_NoError
) mDNS_snprintf(buffer
, bufsz
, "Success");
3114 else if (status
== mStatus_NoSuchRecord
) mDNS_snprintf(buffer
, bufsz
, "GetZoneData %s: %##s", worst_q
->nta
? "not yet complete" : "failed", worst_q
->qname
.c
);
3115 else if (status
== mStatus_PollingMode
) mDNS_snprintf(buffer
, bufsz
, "Query polling %##s", worst_q
->qname
.c
);
3116 else if (status
== mStatus_TransientErr
) mDNS_snprintf(buffer
, bufsz
, "Query not yet established %##s", worst_q
->qname
.c
);
3120 mDNSlocal mStatus
UpdateRRStatus(const mDNS
*const m
, char *buffer
, int bufsz
, const DomainAuthInfo
*const info
)
3124 if (info
->deltime
) return mStatus_NoError
;
3125 for (r
= m
->ResourceRecords
; r
; r
= r
->next
)
3127 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
3128 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
3129 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
3130 // has already checked
3131 const domainname
*n
= r
->resrec
.name
;
3134 DomainAuthInfo
*ptr
;
3135 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
3136 if (SameDomainName(&ptr
->domain
, n
))
3138 if (ptr
== info
&& r
->updateError
== mStatus_BadSig
)
3140 mDNS_snprintf(buffer
, bufsz
, "Resource record update failed for %##s", r
->resrec
.name
);
3141 return r
->updateError
;
3144 n
= (const domainname
*)(n
->c
+ 1 + n
->c
[0]);
3147 return mStatus_NoError
;
3150 #endif // ndef NO_SECURITYFRAMEWORK
3152 // MUST be called with lock held
3153 mDNSlocal
void UpdateAutoTunnelDomainStatus(const mDNS
*const m
, const DomainAuthInfo
*const info
)
3155 #ifdef NO_SECURITYFRAMEWORK
3159 const NATTraversalInfo
*const llq
= m
->LLQNAT
.clientContext
? &m
->LLQNAT
: mDNSNULL
;
3160 const NATTraversalInfo
*const tun
= info
->AutoTunnelNAT
.clientContext
? &info
->AutoTunnelNAT
: mDNSNULL
;
3162 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3163 CFStringRef domain
= NULL
;
3164 CFStringRef tmp
= NULL
;
3165 CFNumberRef num
= NULL
;
3166 mStatus status
= mStatus_NoError
;
3168 if (!m
->mDNS_busy
) LogMsg("UpdateAutoTunnelDomainStatus: ERROR!! Lock not held");
3169 if (!domainStatusDict
)
3171 domainStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3172 if (!domainStatusDict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
3175 if (!dict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
3177 buffer
[mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", info
->domain
.c
) - 1] = 0;
3178 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3179 if (!domain
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3181 mDNS_snprintf(buffer
, sizeof(buffer
), "%#a", &m
->Router
);
3182 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3184 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
3187 CFDictionarySetValue(dict
, CFSTR("RouterAddress"), tmp
);
3191 mDNS_snprintf(buffer
, sizeof(buffer
), "%.4a", &m
->ExternalAddress
);
3192 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3194 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
3197 CFDictionarySetValue(dict
, CFSTR("ExternalAddress"), tmp
);
3203 mDNSu32 port
= mDNSVal16(llq
->ExternalPort
);
3205 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
3207 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
3210 CFDictionarySetValue(dict
, CFSTR("LLQExternalPort"), num
);
3216 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &llq
->Result
);
3218 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
3221 CFDictionarySetValue(dict
, CFSTR("LLQNPMStatus"), num
);
3229 mDNSu32 port
= mDNSVal16(tun
->ExternalPort
);
3231 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
3233 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
3236 CFDictionarySetValue(dict
, CFSTR("AutoTunnelExternalPort"), num
);
3242 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tun
->Result
);
3244 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
3247 CFDictionarySetValue(dict
, CFSTR("AutoTunnelNPMStatus"), num
);
3254 mDNSu32 code
= m
->LastNATMapResultCode
;
3256 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &code
);
3258 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
3261 CFDictionarySetValue(dict
, CFSTR("LastNATMapResultCode"), num
);
3266 // If we have a relay address which lets other hosts to reach us through the relay, then we should
3267 // report success except for the LLQs they don't go over the relay connection. If LLQs fail, then
3268 // report failure. In future, when LLQs go over the relay connection, we don't need this logic
3269 if (!mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddrIn
))
3271 // If we have a bad signature error updating RR, it overrides any error as
3272 // the user needs to be notified immediately
3273 status
= UpdateRRStatus(m
, buffer
, sizeof(buffer
), info
);
3274 if (status
== mStatus_NoError
)
3276 status
= UpdateLLQStatus(m
, buffer
, sizeof(buffer
), info
);
3277 if (status
== mStatus_PollingMode
)
3279 // If we have a relay connection and we are in polling mode, report as success.
3280 // This normally happens when we are behind Double NAT or NAT with UPnP/NAT-PMP
3281 // disabled but we are able to successfully file share/screen share with the help
3282 // of the relay connection. As it just affects the discovery/update of the other
3283 // BTMM hosts, we consider it as minor issue and report it as success.
3284 LogInfo("UpdateAutoTunnelDomainStatus:NonzeroRelayAddress: Polling reported as success");
3285 status
= mStatus_NoError
;
3286 mDNS_snprintf(buffer
, sizeof(buffer
), "Success");
3289 LogInfo("UpdateAutoTunnelDomainStatus:NonzeroRelayAddress: Status %d, %s", status
, buffer
);
3291 else if (!llq
&& !tun
)
3293 status
= mStatus_NotInitializedErr
;
3294 mDNS_snprintf(buffer
, sizeof(buffer
), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
3296 else if ((llq
&& llq
->Result
== mStatus_DoubleNAT
) || (tun
&& tun
->Result
== mStatus_DoubleNAT
))
3298 status
= mStatus_DoubleNAT
;
3299 mDNS_snprintf(buffer
, sizeof(buffer
), "Double NAT: Router is reporting an external address");
3301 else if ((llq
&& llq
->Result
== mStatus_NATPortMappingDisabled
) || (tun
&& tun
->Result
== mStatus_NATPortMappingDisabled
) ||
3302 (m
->LastNATMapResultCode
== NATErr_Refused
&& ((llq
&& !llq
->Result
&& mDNSIPPortIsZero(llq
->ExternalPort
)) || (tun
&& !tun
->Result
&& mDNSIPPortIsZero(tun
->ExternalPort
)))))
3304 status
= mStatus_NATPortMappingDisabled
;
3305 mDNS_snprintf(buffer
, sizeof(buffer
), "NAT-PMP is disabled on the router");
3307 else if ((llq
&& llq
->Result
) || (tun
&& tun
->Result
))
3309 status
= mStatus_NATTraversal
;
3310 mDNS_snprintf(buffer
, sizeof(buffer
), "Error obtaining NAT port mapping from router");
3312 else if (m
->Router
.type
== mDNSAddrType_None
)
3314 status
= mStatus_NoRouter
;
3315 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - none");
3317 else if (m
->Router
.type
== mDNSAddrType_IPv4
&& mDNSIPv4AddressIsZero(m
->Router
.ip
.v4
))
3319 status
= mStatus_NoRouter
;
3320 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - v4 zero");
3322 else if ((llq
&& mDNSIPPortIsZero(llq
->ExternalPort
)) || (tun
&& mDNSIPPortIsZero(tun
->ExternalPort
)))
3324 status
= mStatus_NATTraversal
;
3325 mDNS_snprintf(buffer
, sizeof(buffer
), "Unable to obtain NAT port mapping from router");
3329 status
= UpdateRRStatus(m
, buffer
, sizeof(buffer
), info
);
3330 if (status
== mStatus_NoError
)
3331 status
= UpdateLLQStatus(m
, buffer
, sizeof(buffer
), info
);
3332 LogInfo("UpdateAutoTunnelDomainStatus:ZeroRelayAddress: Status %d, %s", status
, buffer
);
3335 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
);
3337 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
3340 CFDictionarySetValue(dict
, CFSTR("StatusCode"), num
);
3344 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3346 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
3349 CFDictionarySetValue(dict
, CFSTR("StatusMessage"), tmp
);
3353 if (!CFDictionaryContainsKey(domainStatusDict
, domain
) ||
3354 !CFEqual(dict
, (CFMutableDictionaryRef
)CFDictionaryGetValue(domainStatusDict
, domain
)))
3356 CFDictionarySetValue(domainStatusDict
, domain
, dict
);
3357 if (!m
->ShutdownTime
)
3359 static char statusBuf
[16];
3360 mDNS_snprintf(statusBuf
, sizeof(statusBuf
), "%d", (int)status
);
3361 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.domainstatus", status
? "failure" : "success", statusBuf
, "");
3362 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, mDNSNULL
, domainStatusDict
);
3369 debugf("UpdateAutoTunnelDomainStatus: %s", buffer
);
3370 #endif // def NO_SECURITYFRAMEWORK
3373 // MUST be called with lock held
3374 mDNSexport
void UpdateAutoTunnelDomainStatuses(const mDNS
*const m
)
3376 #ifdef NO_SECURITYFRAMEWORK
3379 if (!m
->mDNS_busy
) LogMsg("UpdateAutoTunnelDomainStatuses: ERROR!! Lock not held");
3380 DomainAuthInfo
* info
;
3381 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
3382 if (info
->AutoTunnel
&& !info
->deltime
)
3383 UpdateAutoTunnelDomainStatus(m
, info
);
3384 #endif // def NO_SECURITYFRAMEWORK
3387 // MUST be called with lock held
3388 mDNSlocal mDNSBool
TunnelServers(mDNS
*const m
)
3391 for (r
= m
->ResourceRecords
; r
; r
= r
->next
)
3392 if (r
->resrec
.rrtype
== kDNSType_SRV
)
3394 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, r
->resrec
.name
);
3395 if (AuthInfo
&& AuthInfo
->AutoTunnel
&& !AuthInfo
->deltime
) return(mDNStrue
);
3401 // MUST be called with lock held
3402 mDNSlocal mDNSBool
TunnelClients(mDNS
*const m
)
3405 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
3406 if (p
->q
.ThisQInterval
< 0)
3411 mDNSlocal
void UpdateAnonymousRacoonConfig(mDNS
*m
) // Determine whether we need racoon to accept incoming connections
3413 DomainAuthInfo
*info
;
3415 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
3416 if (info
->AutoTunnel
&& !info
->deltime
&& (!mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) || !mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddrIn
)))
3419 if (info
!= AnonymousRacoonConfig
)
3421 AnonymousRacoonConfig
= info
;
3422 // Create or revert configuration file, and start (or SIGHUP) Racoon
3423 (void)mDNSConfigureServer(AnonymousRacoonConfig
? kmDNSUp
: kmDNSDown
, AnonymousRacoonConfig
? &AnonymousRacoonConfig
->domain
: mDNSNULL
);
3427 // Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
3428 // sometimes the caller may already be holding the lock e.g., RegisterAutoTunnel6Record and sometimes
3429 // not e.g., RegisterAutoTunnelServiceRecord
3430 mDNSlocal
void RegisterAutoTunnelHostRecord(mDNS
*m
, DomainAuthInfo
*info
)
3433 mDNSBool NATProblem
;
3435 if (!m
->mDNS_busy
) LogMsg("RegisterAutoTunnelHostRecord: ERROR!! Lock not held");
3437 // We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
3438 // called at least once with some Services/Records in the domain and hence it is safe to register
3439 // records when this function is called.
3440 if (!info
->AutoTunnelNAT
.clientContext
) { LogInfo("RegisterAutoTunnelHostRecord: No services registered, not registering the record\n"); return; }
3442 // Are we behind a NAT with no NAT-PMP support or behind a Double NAT ? Double NATs may have
3443 // NAT-PMP support but it still does not provide inbound connectivity. If there is no NAT-PMP
3444 // support, ExternalPort is zero. If we are behind a Double NAT, then the NATResult is non-zero.
3446 NATProblem
= mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) || info
->AutoTunnelNAT
.Result
;
3448 if (mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddrIn
))
3450 // If we don't have a relay address, check to see if we are behind a Double NAT or NAT with no NAT-PMP
3454 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
);
3460 // Relay address may be non-zero but we might be going to sleep as the utun interface is not removed
3461 // when going to sleep. If we are awake, we don't care about the NATProblem as the relay connnection
3462 // is up. If we are going to sleep, we should not register the host record if we have a NAT problem.
3463 if (m
->SleepState
!= SleepState_Awake
&& NATProblem
)
3465 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
);
3472 // We use zero Requested port to infer that we should not be calling Register anymore as it might
3473 // be shutdown or the DomainAuthInfo is going away.
3475 // We can use a different set of state variables to track the above as the records registered in
3476 // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
3477 // reuse the NAT variables.
3479 // Set up our address record for the internal tunnel address
3480 // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
3481 if (!mDNSIPPortIsZero(info
->AutoTunnelNAT
.RequestedPort
) && info
->AutoTunnelHostRecord
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3483 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
3484 AppendDomainLabel(&info
->AutoTunnelHostRecord
.namestorage
, &m
->hostlabel
);
3485 AppendDomainName (&info
->AutoTunnelHostRecord
.namestorage
, &info
->domain
);
3486 info
->AutoTunnelHostRecord
.resrec
.rdata
->u
.ipv6
= m
->AutoTunnelHostAddr
;
3487 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
3489 err
= mDNS_Register_internal(m
, &info
->AutoTunnelHostRecord
);
3491 if (err
) LogMsg("RegisterAutoTunnelHostRecord error %d registering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
3494 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
3495 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
3496 LogInfo("RegisterAutoTunnelHostRecord registering AutoTunnelHostRecord %##s", info
->AutoTunnelHostRecord
.namestorage
.c
);
3499 else LogInfo("RegisterAutoTunnelHostRecord: Not registering Context %p Port %d Type %d", info
->AutoTunnelNAT
.clientContext
, mDNSVal16(info
->AutoTunnelNAT
.RequestedPort
), info
->AutoTunnelHostRecord
.resrec
.RecordType
);
3502 mDNSlocal
void DeregisterAutoTunnelHostRecord(mDNS
*m
, DomainAuthInfo
*info
)
3504 LogInfo("DeregisterAutoTunnelHostRecord %##s", info
->domain
.c
);
3506 // Don't deregister if we have the AutoTunnel6 or AutoTunnelService records are registered.
3507 // They indicate that BTMM is working
3508 if (info
->AutoTunnel6Record
.resrec
.RecordType
> kDNSRecordTypeDeregistering
||
3509 info
->AutoTunnelService
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
3511 LogInfo("DeregisterAutoTunnelHostRecord %##s, not deregistering the Host Record AutoTunnel6 RecordType:%d AutoTunnel RecordType: %d", info
->domain
.c
,
3512 info
->AutoTunnel6Record
.resrec
.RecordType
, info
->AutoTunnelService
.resrec
.RecordType
);
3516 if (info
->AutoTunnelHostRecord
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
3518 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelHostRecord
);
3521 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
3522 LogMsg("DeregisterAutoTunnelHostRecord error %d deregistering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
3524 else LogInfo("DeregisterAutoTunnelHostRecord: Deregistered AutoTunnel Host Record");
3526 else LogInfo("DeregisterAutoTunnelHostRecord: Not deregistering Host Record state:%d", info
->AutoTunnelHostRecord
.resrec
.RecordType
);
3529 mDNSlocal
void RegisterAutoTunnelServiceRecords(mDNS
*m
, DomainAuthInfo
*info
)
3533 //if (m->mDNS_busy) LogMsg("RegisterAutoTunnelServiceRecords: ERROR!! Lock already held");
3535 if (info
->AutoTunnelNAT
.clientContext
&& !info
->AutoTunnelNAT
.Result
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) && info
->AutoTunnelTarget
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3537 LogInfo("RegisterAutoTunnelServiceRecords %##s (%#s)", info
->domain
.c
, m
->hostlabel
.c
);
3539 // 1. Set up our address record for the external tunnel address
3540 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
3541 info
->AutoTunnelTarget
.namestorage
.c
[0] = 0;
3542 AppendDomainLabel(&info
->AutoTunnelTarget
.namestorage
, &m
->AutoTunnelLabel
);
3543 AppendDomainName (&info
->AutoTunnelTarget
.namestorage
, &info
->domain
);
3544 info
->AutoTunnelTarget
.resrec
.rdata
->u
.ipv4
= info
->AutoTunnelNAT
.ExternalAddress
;
3545 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
3547 err
= mDNS_Register(m
, &info
->AutoTunnelTarget
);
3548 if (err
) LogMsg("RegisterAutoTunnelServiceRecords error %d registering AutoTunnelTarget %##s", err
, info
->AutoTunnelTarget
.namestorage
.c
);
3549 else LogInfo("RegisterAutoTunnelServiceRecords registering AutoTunnelTarget %##s", info
->AutoTunnelTarget
.namestorage
.c
);
3553 if (info
->AutoTunnelNAT
.clientContext
&& !info
->AutoTunnelNAT
.Result
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) && info
->AutoTunnelService
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3555 // 2. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
3556 AssignDomainName (&info
->AutoTunnelService
.namestorage
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
3557 AppendDomainLabel(&info
->AutoTunnelService
.namestorage
, &m
->hostlabel
);
3558 AppendDomainName (&info
->AutoTunnelService
.namestorage
, &info
->domain
);
3559 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.priority
= 0;
3560 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.weight
= 0;
3561 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.port
= info
->AutoTunnelNAT
.ExternalPort
;
3562 AssignDomainName(&info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.target
, &info
->AutoTunnelTarget
.namestorage
);
3563 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
3564 err
= mDNS_Register(m
, &info
->AutoTunnelService
);
3565 if (err
) LogMsg("RegisterAutoTunnelServiceRecords error %d registering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
3566 else LogInfo("RegisterAutoTunnelServiceRecords registering AutoTunnelService %##s", info
->AutoTunnelService
.namestorage
.c
);
3568 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
3569 info
->AutoTunnelTarget
.namestorage
.c
, &m
->AdvertisedV4
.ip
.v4
, mDNSVal16(info
->AutoTunnelNAT
.IntPort
),
3570 info
->AutoTunnelHostRecord
.namestorage
.c
, &m
->AutoTunnelHostAddr
);
3573 RegisterAutoTunnelHostRecord(m
, info
);
3577 mDNSlocal
void DeregisterAutoTunnelServiceRecords(mDNS
*m
, DomainAuthInfo
*info
)
3579 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info
->domain
.c
);
3580 if (info
->AutoTunnelTarget
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
3582 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelTarget
);
3585 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
3586 LogMsg("DeregisterAutoTunnelServiceRecords error %d deregistering AutoTunnelTarget %##s", err
, info
->AutoTunnelTarget
.namestorage
.c
);
3588 else LogInfo("DeregisterAutoTunnelServiceRecords: Deregistered AutoTunnel Target Record");
3591 else LogInfo("DeregisterAutoTunnelServiceRecords: Not deregistering Target record state:%d", info
->AutoTunnelService
.resrec
.RecordType
);
3593 if (info
->AutoTunnelService
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
3595 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelService
);
3598 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
3599 LogMsg("DeregisterAutoTunnelServiceRecords error %d deregistering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
3601 else LogInfo("DeregisterAutoTunnelServiceRecords: Deregistered AutoTunnel Service Record");
3604 else LogInfo("DeregisterAutoTunnelServiceRecords: Not deregistering service records state:%d", info
->AutoTunnelService
.resrec
.RecordType
);
3606 DeregisterAutoTunnelHostRecord(m
, info
);
3609 // Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
3610 // sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
3611 // not e.g., AutoTunnelHostNameChanged
3612 mDNSlocal
void RegisterAutoTunnelDevInfoRecord(mDNS
*m
, DomainAuthInfo
*info
)
3616 if (!m
->mDNS_busy
) LogMsg("RegisterAutoTunnelDevInfoRecord: Lock not held");
3618 // a. We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
3619 // called at least once with some Services/Records in the domain and hence it is safe to register
3620 // records when this function is called.
3622 // b. We use zero Requested port to infer that we should not be calling Register anymore as it might
3623 // be shutdown or the DomainAuthInfo is going away.
3625 // We can use a different set of state variables to track the above as the records registered in
3626 // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
3627 // reuse the NAT variables.
3629 // Set up device info record
3630 if (info
->AutoTunnelNAT
.clientContext
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.RequestedPort
) && info
->AutoTunnelDeviceInfo
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3632 ConstructServiceName(&info
->AutoTunnelDeviceInfo
.namestorage
, &m
->nicelabel
, &DeviceInfoName
, &info
->domain
);
3633 mDNSu8 len
= m
->HIHardware
.c
[0] < 255 - 6 ? m
->HIHardware
.c
[0] : 255 - 6;
3634 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 1, "model=", 6);
3635 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 7, m
->HIHardware
.c
+ 1, len
);
3636 info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
[0] = 6 + len
; // "model=" plus the device string
3637 info
->AutoTunnelDeviceInfo
.resrec
.rdlength
= 7 + len
; // One extra for the length byte at the start of the string
3638 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
3640 err
= mDNS_Register_internal(m
, &info
->AutoTunnelDeviceInfo
);
3641 if (err
) LogMsg("RegisterAutoTunnelDevInfoRecord error %d registering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
3642 else LogInfo("RegisterAutoTunnelDevInfoRecord registering AutoTunnelDeviceInfo %##s", info
->AutoTunnelDeviceInfo
.namestorage
.c
);
3646 #ifndef NO_SECURITYFRAMEWORK
3647 mDNSlocal
void DeregisterAutoTunnelDevInfoRecord(mDNS
*m
, DomainAuthInfo
*info
)
3649 LogInfo("DeregisterAutoTunnelDevInfoRecord %##s", info
->domain
.c
);
3651 if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
3653 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelDeviceInfo
);
3656 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
3657 LogMsg("DeregisterAutoTunnelDevInfoRecord error %d deregistering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
3659 else LogInfo("DeregisterAutoTunnelDevInfoRecord: Deregistered AutoTunnel Device Info");
3661 else LogInfo("DeregisterAutoTunnelDevInfoRecord: Not deregistering DeviceInfo Record state:%d", info
->AutoTunnelDeviceInfo
.resrec
.RecordType
);
3666 // Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
3667 // sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
3668 // not e.g., AutoTunnelHostNameChanged
3669 mDNSlocal
void RegisterAutoTunnel6Record(mDNS
*m
, DomainAuthInfo
*info
)
3673 if (!m
->mDNS_busy
) LogMsg("RegisterAutoTunnel6Record: ERROR!! Lock not held");
3675 // We deregister the AutoTunnel6Record during sleep and come back here (AutoTunnelRecordCallback) to
3676 // register the address if needed. During that time, we might get a network change event which finds
3677 // that the utun interface exists and tries to register the AutoTunnel6Record which should be stopped.
3678 // Also the RelayAddress is reinitialized during that process which in turn causes the AutoTunnelRecordCallback
3679 // to re-register again. To stop these, we check for the SleepState and register only if we are awake.
3680 if (m
->SleepState
!= SleepState_Awake
)
3682 LogInfo("RegisterAutoTunnel6Record: Not in awake state, SleepState %d", m
->SleepState
);
3686 // if disabled administratively, don't register
3687 // if disabled administratively, don't register
3688 if (!m
->RegisterAutoTunnel6
|| DisableInboundRelayConnection
)
3690 LogInfo("RegisterAutoTunnel6Record: registration Disabled RegisterAutoTunnel6 %d, DisableInbound %d",
3691 m
->RegisterAutoTunnel6
, DisableInboundRelayConnection
);
3695 // If we have a valid Relay address, we need to register it now. When we got a valid address, we may not
3696 // have registered it because it was waiting for at least one service to become active in the BTMM domain.
3697 // During network change event, we might be called multiple times while the "Connectivity" key did not
3698 // change, so check to see if the value has changed. This can also be zero when we are deregistering and
3699 // getting called from the AutoTunnelRecordCallback
3701 if (mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddrIn
))
3703 LogInfo("RegisterAutoTunnel6Record: Relay address is zero, not registering");
3707 if ((info
->AutoTunnel6Record
.resrec
.RecordType
> kDNSRecordTypeDeregistering
) &&
3708 (mDNSSameIPv6Address(info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
, m
->AutoTunnelRelayAddrIn
)))
3710 LogInfo("RegisterAutoTunnel6Record: Relay address %.16a same, not registering", &m
->AutoTunnelRelayAddrIn
);
3715 // a. We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
3716 // called at least once with some Services/Records in the domain and hence it is safe to register
3717 // records when this function is called.
3719 // b. We use zero Requested port to infer that we should not be calling Register anymore as it might
3720 // be shutdown or the DomainAuthInfo is going away.
3722 // We can use a different set of state variables to track the above as the records registered in
3723 // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
3724 // reuse the NAT variables.
3726 if (info
->AutoTunnelNAT
.clientContext
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.RequestedPort
) &&
3727 info
->AutoTunnel6Record
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3729 AssignDomainName (&info
->AutoTunnel6Record
.namestorage
, (const domainname
*) "\x0C" "_autotunnel6");
3730 AppendDomainLabel(&info
->AutoTunnel6Record
.namestorage
, &m
->hostlabel
);
3731 AppendDomainName (&info
->AutoTunnel6Record
.namestorage
, &info
->domain
);
3732 info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
= m
->AutoTunnelRelayAddrIn
;
3733 info
->AutoTunnel6Record
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
3735 err
= mDNS_Register_internal(m
, &info
->AutoTunnel6Record
);
3736 if (err
) LogMsg("RegisterAutoTunnel6Record error %d registering AutoTunnel6 Record %##s", err
, info
->AutoTunnel6Record
.namestorage
.c
);
3737 else LogInfo("RegisterAutoTunnel6Record registering AutoTunnel6 Record %##s", info
->AutoTunnel6Record
.namestorage
.c
);
3739 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
3740 info
->AutoTunnel6Record
.namestorage
.c
, &m
->AutoTunnelRelayAddrIn
,
3741 info
->AutoTunnelHostRecord
.namestorage
.c
, &m
->AutoTunnelHostAddr
);
3743 } else {LogInfo("RegisterAutoTunnel6Record: client context %p, RequestedPort %d, Address %.16a, record type %d", info
->AutoTunnelNAT
.clientContext
, info
->AutoTunnelNAT
.RequestedPort
, &m
->AutoTunnelRelayAddrIn
, info
->AutoTunnel6Record
.resrec
.RecordType
);}
3745 RegisterAutoTunnelHostRecord(m
, info
);
3746 // When the AutoTunnel6 record comes up, we need to kick racoon and update the status.
3747 // If we had a port mapping, we would have done it in RegisterAutoTunnelServiceRecords.
3748 // If we don't have a port mapping, we need to do it here.
3749 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
3750 UpdateAutoTunnelDomainStatus(m
, info
);
3753 mDNSlocal
void DeregisterAutoTunnel6Record(mDNS
*m
, DomainAuthInfo
*info
)
3755 LogInfo("DeregisterAutoTunnel6Record %##s", info
->domain
.c
);
3757 if (info
->AutoTunnel6Record
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
3759 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnel6Record
);
3762 info
->AutoTunnel6Record
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
3763 info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
= zerov6Addr
;
3764 LogMsg("DeregisterAutoTunnel6Record error %d deregistering AutoTunnel6Record %##s", err
, info
->AutoTunnel6Record
.namestorage
.c
);
3766 else LogInfo("DeregisterAutoTunnel6Record: Deregistered AutoTunnel6 Record");
3768 else LogInfo("DeregisterAutoTunnel6Record: Not deregistering AuoTunnel6 record state:%d", info
->AutoTunnel6Record
.resrec
.RecordType
);
3770 DeregisterAutoTunnelHostRecord(m
, info
);
3771 // UpdateAutoTunnelDomainStatus is careful enough not to turn it on if we don't have
3772 // a external port mapping. Otherwise, it will be turned off.
3774 UpdateAutoTunnelDomainStatus(m
, info
);
3778 mDNSlocal
void AutoTunnelRecordCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
3780 DomainAuthInfo
*info
= (DomainAuthInfo
*)rr
->RecordContext
;
3781 if (result
== mStatus_MemFree
)
3783 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m
, rr
));
3784 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
3785 if (rr
== &info
->AutoTunnelHostRecord
)
3787 rr
->namestorage
.c
[0] = 0;
3788 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
3789 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m
->NextSRVUpdate
- m
->timenow
, m
->timenow
);
3791 if (m
->ShutdownTime
) {LogInfo("AutoTunnelRecordCallback: Shutdown, returning");return;}
3792 if (rr
== &info
->AutoTunnelHostRecord
)
3794 LogInfo("AutoTunnelRecordCallback: calling RegisterAutoTunnelHostRecord");
3795 RegisterAutoTunnelHostRecord(m
,info
);
3797 else if (rr
== &info
->AutoTunnelDeviceInfo
)
3799 LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnelDevInfoRecord");
3800 RegisterAutoTunnelDevInfoRecord(m
,info
);
3802 else if (rr
== &info
->AutoTunnelService
|| rr
== &info
->AutoTunnelTarget
)
3804 LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnelServiceRecords");
3805 RegisterAutoTunnelServiceRecords(m
,info
);
3807 else if (rr
== &info
->AutoTunnel6Record
)
3809 LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnel6Record");
3810 info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
= zerov6Addr
;
3811 RegisterAutoTunnel6Record(m
,info
);
3816 #ifndef NO_SECURITYFRAMEWORK
3817 mDNSlocal
void AutoTunnelDeleteAuthInfoState(mDNS
*m
, DomainAuthInfo
*info
)
3819 LogInfo("AutoTunnelDeleteAuthInfoState: Cleaning up state releated to Domain AuthInfo %##s", info
->domain
.c
);
3821 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
3822 DeregisterAutoTunnelDevInfoRecord(m
, info
);
3823 DeregisterAutoTunnelServiceRecords(m
, info
);
3824 DeregisterAutoTunnel6Record(m
, info
);
3825 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
3826 UpdateAutoTunnelDomainStatus(m
, info
);
3828 #endif // ndef NO_SECURITYFRAMEWORK
3830 mDNSlocal
void AutoTunnelNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
3832 DomainAuthInfo
*info
= (DomainAuthInfo
*)n
->clientContext
;
3833 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s",
3834 n
->Result
, &n
->ExternalAddress
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->ExternalPort
), m
->hostlabel
.c
, info
->domain
.c
);
3836 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
3837 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m
->NextSRVUpdate
- m
->timenow
, m
->timenow
);
3839 DeregisterAutoTunnelServiceRecords(m
, info
);
3840 RegisterAutoTunnelServiceRecords(m
, info
);
3842 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
3844 UpdateAutoTunnelDomainStatus(m
, (DomainAuthInfo
*)n
->clientContext
);
3847 mDNSlocal
void AbortDeregistration(mDNS
*const m
, AuthRecord
*rr
)
3849 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
3851 LogInfo("Aborting deregistration of %s", ARDisplayString(m
, rr
));
3852 CompleteDeregistration(m
, rr
);
3854 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnregistered
)
3855 LogMsg("AbortDeregistration ERROR RecordType %02X for %s", ARDisplayString(m
, rr
));
3858 mDNSlocal
void AutoTunnelHostNameChanged(mDNS
*m
, DomainAuthInfo
*info
)
3860 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m
->hostlabel
.c
, info
->domain
.c
);
3862 DeregisterAutoTunnelDevInfoRecord(m
, info
);
3863 DeregisterAutoTunnelServiceRecords(m
, info
);
3864 DeregisterAutoTunnel6Record(m
, info
);
3865 RegisterAutoTunnelServiceRecords(m
, info
);
3868 RegisterAutoTunnelDevInfoRecord(m
, info
);
3869 RegisterAutoTunnel6Record(m
, info
);
3870 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
3874 mDNSlocal
void SetupLocalAutoTunnel6Records(mDNS
*const m
, DomainAuthInfo
*info
)
3876 AbortDeregistration(m
, &info
->AutoTunnelDeviceInfo
);
3877 AbortDeregistration(m
, &info
->AutoTunnel6Record
);
3879 // When the BTMM is turned on/off too quickly, following things happen.
3881 // 1. Turning off BTMM triggers deregistration of the DevInfo/AutoTunnel6 etc. records
3882 // 2. While (1) is in progress, the BTMM is turned on
3884 // At step (2), mDNS_SetSecretForDomain clears info->deltime indicating that the domain is valid
3885 // while we have not processed the turning off BTMM completely. Hence, we end up calling this
3886 // function to re-register the records. AbortDeregistration above aborts the Deregistration as the
3887 // records are still in Deregistering state and in AutoTunnelRecordCallback we end up registering
3888 // again. So, we have to be careful below to not call mDNS_SetupResourceRecord again which will
3889 // reset the state to Unregistered and registering again will lead to error as it is registered
3890 // and already in the list. Hence, register below only if needed.
3892 if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
||
3893 info
->AutoTunnel6Record
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
)
3895 LogInfo("SetupLocalAutoTunnel6Records: AutoTunnel Records not in Unregistered state: Device: %d, AutoTunnel6:%d",
3896 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
, info
->AutoTunnel6Record
.resrec
.RecordType
);
3899 if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3901 mDNS_SetupResourceRecord(&info
->AutoTunnelDeviceInfo
, mDNSNULL
, mDNSInterface_Any
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
3902 RegisterAutoTunnelDevInfoRecord(m
, info
);
3904 if (info
->AutoTunnel6Record
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3906 mDNS_SetupResourceRecord(&info
->AutoTunnel6Record
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
3907 RegisterAutoTunnel6Record(m
, info
);
3910 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
3912 UpdateAutoTunnelDomainStatus(m
, info
);
3913 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
3916 // Before SetupLocalAutoTunnelInterface_internal is called,
3917 // m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
3918 // Must be called with the lock held
3919 mDNSexport
void SetupLocalAutoTunnelInterface_internal(mDNS
*const m
, mDNSBool servicesStarting
)
3921 // 1. Configure the local IPv6 ULA BTMM address
3922 if (!m
->AutoTunnelHostAddrActive
)
3924 m
->AutoTunnelHostAddrActive
= mDNStrue
;
3925 LogInfo("SetupLocalAutoTunnelInterface_internal: Setting up AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
3926 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp
, m
->AutoTunnelHostAddr
.b
);
3929 // 2. If we have at least one server (pending) listening, publish our records
3930 // The services may not be in the list when it is first trying to resolve the target of the SRV record.
3931 // servicesStarting is an indication of that. Use that instead of looking up in the list of Services/Records.
3932 if (servicesStarting
|| TunnelServers(m
))
3934 DomainAuthInfo
*info
;
3935 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
3937 if (info
->AutoTunnel
&& !info
->deltime
&& !info
->AutoTunnelNAT
.clientContext
)
3939 // If we just resurrected a DomainAuthInfo that is still deregistering, we need to abort the
3940 // deregistration process before re-using the AuthRecord memory
3942 // Note: We don't need the same caution as in SetupLocalAutoTunnel6Records (see the comments there)
3943 // as AutoTunnelRecordCallback (called as a result of AbortDeregistration) will not end up registering
3944 // the records because clientContext is still NULL
3946 AbortDeregistration(m
, &info
->AutoTunnelTarget
);
3947 AbortDeregistration(m
, &info
->AutoTunnelService
);
3948 AbortDeregistration(m
, &info
->AutoTunnelHostRecord
);
3950 mDNS_SetupResourceRecord(&info
->AutoTunnelTarget
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, kHostNameTTL
,
3951 kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
3952 mDNS_SetupResourceRecord(&info
->AutoTunnelService
, mDNSNULL
, mDNSInterface_Any
, kDNSType_SRV
, kHostNameTTL
,
3953 kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
3954 mDNS_SetupResourceRecord(&info
->AutoTunnelHostRecord
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
,
3955 kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
3957 // Try to get a NAT port mapping for the AutoTunnelService
3958 info
->AutoTunnelNAT
.clientCallback
= AutoTunnelNATCallback
;
3959 info
->AutoTunnelNAT
.clientContext
= info
;
3960 info
->AutoTunnelNAT
.Protocol
= NATOp_MapUDP
;
3961 info
->AutoTunnelNAT
.IntPort
= IPSECPort
;
3962 info
->AutoTunnelNAT
.RequestedPort
= IPSECPort
;
3963 info
->AutoTunnelNAT
.NATLease
= 0;
3964 mStatus err
= mDNS_StartNATOperation_internal(m
, &info
->AutoTunnelNAT
);
3965 if (err
) LogMsg("SetupLocalAutoTunnelInterface_internal: error %d starting NAT mapping", err
);
3967 // Register the records that can be done without communicating with the NAT
3969 // Note: This should be done after we setup the AutoTunnelNAT information
3970 // as some of the fields in that structure are used to infer other information
3971 // e.g., is it okay to register now ?
3973 SetupLocalAutoTunnel6Records(m
, info
);
3980 mDNSlocal mStatus
AutoTunnelSetKeys(ClientTunnel
*tun
, mDNSBool AddNew
)
3982 mDNSv6Addr loc_outer6
;
3983 mDNSv6Addr rmt_outer6
;
3985 // When we are tunneling over IPv6 Relay address, the port number is zero
3986 if (mDNSIPPortIsZero(tun
->rmt_outer_port
))
3988 loc_outer6
= tun
->loc_outer6
;
3989 rmt_outer6
= tun
->rmt_outer6
;
3993 loc_outer6
= zerov6Addr
;
3994 loc_outer6
.b
[0] = tun
->loc_outer
.b
[0];
3995 loc_outer6
.b
[1] = tun
->loc_outer
.b
[1];
3996 loc_outer6
.b
[2] = tun
->loc_outer
.b
[2];
3997 loc_outer6
.b
[3] = tun
->loc_outer
.b
[3];
3999 rmt_outer6
= zerov6Addr
;
4000 rmt_outer6
.b
[0] = tun
->rmt_outer
.b
[0];
4001 rmt_outer6
.b
[1] = tun
->rmt_outer
.b
[1];
4002 rmt_outer6
.b
[2] = tun
->rmt_outer
.b
[2];
4003 rmt_outer6
.b
[3] = tun
->rmt_outer
.b
[3];
4006 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)));
4009 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
4010 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
4012 mDNSlocal
void ReissueBlockedQuestionWithType(mDNS
*const m
, domainname
*d
, mDNSBool success
, mDNSu16 qtype
)
4014 DNSQuestion
*q
= m
->Questions
;
4017 if (q
->NoAnswer
== NoAnswer_Suspended
&& q
->qtype
== qtype
&& q
->AuthInfo
&& q
->AuthInfo
->AutoTunnel
&& SameDomainName(&q
->qname
, d
))
4019 LogInfo("Restart %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4020 mDNSQuestionCallback
*tmp
= q
->QuestionCallback
;
4021 q
->QuestionCallback
= AutoTunnelCallback
; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
4022 mDNS_StopQuery(m
, q
);
4023 mDNS_StartQuery(m
, q
);
4024 q
->QuestionCallback
= tmp
; // Restore QuestionCallback back to the real value
4025 if (!success
) q
->NoAnswer
= NoAnswer_Fail
;
4026 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
4027 // In general we have to assume that the question list might have changed in arbitrary ways.
4028 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
4029 // already in use. The safest solution is just to go back to the start of the list and start again.
4030 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
4031 // just one suspended question, so it's really a 2n algorithm.
4039 mDNSlocal
void ReissueBlockedQuestions(mDNS
*const m
, domainname
*d
, mDNSBool success
)
4041 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
4042 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
4043 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
4044 // 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.
4045 // 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.
4046 ReissueBlockedQuestionWithType(m
, d
, success
, kDNSType_AAAA
);
4047 ReissueBlockedQuestionWithType(m
, d
, mDNStrue
, kDNSType_A
);
4050 mDNSlocal
void UnlinkAndReissueBlockedQuestions(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool success
)
4052 ClientTunnel
**p
= &m
->TunnelClients
;
4053 while (*p
!= tun
&& *p
) p
= &(*p
)->next
;
4054 if (*p
) *p
= tun
->next
;
4055 ReissueBlockedQuestions(m
, &tun
->dstname
, success
);
4056 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun
);
4057 freeL("ClientTunnel", tun
);
4060 mDNSlocal mDNSBool
TunnelClientDeleteMatching(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool v6Tunnel
)
4063 mDNSBool needSetKeys
= mDNStrue
;
4068 // Is this a tunnel to the same host that we are trying to setup now?
4069 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
4072 ClientTunnel
*old
= *p
;
4075 if (!mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue; }
4076 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4077 if (old
->q
.ThisQInterval
>= 0)
4079 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4080 mDNS_StopQuery(m
, &old
->q
);
4082 else if (!mDNSSameIPv6Address((*p
)->rmt_inner
, tun
->rmt_inner
) ||
4083 !mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
4084 !mDNSSameIPv6Address(old
->loc_outer6
, tun
->loc_outer6
) ||
4085 !mDNSSameIPv6Address(old
->rmt_outer6
, tun
->rmt_outer6
))
4087 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4088 // the other parameters of the tunnel are different
4089 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4090 AutoTunnelSetKeys(old
, mDNSfalse
);
4094 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4095 // as "tun" and "old" are identical
4096 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
,
4098 needSetKeys
= mDNSfalse
;
4103 if (mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue; }
4104 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4105 if (old
->q
.ThisQInterval
>= 0)
4107 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4108 mDNS_StopQuery(m
, &old
->q
);
4110 else if (!mDNSSameIPv6Address((*p
)->rmt_inner
, tun
->rmt_inner
) ||
4111 !mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
4112 !mDNSSameIPv4Address(old
->loc_outer
, tun
->loc_outer
) ||
4113 !mDNSSameIPv4Address(old
->rmt_outer
, tun
->rmt_outer
) ||
4114 !mDNSSameIPPort(old
->rmt_outer_port
, tun
->rmt_outer_port
))
4116 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4117 // the other parameters of the tunnel are different
4118 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4119 AutoTunnelSetKeys(old
, mDNSfalse
);
4123 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4124 // as "tun" and "old" are identical
4125 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
,
4127 needSetKeys
= mDNSfalse
;
4132 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old
);
4133 freeL("ClientTunnel", old
);
4139 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
4140 // tunnel will be deleted
4141 mDNSlocal
void TunnelClientDeleteAny(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool v6Tunnel
)
4148 // If there is more than one client tunnel to the same host, delete all of them.
4149 // We do this by just checking against the EUI64 rather than the full address
4150 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
4153 ClientTunnel
*old
= *p
;
4156 if (!mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue;}
4157 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4161 if (mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue;}
4162 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4164 if (old
->q
.ThisQInterval
>= 0)
4166 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4167 mDNS_StopQuery(m
, &old
->q
);
4171 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4172 AutoTunnelSetKeys(old
, mDNSfalse
);
4175 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old
);
4176 freeL("ClientTunnel", old
);
4181 mDNSlocal
void TunnelClientFinish(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
)
4183 mDNSBool needSetKeys
= mDNStrue
;
4184 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
4185 mDNSBool v6Tunnel
= mDNSfalse
;
4187 // If the port is zero, then we have a relay address of the peer
4188 if (mDNSIPPortIsZero(tun
->rmt_outer_port
))
4189 v6Tunnel
= mDNStrue
;
4193 LogInfo("TunnelClientFinish: Relay address %.16a", &answer
->rdata
->u
.ipv6
);
4194 tun
->rmt_outer6
= answer
->rdata
->u
.ipv6
;
4195 tun
->loc_outer6
= m
->AutoTunnelRelayAddrOut
;
4199 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer
->rdata
->u
.ipv4
);
4200 tun
->rmt_outer
= answer
->rdata
->u
.ipv4
;
4201 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
4202 tmpDst
.ip
.v4
= tun
->rmt_outer
;
4203 mDNSAddr tmpSrc
= zeroAddr
;
4204 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
4205 if (tmpSrc
.type
== mDNSAddrType_IPv4
) tun
->loc_outer
= tmpSrc
.ip
.v4
;
4206 else tun
->loc_outer
= m
->AdvertisedV4
.ip
.v4
;
4209 question
->ThisQInterval
= -1; // So we know this tunnel setup has completed
4210 tun
->loc_inner
= m
->AutoTunnelHostAddr
;
4212 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
4213 // look for existing tunnels to see whether they have the same information for our peer.
4214 // If not, delete them and need to create a new tunnel. If they are same, just use the
4215 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
4216 TunnelClientDeleteAny(m
, tun
, !v6Tunnel
);
4217 needSetKeys
= TunnelClientDeleteMatching(m
, tun
, v6Tunnel
);
4219 if (needSetKeys
) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel
? "IPv6" : "IPv4"), tun
->dstname
.c
, &tun
->rmt_inner
);
4220 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel
? "IPv6" : "IPv4"), tun
->dstname
.c
, &tun
->rmt_inner
);
4222 if (m
->AutoTunnelHostAddr
.b
[0]) { mDNS_Lock(m
); SetupLocalAutoTunnelInterface_internal(m
, mDNSfalse
); mDNS_Unlock(m
); };
4224 mStatus result
= needSetKeys
? AutoTunnelSetKeys(tun
, mDNStrue
) : mStatus_NoError
;
4225 static char msgbuf
[32];
4226 mDNS_snprintf(msgbuf
, sizeof(msgbuf
), "Tunnel setup - %d", result
);
4227 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.config", result
? "failure" : "success", msgbuf
, "");
4228 // Kick off any questions that were held pending this tunnel setup
4229 ReissueBlockedQuestions(m
, &tun
->dstname
, (result
== mStatus_NoError
) ? mDNStrue
: mDNSfalse
);
4232 mDNSexport
void AutoTunnelCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
4234 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
4236 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun
, AddRecord
, answer
->rdlength
, question
->qtype
);
4238 if (!AddRecord
) return;
4239 mDNS_StopQuery(m
, question
);
4241 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
4242 // The code below will look for _autotunnel._udp SRV record followed by A record
4243 if (tun
->tc_state
!= TC_STATE_AAAA_PEER_RELAY
&& !answer
->rdlength
)
4245 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
4246 static char msgbuf
[16];
4247 mDNS_snprintf(msgbuf
, sizeof(msgbuf
), "%s lookup", DNSTypeName(question
->qtype
));
4248 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.config", "failure", msgbuf
, "");
4249 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNSfalse
);
4253 switch (tun
->tc_state
)
4255 case TC_STATE_AAAA_PEER
:
4256 if (question
->qtype
!= kDNSType_AAAA
)
4258 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question
->qtype
);
4260 if (mDNSSameIPv6Address(answer
->rdata
->u
.ipv6
, m
->AutoTunnelHostAddr
))
4262 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer
->rdata
->u
.ipv6
);
4263 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNStrue
);
4266 tun
->rmt_inner
= answer
->rdata
->u
.ipv6
;
4267 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun
->rmt_inner
);
4268 if (!mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddrOut
))
4270 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
4271 tun
->tc_state
= TC_STATE_AAAA_PEER_RELAY
;
4272 question
->qtype
= kDNSType_AAAA
;
4273 AssignDomainName(&question
->qname
, (const domainname
*) "\x0C" "_autotunnel6");
4277 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
4278 tun
->tc_state
= TC_STATE_SRV_PEER
;
4279 question
->qtype
= kDNSType_SRV
;
4280 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
4282 AppendDomainName(&question
->qname
, &tun
->dstname
);
4283 mDNS_StartQuery(m
, &tun
->q
);
4285 case TC_STATE_AAAA_PEER_RELAY
:
4286 if (question
->qtype
!= kDNSType_AAAA
)
4288 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question
->qtype
);
4290 // If it failed, look for the SRV record.
4291 if (!answer
->rdlength
)
4293 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
4294 tun
->tc_state
= TC_STATE_SRV_PEER
;
4295 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
4296 AppendDomainName(&question
->qname
, &tun
->dstname
);
4297 question
->qtype
= kDNSType_SRV
;
4298 mDNS_StartQuery(m
, &tun
->q
);
4301 TunnelClientFinish(m
, question
, answer
);
4303 case TC_STATE_SRV_PEER
:
4304 if (question
->qtype
!= kDNSType_SRV
)
4306 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question
->qtype
);
4308 LogInfo("AutoTunnelCallback: SRV target name %##s", answer
->rdata
->u
.srv
.target
.c
);
4309 tun
->tc_state
= TC_STATE_ADDR_PEER
;
4310 AssignDomainName(&tun
->q
.qname
, &answer
->rdata
->u
.srv
.target
);
4311 tun
->rmt_outer_port
= answer
->rdata
->u
.srv
.port
;
4312 question
->qtype
= kDNSType_A
;
4313 mDNS_StartQuery(m
, &tun
->q
);
4315 case TC_STATE_ADDR_PEER
:
4316 if (question
->qtype
!= kDNSType_A
)
4318 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question
->qtype
);
4320 TunnelClientFinish(m
, question
, answer
);
4323 LogMsg("AutoTunnelCallback: Unknown question %p", question
);
4327 // Must be called with the lock held
4328 mDNSexport
void AddNewClientTunnel(mDNS
*const m
, DNSQuestion
*const q
)
4330 ClientTunnel
*p
= mallocL("ClientTunnel", sizeof(ClientTunnel
));
4332 AssignDomainName(&p
->dstname
, &q
->qname
);
4333 p
->MarkedForDeletion
= mDNSfalse
;
4334 p
->loc_inner
= zerov6Addr
;
4335 p
->loc_outer
= zerov4Addr
;
4336 p
->loc_outer6
= zerov6Addr
;
4337 p
->rmt_inner
= zerov6Addr
;
4338 p
->rmt_outer
= zerov4Addr
;
4339 p
->rmt_outer6
= zerov6Addr
;
4340 p
->rmt_outer_port
= zeroIPPort
;
4341 p
->tc_state
= TC_STATE_AAAA_PEER
;
4342 p
->next
= m
->TunnelClients
;
4343 m
->TunnelClients
= p
; // We intentionally build list in reverse order
4345 p
->q
.InterfaceID
= mDNSInterface_Any
;
4346 p
->q
.Target
= zeroAddr
;
4347 AssignDomainName(&p
->q
.qname
, &q
->qname
);
4348 p
->q
.qtype
= kDNSType_AAAA
;
4349 p
->q
.qclass
= kDNSClass_IN
;
4350 p
->q
.LongLived
= mDNSfalse
;
4351 p
->q
.ExpectUnique
= mDNStrue
;
4352 p
->q
.ForceMCast
= mDNSfalse
;
4353 p
->q
.ReturnIntermed
= mDNStrue
;
4354 p
->q
.SuppressUnusable
= mDNSfalse
;
4355 p
->q
.WakeOnResolve
= mDNSfalse
;
4356 p
->q
.QuestionCallback
= AutoTunnelCallback
;
4357 p
->q
.QuestionContext
= p
;
4359 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p
, &q
->qname
.c
, DNSTypeName(q
->qtype
), q
->LongLived
? " LongLived" : "");
4360 mDNS_StartQuery_internal(m
, &p
->q
);
4363 #endif // APPLE_OSX_mDNSResponder
4365 #if COMPILER_LIKES_PRAGMA_MARK
4367 #pragma mark - Power State & Configuration Change Management
4370 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
, mDNSs32 utc
)
4372 mDNSBool foundav4
= mDNSfalse
;
4373 mDNSBool foundav6
= mDNSfalse
;
4374 struct ifaddrs
*ifa
= myGetIfAddrs(1);
4375 struct ifaddrs
*v4Loopback
= NULL
;
4376 struct ifaddrs
*v6Loopback
= NULL
;
4377 char defaultname
[64];
4379 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
4380 if (InfoSocket
< 3 && errno
!= EAFNOSUPPORT
) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
4382 if (m
->SleepState
== SleepState_Sleeping
) ifa
= NULL
;
4386 #if LIST_ALL_INTERFACES
4387 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
4388 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
4389 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4390 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
4391 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
4392 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4393 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
4394 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
4395 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4396 if (!(ifa
->ifa_flags
& IFF_UP
))
4397 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
4398 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4399 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
4400 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
4401 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4402 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
4403 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
4404 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4405 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
4406 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
4407 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4410 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
4412 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
4413 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(m
->PrimaryMAC
) && mDNSSameEthAddress(&m
->PrimaryMAC
, &zeroEthAddr
))
4414 mDNSPlatformMemCopy(m
->PrimaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6);
4417 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
)
4418 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
4420 if (!ifa
->ifa_netmask
)
4423 SetupAddr(&ip
, ifa
->ifa_addr
);
4424 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
4425 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
4427 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
4428 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4429 else if (ifa
->ifa_netmask
->sa_family
!= ifa
->ifa_addr
->sa_family
&& ifa
->ifa_netmask
->sa_family
!= 0)
4432 SetupAddr(&ip
, ifa
->ifa_addr
);
4433 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
4434 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
4436 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
4437 else if ((int)if_nametoindex(ifa
->ifa_name
) <= 0)
4439 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
));
4443 // Make sure ifa_netmask->sa_family is set correctly
4444 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4445 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
;
4446 int ifru_flags6
= 0;
4448 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
4449 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
4451 struct in6_ifreq ifr6
;
4452 mDNSPlatformMemZero((char *)&ifr6
, sizeof(ifr6
));
4453 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
4454 ifr6
.ifr_addr
= *sin6
;
4455 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
4456 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
4457 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
4460 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
4462 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
4464 if (ifa
->ifa_addr
->sa_family
== AF_INET
) v4Loopback
= ifa
;
4466 else if (sin6
->sin6_addr
.s6_addr
[0] != 0xFD) v6Loopback
= ifa
;
4471 NetworkInterfaceInfoOSX
*i
= AddInterfaceToList(m
, ifa
, utc
);
4472 if (i
&& MulticastInterface(i
) && i
->ifinfo
.Advertise
)
4474 if (ifa
->ifa_addr
->sa_family
== AF_INET
) foundav4
= mDNStrue
;
4475 else foundav6
= mDNStrue
;
4481 ifa
= ifa
->ifa_next
;
4484 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
4485 if (!foundav4
&& v4Loopback
) AddInterfaceToList(m
, v4Loopback
, utc
);
4486 if (!foundav6
&& v6Loopback
) AddInterfaceToList(m
, v6Loopback
, utc
);
4488 // Now the list is complete, set the McastTxRx setting for each interface.
4489 NetworkInterfaceInfoOSX
*i
;
4490 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
4493 mDNSBool txrx
= MulticastInterface(i
);
4494 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
4495 txrx
= txrx
&& ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
4497 if (i
->ifinfo
.McastTxRx
!= txrx
)
4499 i
->ifinfo
.McastTxRx
= txrx
;
4500 i
->Exists
= 2; // State change; need to deregister and reregister this interface
4505 if (InfoSocket
>= 0) close(InfoSocket
);
4508 // If we haven't set up AutoTunnelHostAddr yet, do it now
4509 if (!mDNSSameEthAddress(&m
->PrimaryMAC
, &zeroEthAddr
) && m
->AutoTunnelHostAddr
.b
[0] == 0)
4511 m
->AutoTunnelHostAddr
.b
[0x0] = 0xFD; // Required prefix for "locally assigned" ULA (See RFC 4193)
4512 m
->AutoTunnelHostAddr
.b
[0x1] = mDNSRandom(255);
4513 m
->AutoTunnelHostAddr
.b
[0x2] = mDNSRandom(255);
4514 m
->AutoTunnelHostAddr
.b
[0x3] = mDNSRandom(255);
4515 m
->AutoTunnelHostAddr
.b
[0x4] = mDNSRandom(255);
4516 m
->AutoTunnelHostAddr
.b
[0x5] = mDNSRandom(255);
4517 m
->AutoTunnelHostAddr
.b
[0x6] = mDNSRandom(255);
4518 m
->AutoTunnelHostAddr
.b
[0x7] = mDNSRandom(255);
4519 m
->AutoTunnelHostAddr
.b
[0x8] = m
->PrimaryMAC
.b
[0] ^ 0x02; // See RFC 3513, Appendix A for explanation
4520 m
->AutoTunnelHostAddr
.b
[0x9] = m
->PrimaryMAC
.b
[1];
4521 m
->AutoTunnelHostAddr
.b
[0xA] = m
->PrimaryMAC
.b
[2];
4522 m
->AutoTunnelHostAddr
.b
[0xB] = 0xFF;
4523 m
->AutoTunnelHostAddr
.b
[0xC] = 0xFE;
4524 m
->AutoTunnelHostAddr
.b
[0xD] = m
->PrimaryMAC
.b
[3];
4525 m
->AutoTunnelHostAddr
.b
[0xE] = m
->PrimaryMAC
.b
[4];
4526 m
->AutoTunnelHostAddr
.b
[0xF] = m
->PrimaryMAC
.b
[5];
4527 m
->AutoTunnelLabel
.c
[0] = mDNS_snprintf((char*)m
->AutoTunnelLabel
.c
+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
4528 m
->AutoTunnelHostAddr
.b
[0x8], m
->AutoTunnelHostAddr
.b
[0x9], m
->AutoTunnelHostAddr
.b
[0xA], m
->AutoTunnelHostAddr
.b
[0xB],
4529 m
->AutoTunnelHostAddr
.b
[0xC], m
->AutoTunnelHostAddr
.b
[0xD], m
->AutoTunnelHostAddr
.b
[0xE], m
->AutoTunnelHostAddr
.b
[0xF]);
4530 LogInfo("m->AutoTunnelLabel %#s", m
->AutoTunnelLabel
.c
);
4533 mDNS_snprintf(defaultname
, sizeof(defaultname
), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen
, HINFO_HWstring
,
4534 m
->PrimaryMAC
.b
[0], m
->PrimaryMAC
.b
[1], m
->PrimaryMAC
.b
[2], m
->PrimaryMAC
.b
[3], m
->PrimaryMAC
.b
[4], m
->PrimaryMAC
.b
[5]);
4536 // Set up the nice label
4537 domainlabel nicelabel
;
4539 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
4540 if (nicelabel
.c
[0] == 0)
4542 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname
);
4543 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
4546 // Set up the RFC 1034-compliant label
4547 domainlabel hostlabel
;
4549 GetUserSpecifiedLocalHostName(&hostlabel
);
4550 if (hostlabel
.c
[0] == 0)
4552 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname
);
4553 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
4556 mDNSBool namechange
= mDNSfalse
;
4558 // We use a case-sensitive comparison here because even though changing the capitalization
4559 // of the name alone is not significant to DNS, it's still a change from the user's point of view
4560 if (SameDomainLabelCS(m
->p
->usernicelabel
.c
, nicelabel
.c
))
4561 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
4564 if (m
->p
->usernicelabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
4565 LogMsg("User updated Computer Name from “%#s” to “%#s”", m
->p
->usernicelabel
.c
, nicelabel
.c
);
4566 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
4567 namechange
= mDNStrue
;
4570 if (SameDomainLabelCS(m
->p
->userhostlabel
.c
, hostlabel
.c
))
4571 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
4574 if (m
->p
->userhostlabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
4575 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m
->p
->userhostlabel
.c
, hostlabel
.c
);
4576 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
4578 namechange
= mDNStrue
;
4581 #if APPLE_OSX_mDNSResponder
4582 if (namechange
) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
4584 DomainAuthInfo
*info
;
4585 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
4586 if (info
->AutoTunnel
) AutoTunnelHostNameChanged(m
, info
);
4588 #endif // APPLE_OSX_mDNSResponder
4590 return(mStatus_NoError
);
4593 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
4594 // Returns -1 if all the one-bits are not contiguous
4595 mDNSlocal
int CountMaskBits(mDNSAddr
*mask
)
4597 int i
= 0, bits
= 0;
4598 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
4601 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
4602 while (b
& 0x80) { bits
++; b
<<= 1; }
4605 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
4609 // returns count of non-link local V4 addresses registered
4610 mDNSlocal
int SetupActiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
4612 NetworkInterfaceInfoOSX
*i
;
4614 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
4617 NetworkInterfaceInfo
*const n
= &i
->ifinfo
;
4618 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AAAA_OVER_V4
? AF_UNSPEC
: i
->sa_family
);
4619 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifinfo
.ifname
);
4621 if (i
->Registered
&& i
->Registered
!= primary
) // Sanity check
4623 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i
->Registered
, primary
);
4624 i
->Registered
= mDNSNULL
;
4629 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
4630 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
4631 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it
4634 i
->Registered
= primary
;
4636 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
4637 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
4638 // 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.
4639 i
->Occulting
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->LastSeen
> 0 && utc
- i
->LastSeen
< 60);
4641 mDNS_RegisterInterface(m
, n
, i
->Flashing
&& i
->Occulting
);
4643 if (!mDNSAddressIsLinkLocal(&n
->ip
)) count
++;
4644 LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
4645 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
, primary
, &n
->ip
, CountMaskBits(&n
->mask
),
4646 i
->Flashing
? " (Flashing)" : "",
4647 i
->Occulting
? " (Occulting)" : "",
4648 n
->InterfaceActive
? " (Primary)" : "");
4651 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
);
4654 if (i
->sa_family
== AF_INET
)
4657 primary
->ifa_v4addr
.s_addr
= n
->ip
.ip
.v4
.NotAnInteger
;
4658 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
4659 imr
.imr_interface
= primary
->ifa_v4addr
;
4661 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
4662 // before trying to join the group, to clear out stale kernel state which may be lingering.
4663 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
4664 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
4665 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
4666 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
4667 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
4668 // because by the time we get the configuration change notification, the interface is already gone,
4669 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
4670 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
4671 if (SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AF_INET
) == i
)
4673 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
);
4674 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, &imr
, sizeof(imr
));
4675 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
4676 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err
, errno
, strerror(errno
));
4679 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i
->ifinfo
.ifname
, i
->scope_id
, &imr
.imr_multiaddr
, &imr
.imr_interface
);
4680 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
4681 // Joining same group twice can give "Address already in use" error -- no need to report that
4682 if (err
< 0 && (errno
!= EADDRINUSE
))
4683 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err
, errno
, strerror(errno
), &imr
.imr_multiaddr
, &imr
.imr_interface
);
4686 if (i
->sa_family
== AF_INET6
)
4688 struct ipv6_mreq i6mr
;
4689 i6mr
.ipv6mr_interface
= primary
->scope_id
;
4690 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroup_v6
.ip
.v6
;
4692 if (SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AF_INET6
) == i
)
4694 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
);
4695 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
4696 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
4697 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
4700 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i
->ifinfo
.ifname
, i
->scope_id
, &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
4701 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
4702 // Joining same group twice can give "Address already in use" error -- no need to report that
4703 if (err
< 0 && (errno
!= EADDRINUSE
))
4704 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
4714 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
, mDNSs32 utc
)
4716 NetworkInterfaceInfoOSX
*i
;
4717 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
4719 if (i
->Exists
) i
->LastSeen
= utc
;
4720 i
->Exists
= mDNSfalse
;
4724 // returns count of non-link local V4 addresses deregistered
4725 mDNSlocal
int ClearInactiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
4728 // If an interface is going away, then deregister this from the mDNSCore.
4729 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
4730 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
4731 // it refers to has gone away we'll crash.
4732 NetworkInterfaceInfoOSX
*i
;
4734 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
4736 // If this interface is no longer active, or its InterfaceID is changing, deregister it
4737 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AAAA_OVER_V4
? AF_UNSPEC
: i
->sa_family
);
4739 if (i
->Exists
== 0 || i
->Exists
== 2 || i
->Registered
!= primary
)
4741 i
->Flashing
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->AppearanceTime
< 60);
4742 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
4743 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
, primary
,
4744 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
),
4745 i
->Flashing
? " (Flashing)" : "",
4746 i
->Occulting
? " (Occulting)" : "",
4747 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
4748 mDNS_DeregisterInterface(m
, &i
->ifinfo
, i
->Flashing
&& i
->Occulting
);
4749 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
4750 i
->Registered
= mDNSNULL
;
4751 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
4752 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
4753 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
4755 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
4756 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
4761 // Now that everything that's going to deregister has done so, we can clean up and free the memory
4762 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
4766 // If no longer active, delete interface from list and free memory
4769 if (i
->LastSeen
== utc
) i
->LastSeen
= utc
- 1;
4770 mDNSBool
delete = (NumCacheRecordsForInterfaceID(m
, i
->ifinfo
.InterfaceID
) == 0) && (utc
- i
->LastSeen
>= 60);
4771 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
4772 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
,
4773 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), utc
- i
->LastSeen
,
4774 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
4775 #if APPLE_OSX_mDNSResponder
4776 if (i
->BPF_fd
>= 0) CloseBPF(i
);
4777 #endif // APPLE_OSX_mDNSResponder
4781 freeL("NetworkInterfaceInfoOSX", i
);
4782 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
4790 mDNSlocal
void AppendDNameListElem(DNameListElem
***List
, mDNSu32 uid
, domainname
*name
)
4792 DNameListElem
*dnle
= (DNameListElem
*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem
));
4793 if (!dnle
) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
4796 dnle
->next
= mDNSNULL
;
4798 AssignDomainName(&dnle
->name
, name
);
4800 *List
= &dnle
->next
;
4804 mDNSlocal
int compare_dns_configs(const void *aa
, const void *bb
)
4806 dns_resolver_t
*a
= *(dns_resolver_t
**)aa
;
4807 dns_resolver_t
*b
= *(dns_resolver_t
**)bb
;
4809 return (a
->search_order
< b
->search_order
) ? -1 : (a
->search_order
== b
->search_order
) ? 0 : 1;
4812 mDNSlocal
void ConfigResolvers(mDNS
*const m
, dns_config_t
*config
, mDNSBool scope
, mDNSBool setsearch
, mDNSBool setservers
)
4816 #if DNSINFO_VERSION >= 20091104
4817 dns_resolver_t
**resolver
= scope
? config
->scoped_resolver
: config
->resolver
;
4818 int nresolvers
= scope
? config
->n_scoped_resolver
: config
->n_resolver
;
4820 (void) scope
; // unused
4821 dns_resolver_t
**resolver
= config
->resolver
;
4822 int nresolvers
= config
->n_resolver
;
4825 // Currently we don't support search lists for scoped resolvers. The WAB support for this will be added later.
4826 if (setsearch
&& !scope
&& nresolvers
)
4828 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
4829 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
4830 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
4831 // instead use the search domain list as the sole authority for what domains to search and in what order
4832 // (and the domain from the "domain" field will also appear somewhere in that list).
4833 // Also, all search domains get added to the search list for resolver[0], so the domains and/or
4834 // search lists for other resolvers in the list need to be ignored.
4836 // Note: Starting DNSINFO_VERSION 20091104, search list is present only in the first resolver (resolver 0).
4837 // i.e., n_search for the first resolver is always non-zero. We don't guard it with #ifs for better readability
4839 if (resolver
[0]->n_search
== 0)
4841 LogInfo("ConfigResolvers: (%s) configuring zeroth domain as search list %s", scope
? "Scoped" : "Non-scoped", resolver
[0]->domain
);
4842 mDNS_AddSearchDomain_CString(resolver
[0]->domain
);
4846 for (i
= 0; i
< resolver
[0]->n_search
; i
++)
4848 LogInfo("ConfigResolvers: (%s) configuring search list %s", scope
? "Scoped" : "Non-scoped", resolver
[0]->search
[i
]);
4849 mDNS_AddSearchDomain_CString(resolver
[0]->search
[i
]);
4854 if (!setservers
) return;
4856 // For the "default" resolver ("resolver #1") the "domain" value is bogus and we need to ignore it.
4857 // e.g. the default resolver's "domain" value might say "apple.com", which indicates that this resolver
4858 // is only for names that fall under "apple.com", but that's not correct. Actually the default resolver is
4859 // for all names not covered by a more specific resolver (i.e. its domain should be ".", the root domain).
4861 // Note: Starting DNSINFO_VERSION 20091104, domain value of this first resolver (resolver 0) is always NULL.
4862 // We don't guard it with #ifs for better readability
4864 if ((nresolvers
!= 0) && resolver
[0]->domain
)
4865 resolver
[0]->domain
[0] = 0; // don't stop pointing at the memory, just change the first byte
4867 qsort(resolver
, nresolvers
, sizeof(dns_resolver_t
*), compare_dns_configs
);
4869 for (i
= 0; i
< nresolvers
; i
++)
4872 dns_resolver_t
*r
= resolver
[i
];
4873 mDNSInterfaceID interface
= mDNSInterface_Any
;
4876 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scope
? "Scoped" : "", i
, r
->domain
, r
->n_nameserver
);
4878 // On Tiger, dnsinfo entries for mDNS domains have port 5353, the mDNS port. Ignore them.
4879 // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
4880 // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
4881 // We also don't need to do any more work if there are no nameserver addresses
4882 if (r
->port
== 5353 || r
->n_nameserver
== 0) continue;
4884 if (!r
->domain
|| !*r
->domain
) d
.c
[0] = 0;
4885 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
))
4886 { LogMsg("ConfigResolvers: config->resolver[%d] bad domain %s", i
, r
->domain
); continue; }
4888 // DNS server option parsing
4889 if (r
->options
!= NULL
)
4891 char *nextOption
= r
->options
;
4892 char *currentOption
= NULL
;
4893 while ((currentOption
= strsep(&nextOption
, " ")) != NULL
&& currentOption
[0] != 0)
4895 // The option may be in the form of interface=xxx where xxx is an interface name.
4896 if (strncmp(currentOption
, kInterfaceSpecificOption
, sizeof(kInterfaceSpecificOption
) - 1) == 0)
4898 NetworkInterfaceInfoOSX
*ni
;
4899 char ifname
[IF_NAMESIZE
+1];
4900 mDNSu32 ifindex
= 0;
4901 // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
4902 // This allows us to block these special queries from going out on the wire.
4903 strlcpy(ifname
, currentOption
+ sizeof(kInterfaceSpecificOption
)-1, sizeof(ifname
));
4904 ifindex
= if_nametoindex(ifname
);
4905 if (ifindex
== 0) { disabled
= 1; LogMsg("ConfigResolvers: RegisterSplitDNS interface specific - interface %s not found", ifname
); continue; }
4906 LogInfo("ConfigResolvers: interface specific entry: %s on %s (%d)", r
->domain
, ifname
, ifindex
);
4907 // Find the interface. Can't use mDNSPlatformInterfaceIDFromInterfaceIndex
4908 // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
4909 for (ni
= m
->p
->InterfaceList
; ni
; ni
= ni
->next
)
4910 if (ni
->ifinfo
.InterfaceID
&& ni
->scope_id
== ifindex
) break;
4911 if (ni
!= NULL
) interface
= ni
->ifinfo
.InterfaceID
;
4912 if (interface
== mDNSNULL
)
4915 LogMsg("ConfigResolvers: RegisterSplitDNS interface specific - index %d (%s) not found", ifindex
, ifname
);
4922 // flags and if_index are defined only from this DNSINFO_VERSION onwards. Currently these
4923 // fields are zero for non-scoped resolvers. For now, these fields have non-zero values only
4924 // for scoped_resolvers.
4925 #if DNSINFO_VERSION >= 20091104
4926 if (scope
&& (r
->flags
& DNS_RESOLVER_FLAGS_SCOPED
) && (r
->if_index
!= 0))
4928 NetworkInterfaceInfoOSX
*ni
;
4929 interface
= mDNSNULL
;
4930 for (ni
= m
->p
->InterfaceList
; ni
; ni
= ni
->next
)
4931 if (ni
->ifinfo
.InterfaceID
&& ni
->scope_id
== r
->if_index
) break;
4932 if (ni
!= NULL
) interface
= ni
->ifinfo
.InterfaceID
;
4933 if (interface
== mDNSNULL
)
4936 LogMsg("ConfigResolvers: interface specific index %d not found", r
->if_index
);
4942 for (n
= 0; n
< r
->n_nameserver
; n
++)
4943 if (r
->nameserver
[n
]->sa_family
== AF_INET
|| r
->nameserver
[n
]->sa_family
== AF_INET6
)
4946 // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
4947 if (SetupAddr(&saddr
, r
->nameserver
[n
])) LogMsg("RegisterSplitDNS: bad IP address");
4950 mDNSBool scopedDNS
= mDNSfalse
;
4952 #if DNSINFO_VERSION >= 20091104
4953 // By setting scoped, this DNSServer can only be picked if the right interfaceID
4954 // is given in the question
4955 if (scope
&& (r
->flags
& DNS_RESOLVER_FLAGS_SCOPED
) && (interface
== mDNSNULL
))
4956 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
));
4958 scopedDNS
= (scope
&& (r
->flags
& DNS_RESOLVER_FLAGS_SCOPED
)) ? mDNStrue
: mDNSfalse
;
4960 s
= mDNS_AddDNSServer(m
, &d
, interface
, &saddr
, r
->port
? mDNSOpaque16fromIntVal(r
->port
) : UnicastDNSPort
, scopedDNS
);
4963 if (disabled
) s
->teststate
= DNSServer_Disabled
;
4964 LogInfo("ConfigResolvers: DNS server %#a:%d for domain %##s from slot %d,%d", &s
->addr
, mDNSVal16(s
->port
), d
.c
, i
, n
);
4971 mDNSexport
void mDNSPlatformSetDNSConfig(mDNS
*const m
, mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
, DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
)
4974 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
4977 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
4978 if (fqdn
) fqdn
->c
[0] = 0;
4979 if (RegDomains
) *RegDomains
= NULL
;
4980 if (BrowseDomains
) *BrowseDomains
= NULL
;
4982 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
4983 setservers
? " setservers" : "",
4984 setsearch
? " setsearch" : "",
4985 fqdn
? " fqdn" : "",
4986 RegDomains
? " RegDomains" : "",
4987 BrowseDomains
? " BrowseDomains" : "");
4989 // Add the inferred address-based configuration discovery domains
4990 // (should really be in core code I think, not platform-specific)
4993 struct ifaddrs
*ifa
= mDNSNULL
;
4994 struct sockaddr_in saddr
;
4995 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
4996 saddr
.sin_len
= sizeof(saddr
);
4997 saddr
.sin_family
= AF_INET
;
4999 saddr
.sin_addr
.s_addr
= *(in_addr_t
*)&m
->Router
.ip
.v4
;
5001 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
5002 if (!AddrRequiresPPPConnection((struct sockaddr
*)&saddr
)) ifa
= myGetIfAddrs(1);
5007 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
5009 !(ifa
->ifa_flags
& IFF_LOOPBACK
) &&
5010 !SetupAddr(&a
, ifa
->ifa_addr
) &&
5011 !mDNSv4AddressIsLinkLocal(&a
.ip
.v4
) )
5013 // 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
5014 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5015 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
; // Make sure ifa_netmask->sa_family is set correctly
5016 SetupAddr(&n
, ifa
->ifa_netmask
);
5017 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
5018 mDNS_snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d.in-addr.arpa.", a
.ip
.v4
.b
[3] & n
.ip
.v4
.b
[3],
5019 a
.ip
.v4
.b
[2] & n
.ip
.v4
.b
[2],
5020 a
.ip
.v4
.b
[1] & n
.ip
.v4
.b
[1],
5021 a
.ip
.v4
.b
[0] & n
.ip
.v4
.b
[0]);
5022 mDNS_AddSearchDomain_CString(buf
);
5024 ifa
= ifa
->ifa_next
;
5028 #ifndef MDNS_NO_DNSINFO
5029 if (setservers
|| setsearch
)
5031 dns_config_t
*config
= dns_configuration_copy();
5034 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
5035 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
5036 // Apparently this is expected behaviour -- "not a bug".
5037 // Accordingly, we suppress syslog messages for the first three minutes after boot.
5038 // If we are still getting failures after three minutes, then we log them.
5039 if (OSXVers
> OSXVers_10_3_Panther
&& (mDNSu32
)mDNSPlatformRawTime() > (mDNSu32
)(mDNSPlatformOneSecond
* 180))
5040 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
5044 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config
->n_resolver
);
5046 #if APPLE_OSX_mDNSResponder
5047 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
5048 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
5049 if (config
->n_resolver
&& config
->resolver
[0]->domain
&& config
->resolver
[0]->n_nameserver
&& config
->resolver
[0]->nameserver
[0])
5050 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain
, config
->resolver
[0]->domain
);
5051 else ActiveDirectoryPrimaryDomain
.c
[0] = 0;
5052 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
5053 ActiveDirectoryPrimaryDomainLabelCount
= CountLabels(&ActiveDirectoryPrimaryDomain
);
5054 if (config
->n_resolver
&& config
->resolver
[0]->n_nameserver
&& SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain
, ActiveDirectoryPrimaryDomainLabelCount
- 1), &localdomain
))
5055 SetupAddr(&ActiveDirectoryPrimaryDomainServer
, config
->resolver
[0]->nameserver
[0]);
5058 AssignDomainName(&ActiveDirectoryPrimaryDomain
, (const domainname
*)"");
5059 ActiveDirectoryPrimaryDomainLabelCount
= 0;
5060 ActiveDirectoryPrimaryDomainServer
= zeroAddr
;
5064 ConfigResolvers(m
, config
, mDNSfalse
, setsearch
, setservers
);
5065 #if DNSINFO_VERSION >= 20091104
5066 ConfigResolvers(m
, config
, mDNStrue
, setsearch
, setservers
);
5068 dns_configuration_free(config
);
5069 setservers
= mDNSfalse
; // Done these now -- no need to fetch the same data from SCDynamicStore
5070 setsearch
= mDNSfalse
;
5073 #endif // MDNS_NO_DNSINFO
5075 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL
, NULL
);
5077 LogMsg("mDNSPlatformSetDNSConfig: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5080 CFDictionaryRef ddnsdict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_DynamicDNS
);
5085 CFArrayRef fqdnArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("HostNames"));
5086 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
5088 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
5089 CFDictionaryRef fqdnDict
= CFArrayGetValueAtIndex(fqdnArray
, 0);
5090 if (fqdnDict
&& DictionaryIsEnabled(fqdnDict
))
5092 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
5095 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5096 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
5097 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
5098 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
5106 CFArrayRef regArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("RegistrationDomains"));
5107 if (regArray
&& CFArrayGetCount(regArray
) > 0)
5109 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
5110 if (regDict
&& DictionaryIsEnabled(regDict
))
5112 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
5115 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5116 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
5117 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
5120 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf
);
5121 AppendDNameListElem(&RegDomains
, 0, &d
);
5130 CFArrayRef browseArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("BrowseDomains"));
5133 for (i
= 0; i
< CFArrayGetCount(browseArray
); i
++)
5135 CFDictionaryRef browseDict
= CFArrayGetValueAtIndex(browseArray
, i
);
5136 if (browseDict
&& DictionaryIsEnabled(browseDict
))
5138 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
5141 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5142 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
5143 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf
[0] ? buf
: "(unknown)");
5146 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf
);
5147 AppendDNameListElem(&BrowseDomains
, 0, &d
);
5154 CFRelease(ddnsdict
);
5159 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BackToMyMac
);
5162 CFIndex size
= CFDictionaryGetCount(btmm
);
5163 const void *key
[size
];
5164 const void *val
[size
];
5165 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
5166 for (i
= 0; i
< size
; i
++)
5168 LogInfo("BackToMyMac %d", i
);
5169 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5170 LogMsg("Can't read BackToMyMac %d key %s", i
, buf
);
5173 mDNSu32 uid
= atoi(buf
);
5174 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5175 LogMsg("Can't read BackToMyMac %d val %s", i
, buf
);
5176 else if (MakeDomainNameFromDNSNameString(&d
, buf
) && d
.c
[0])
5178 LogInfo("BackToMyMac %d %d %##s", i
, uid
, d
.c
);
5179 AppendDNameListElem(&RegDomains
, uid
, &d
);
5187 if (setservers
|| setsearch
)
5189 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_DNS
);
5194 CFArrayRef values
= CFDictionaryGetValue(dict
, kSCPropNetDNSServerAddresses
);
5197 LogInfo("DNS Server Address values: %d", (int)CFArrayGetCount(values
));
5198 for (i
= 0; i
< CFArrayGetCount(values
); i
++)
5200 CFStringRef s
= CFArrayGetValueAtIndex(values
, i
);
5201 mDNSAddr addr
= { mDNSAddrType_IPv4
, { { { 0 } } } };
5202 if (s
&& CFStringGetCString(s
, buf
, 256, kCFStringEncodingUTF8
) &&
5203 inet_aton(buf
, (struct in_addr
*) &addr
.ip
.v4
))
5205 LogInfo("Adding DNS server from dict: %s", buf
);
5206 mDNS_AddDNSServer(m
, mDNSNULL
, mDNSInterface_Any
, &addr
, UnicastDNSPort
, mDNSfalse
);
5210 else LogInfo("No DNS Server Address values");
5214 // Add the manual and/or DHCP-dicovered search domains
5215 CFArrayRef searchDomains
= CFDictionaryGetValue(dict
, kSCPropNetDNSSearchDomains
);
5218 for (i
= 0; i
< CFArrayGetCount(searchDomains
); i
++)
5220 CFStringRef s
= CFArrayGetValueAtIndex(searchDomains
, i
);
5221 if (s
&& CFStringGetCString(s
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5222 mDNS_AddSearchDomain_CString(buf
);
5225 else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
5227 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
5228 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
5229 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
5230 // instead use the search domain list as the sole authority for what domains to search and in what order
5231 // (and the domain from the "domain" field will also appear somewhere in that list).
5232 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetDNSDomainName
);
5233 if (string
&& CFStringGetCString(string
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5234 mDNS_AddSearchDomain_CString(buf
);
5244 mDNSexport mStatus
mDNSPlatformGetPrimaryInterface(mDNS
*const m
, mDNSAddr
*v4
, mDNSAddr
*v6
, mDNSAddr
*r
)
5249 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL
, NULL
);
5251 LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5254 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_IPv4
);
5257 r
->type
= mDNSAddrType_IPv4
;
5258 r
->ip
.v4
= zerov4Addr
;
5259 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
5262 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
5263 LogMsg("Could not convert router to CString");
5266 struct sockaddr_in saddr
;
5267 saddr
.sin_len
= sizeof(saddr
);
5268 saddr
.sin_family
= AF_INET
;
5270 inet_aton(buf
, &saddr
.sin_addr
);
5272 *(in_addr_t
*)&r
->ip
.v4
= saddr
.sin_addr
.s_addr
;
5276 string
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
5279 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
5280 struct ifaddrs
*ifa
= myGetIfAddrs(1);
5282 *v4
= *v6
= zeroAddr
;
5284 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
)) { LogMsg("Could not convert router to CString"); goto exit
; }
5286 // find primary interface in list
5287 while (ifa
&& (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
) || !HavePrimaryGlobalv6
))
5289 mDNSAddr tmp6
= zeroAddr
;
5290 if (!strcmp(buf
, ifa
->ifa_name
))
5292 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
5294 if (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
)) SetupAddr(v4
, ifa
->ifa_addr
);
5296 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
5298 SetupAddr(&tmp6
, ifa
->ifa_addr
);
5299 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
5300 { HavePrimaryGlobalv6
= mDNStrue
; *v6
= tmp6
; }
5305 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
5306 if (!HavePrimaryGlobalv6
&& ifa
->ifa_addr
->sa_family
== AF_INET6
&& !v6
->ip
.v6
.b
[0])
5308 SetupAddr(&tmp6
, ifa
->ifa_addr
);
5309 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) *v6
= tmp6
;
5312 ifa
= ifa
->ifa_next
;
5315 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
5316 // V4 to communicate w/ our DNS server
5324 return mStatus_NoError
;
5327 mDNSexport
void mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
5329 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status
, dname
->c
);
5330 char uname
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
5331 ConvertDomainNameToCString(dname
, uname
);
5337 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
5341 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
5342 // That single entity is a CFDictionary with name "HostNames".
5343 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
5344 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
5345 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
5346 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
5347 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
5349 const CFStringRef StateKeys
[1] = { CFSTR("HostNames") };
5350 const CFStringRef HostKeys
[1] = { CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
) };
5351 const CFStringRef StatusKeys
[1] = { CFSTR("Status") };
5352 if (!HostKeys
[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname
);
5355 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
5356 if (!StatusVals
[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status
);
5359 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
5362 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
5365 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
5368 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig
, mDNSNULL
, StateDict
);
5369 CFRelease(StateDict
);
5371 CFRelease(StateVals
[0]);
5373 CFRelease(HostVals
[0]);
5375 CFRelease(StatusVals
[0]);
5377 CFRelease(HostKeys
[0]);
5381 #if APPLE_OSX_mDNSResponder
5384 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
5385 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
5387 mDNSlocal mDNSBool
IsBTMMDomain(domainname
*d
)
5389 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:IsBTMMDomain"), NULL
, NULL
);
5392 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5395 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BackToMyMac
);
5398 CFIndex size
= CFDictionaryGetCount(btmm
);
5399 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
5400 const void *key
[size
];
5401 const void *val
[size
];
5404 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
5405 for (i
= 0; i
< size
; i
++)
5407 LogInfo("BackToMyMac %d", i
);
5408 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5409 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i
, buf
);
5412 mDNSu32 uid
= atoi(buf
);
5413 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5414 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i
, buf
);
5415 else if (MakeDomainNameFromDNSNameString(&dom
, buf
) && dom
.c
[0])
5417 if (SameDomainName(&dom
, d
))
5419 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d
->c
, uid
);
5430 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d
->c
);
5434 // Appends data to the buffer
5435 mDNSlocal
int AddOneItem(char *buf
, int bufsz
, char *data
, int *currlen
)
5439 len
= strlcpy(buf
+ *currlen
, data
, bufsz
- *currlen
);
5440 if (len
>= (bufsz
- *currlen
))
5442 // if we have exceeded the space in buf, it has already been NULL terminated
5443 // and we have nothing more to do. Set currlen to the last byte so that the caller
5444 // knows to do the right thing
5445 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen
, len
);
5446 *currlen
= bufsz
- 1;
5449 else { (*currlen
) += len
; }
5451 buf
[*currlen
] = ',';
5452 if (*currlen
>= bufsz
)
5454 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen
);
5455 *currlen
= bufsz
- 1;
5459 // if we have filled up the buffer exactly, then there is no more work to do
5460 if (*currlen
== bufsz
- 1) { buf
[*currlen
] = 0; return -1; }
5465 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
5466 // BTMM domains, then bring down the connection to the relay.
5467 mDNSlocal
void UpdateBTMMRelayConnection(mDNS
*const m
)
5469 DomainAuthInfo
*BTMMDomain
= mDNSNULL
;
5470 DomainAuthInfo
*FoundInList
;
5471 static mDNSBool AWACSDConnected
= mDNSfalse
;
5472 char AllUsers
[1024]; // maximum size of mach message
5473 char AllPass
[1024]; // maximum size of mach message
5474 char username
[MAX_DOMAIN_LABEL
+ 1];
5478 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
5479 // we may not be able to send the dns queries over the relay connection which may be needed
5480 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
5481 // need to make sure that we send the disconnect before attempting the next connect as the
5482 // awacs connections are redirected based on usernames.
5484 // For now we send a disconnect immediately. When we start sending dns queries over the relay
5485 // connection, we will need to fix this.
5487 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
5488 if (!FoundInList
->deltime
&& FoundInList
->AutoTunnel
&& IsBTMMDomain(&FoundInList
->domain
))
5490 // We need the passwd from the first domain.
5491 BTMMDomain
= FoundInList
;
5492 ConvertDomainLabelToCString_unescaped((domainlabel
*)BTMMDomain
->domain
.c
, username
);
5493 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username
, BTMMDomain
->domain
.c
);
5494 if (AddOneItem(AllUsers
, sizeof(AllUsers
), username
, &currulen
) == -1) break;
5495 if (AddOneItem(AllPass
, sizeof(AllPass
), BTMMDomain
->b64keydata
, &currplen
) == -1) break;
5500 // In the normal case (where we neither exceed the buffer size nor write bytes that
5501 // fit exactly into the buffer), currulen/currplen should be a different size than
5502 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
5504 if (currulen
!= (int)(sizeof(AllUsers
) - 1)) AllUsers
[currulen
- 1] = 0;
5505 if (currplen
!= (int)(sizeof(AllPass
) - 1)) AllPass
[currplen
- 1] = 0;
5507 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers
);
5508 AWACS_Connect(AllUsers
, AllPass
, "hello.connectivity.me.com");
5509 AWACSDConnected
= mDNStrue
;
5513 // Disconnect only if we connected previously
5514 if (AWACSDConnected
)
5516 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
5518 AWACSDConnected
= mDNSfalse
;
5520 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
5524 mDNSlocal
void UpdateBTMMRelayConnection(mDNS
*const m
)
5527 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
5529 #endif // ! NO_AWACS
5530 #endif // APPLE_OSX_mDNSResponder
5532 // MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
5533 mDNSexport
void SetDomainSecrets(mDNS
*m
)
5535 #ifdef NO_SECURITYFRAMEWORK
5537 LogMsg("Note: SetDomainSecrets: no keychain support");
5539 mDNSBool haveAutoTunnels
= mDNSfalse
;
5541 LogInfo("SetDomainSecrets");
5543 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
5544 // In the case where the user simultaneously removes their DDNS host name and the key
5545 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
5546 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
5547 // address records behind that we no longer have permission to delete.
5548 DomainAuthInfo
*ptr
;
5549 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
5550 ptr
->deltime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
*10);
5552 #if APPLE_OSX_mDNSResponder
5554 // Mark all TunnelClients for deletion
5555 ClientTunnel
*client
;
5556 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
5558 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client
->dstname
.c
);
5559 client
->MarkedForDeletion
= mDNStrue
;
5562 #endif // APPLE_OSX_mDNSResponder
5564 // String Array used to write list of private domains to Dynamic Store
5565 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
5566 if (!sa
) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
5568 CFDataRef data
= NULL
;
5569 const int itemsPerEntry
= 3; // domain name, key name, key value
5570 CFArrayRef secrets
= NULL
;
5571 int err
= mDNSKeychainGetSecrets(&secrets
);
5572 if (err
|| !secrets
)
5573 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err
, secrets
);
5576 CFIndex ArrayCount
= CFArrayGetCount(secrets
);
5577 // Iterate through the secrets
5578 for (i
= 0; i
< ArrayCount
; ++i
)
5581 CFArrayRef entry
= CFArrayGetValueAtIndex(secrets
, i
);
5582 if (CFArrayGetTypeID() != CFGetTypeID(entry
) || itemsPerEntry
!= CFArrayGetCount(entry
))
5583 { LogMsg("SetDomainSecrets: malformed entry"); continue; }
5584 for (j
= 0; j
< CFArrayGetCount(entry
); ++j
)
5585 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry
, j
)))
5586 { LogMsg("SetDomainSecrets: malformed entry item"); continue; }
5588 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
5590 // Get DNS domain this key is for
5591 char stringbuf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal domainname as C-string, including terminating NUL
5592 data
= CFArrayGetValueAtIndex(entry
, 0);
5593 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
5594 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data
)); continue; }
5595 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
5596 stringbuf
[CFDataGetLength(data
)] = '\0';
5599 if (!MakeDomainNameFromDNSNameString(&domain
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf
); continue; }
5602 data
= CFArrayGetValueAtIndex(entry
, 1);
5603 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
5604 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data
)); continue; }
5605 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)stringbuf
);
5606 stringbuf
[CFDataGetLength(data
)] = '\0';
5609 if (!MakeDomainNameFromDNSNameString(&keyname
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf
); continue; }
5612 data
= CFArrayGetValueAtIndex(entry
, 2);
5613 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
5614 { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data
)); continue; }
5615 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
5616 stringbuf
[CFDataGetLength(data
)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
5618 DomainAuthInfo
*FoundInList
;
5619 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
5620 if (SameDomainName(&FoundInList
->domain
, &domain
)) break;
5622 #if APPLE_OSX_mDNSResponder
5625 // If any client tunnel destination is in this domain, set deletion flag to false
5626 ClientTunnel
*client
;
5627 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
5628 if (FoundInList
== GetAuthInfoForName_internal(m
, &client
->dstname
))
5630 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client
->dstname
.c
);
5631 client
->MarkedForDeletion
= mDNSfalse
;
5635 #endif // APPLE_OSX_mDNSResponder
5637 // Uncomment the line below to view the keys as they're read out of the system keychain
5638 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
5639 //LogInfo("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, stringbuf);
5641 // If didn't find desired domain in the list, make a new entry
5643 if (FoundInList
&& FoundInList
->AutoTunnel
&& haveAutoTunnels
== mDNSfalse
) haveAutoTunnels
= mDNStrue
;
5646 ptr
= (DomainAuthInfo
*)mallocL("DomainAuthInfo", sizeof(*ptr
));
5647 if (!ptr
) { LogMsg("SetDomainSecrets: No memory"); continue; }
5650 LogInfo("SetDomainSecrets: %d of %d %##s", i
, ArrayCount
, &domain
);
5651 if (mDNS_SetSecretForDomain(m
, ptr
, &domain
, &keyname
, stringbuf
, IsTunnelModeDomain(&domain
)) == mStatus_BadParamErr
)
5653 if (!FoundInList
) mDNSPlatformMemFree(ptr
); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
5657 #if APPLE_OSX_mDNSResponder
5658 if (ptr
->AutoTunnel
) UpdateAutoTunnelDomainStatus(m
, ptr
);
5659 #endif // APPLE_OSX_mDNSResponder
5661 ConvertDomainNameToCString(&domain
, stringbuf
);
5662 CFStringRef cfs
= CFStringCreateWithCString(NULL
, stringbuf
, kCFStringEncodingUTF8
);
5663 if (cfs
) { CFArrayAppendValue(sa
, cfs
); CFRelease(cfs
); }
5667 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, mDNSNULL
, sa
);
5670 #if APPLE_OSX_mDNSResponder
5672 // clean up ClientTunnels
5673 ClientTunnel
**pp
= &m
->TunnelClients
;
5676 if ((*pp
)->MarkedForDeletion
)
5678 ClientTunnel
*cur
= *pp
;
5679 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur
, cur
->dstname
.c
);
5680 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
5681 AutoTunnelSetKeys(cur
, mDNSfalse
);
5683 freeL("ClientTunnel", cur
);
5689 DomainAuthInfo
*info
= m
->AuthInfoList
;
5692 if (info
->AutoTunnel
&& info
->deltime
)
5694 if (info
->AutoTunnelNAT
.clientContext
)
5696 // stop the NAT operation
5697 mDNS_StopNATOperation_internal(m
, &info
->AutoTunnelNAT
);
5698 if (info
->AutoTunnelNAT
.clientCallback
)
5700 // Reset port and cleanup the state
5701 info
->AutoTunnelNAT
.ExternalAddress
= m
->ExternalAddress
;
5702 info
->AutoTunnelNAT
.ExternalPort
= zeroIPPort
;
5703 info
->AutoTunnelNAT
.RequestedPort
= zeroIPPort
;
5704 info
->AutoTunnelNAT
.Lifetime
= 0;
5705 info
->AutoTunnelNAT
.Result
= mStatus_NoError
;
5706 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
5707 AutoTunnelDeleteAuthInfoState(m
, info
);
5708 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
5710 info
->AutoTunnelNAT
.clientContext
= mDNSNULL
;
5712 RemoveAutoTunnelDomainStatus(m
, info
);
5717 if (!haveAutoTunnels
&& !m
->TunnelClients
&& m
->AutoTunnelHostAddrActive
)
5719 // remove interface if no autotunnel servers and no more client tunnels
5720 LogInfo("SetDomainSecrets: Bringing tunnel interface DOWN");
5721 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
5722 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
5723 mDNSPlatformMemZero(m
->AutoTunnelHostAddr
.b
, sizeof(m
->AutoTunnelHostAddr
.b
));
5726 if (m
->AutoTunnelHostAddr
.b
[0])
5727 if (TunnelClients(m
) || TunnelServers(m
))
5728 SetupLocalAutoTunnelInterface_internal(m
, mDNSfalse
);
5730 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
5731 UpdateBTMMRelayConnection(m
);
5733 #endif // APPLE_OSX_mDNSResponder
5735 CheckSuppressUnusableQuestions(m
);
5737 #endif /* NO_SECURITYFRAMEWORK */
5740 mDNSlocal
void SetLocalDomains(void)
5742 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
5743 if (!sa
) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
5745 CFArrayAppendValue(sa
, CFSTR("local"));
5746 CFArrayAppendValue(sa
, CFSTR("254.169.in-addr.arpa"));
5747 CFArrayAppendValue(sa
, CFSTR("8.e.f.ip6.arpa"));
5748 CFArrayAppendValue(sa
, CFSTR("9.e.f.ip6.arpa"));
5749 CFArrayAppendValue(sa
, CFSTR("a.e.f.ip6.arpa"));
5750 CFArrayAppendValue(sa
, CFSTR("b.e.f.ip6.arpa"));
5752 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig
, mDNSNULL
, sa
);
5756 mDNSlocal
void GetCurrentPMSetting(const CFStringRef name
, mDNSs32
*val
)
5758 #if USE_IOPMCOPYACTIVEPMPREFERENCES
5759 CFTypeRef blob
= NULL
;
5760 CFStringRef str
= NULL
;
5761 CFDictionaryRef odict
= NULL
;
5762 CFDictionaryRef idict
= NULL
;
5763 CFNumberRef number
= NULL
;
5765 blob
= IOPSCopyPowerSourcesInfo();
5766 if (!blob
) { LogMsg("GetCurrentPMSetting: IOPSCopyPowerSourcesInfo failed!"); goto end
; }
5768 odict
= IOPMCopyActivePMPreferences();
5769 if (!odict
) { LogMsg("GetCurrentPMSetting: IOPMCopyActivePMPreferences failed!"); goto end
; }
5771 str
= IOPSGetProvidingPowerSourceType(blob
);
5772 if (!str
) { LogMsg("GetCurrentPMSetting: IOPSGetProvidingPowerSourceType failed!"); goto end
; }
5774 idict
= CFDictionaryGetValue(odict
, str
);
5778 if (!CFStringGetCString(str
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
5779 LogMsg("GetCurrentPMSetting: CFDictionaryGetValue (%s) failed!", buf
);
5783 number
= CFDictionaryGetValue(idict
, name
);
5784 if (!number
|| CFGetTypeID(number
) != CFNumberGetTypeID() || !CFNumberGetValue(number
, kCFNumberSInt32Type
, val
))
5787 if (blob
) CFRelease(blob
);
5788 if (odict
) CFRelease(odict
);
5792 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetCurrentPMSetting"), NULL
, NULL
);
5793 if (!store
) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5796 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_PowerSettings
);
5797 if (!dict
) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
5800 CFNumberRef number
= CFDictionaryGetValue(dict
, name
);
5801 if (!number
|| CFGetTypeID(number
) != CFNumberGetTypeID() || !CFNumberGetValue(number
, kCFNumberSInt32Type
, val
))
5811 #if APPLE_OSX_mDNSResponder
5813 static CFMutableDictionaryRef spsStatusDict
= NULL
;
5814 static const CFStringRef kMetricRef
= CFSTR("Metric");
5816 mDNSlocal
void SPSStatusPutNumber(CFMutableDictionaryRef dict
, const mDNSu8
* const ptr
, CFStringRef key
)
5818 mDNSu8 tmp
= (ptr
[0] - '0') * 10 + ptr
[1] - '0';
5819 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt8Type
, &tmp
);
5821 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
5824 CFDictionarySetValue(dict
, key
, num
);
5829 mDNSlocal CFMutableDictionaryRef
SPSCreateDict(const mDNSu8
* const ptr
)
5831 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
5832 if (!dict
) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict
; }
5835 buffer
[mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", ptr
) - 1] = 0;
5836 CFStringRef spsname
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
5837 if (!spsname
) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict
); return NULL
; }
5838 CFDictionarySetValue(dict
, CFSTR("FullName"), spsname
);
5841 if (ptr
[0] >= 2) SPSStatusPutNumber(dict
, ptr
+ 1, CFSTR("Type"));
5842 if (ptr
[0] >= 5) SPSStatusPutNumber(dict
, ptr
+ 4, CFSTR("Portability"));
5843 if (ptr
[0] >= 8) SPSStatusPutNumber(dict
, ptr
+ 7, CFSTR("MarginalPower"));
5844 if (ptr
[0] >= 11) SPSStatusPutNumber(dict
, ptr
+10, CFSTR("TotalPower"));
5846 mDNSu32 tmp
= SPSMetric(ptr
);
5847 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tmp
);
5849 LogMsg("SPSCreateDict: Could not create CFNumber");
5852 CFDictionarySetValue(dict
, kMetricRef
, num
);
5858 memcpy(buffer
, ptr
+ 13, ptr
[0] - 12);
5859 buffer
[ptr
[0] - 12] = 0;
5860 spsname
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
5861 if (!spsname
) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict
); return NULL
; }
5864 CFDictionarySetValue(dict
, CFSTR("PrettyName"), spsname
);
5872 mDNSlocal CFComparisonResult
CompareSPSEntries(const void *val1
, const void *val2
, void *context
)
5875 return CFNumberCompare((CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val1
, kMetricRef
),
5876 (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val2
, kMetricRef
),
5880 mDNSlocal
void UpdateSPSStatus(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
5882 NetworkInterfaceInfo
* info
= (NetworkInterfaceInfo
*)question
->QuestionContext
;
5883 debugf("UpdateSPSStatus: %s %##s %s %s", info
->ifname
, question
->qname
.c
, AddRecord
? "Add" : "Rmv", answer
? RRDisplayString(m
, answer
) : "<null>");
5886 mDNS_UpdateAllowSleep(m
);
5889 if (answer
&& SPSMetric(answer
->rdata
->u
.name
.c
) > 999999) return; // Ignore instances with invalid names
5893 spsStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
5894 if (!spsStatusDict
) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
5897 CFStringRef ifname
= CFStringCreateWithCString(NULL
, info
->ifname
, kCFStringEncodingUTF8
);
5898 if (!ifname
) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
5900 CFMutableArrayRef array
= NULL
;
5902 if (!CFDictionaryGetValueIfPresent(spsStatusDict
, ifname
, (const void**) &array
))
5904 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
5905 if (!array
) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname
); return; }
5906 CFDictionarySetValue(spsStatusDict
, ifname
, array
);
5907 CFRelease(array
); // let go of our reference, now that the dict has one
5910 if (!array
) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info
->ifname
); CFRelease(ifname
); return; }
5912 if (!answer
) // special call that means the question has been stopped (because the interface is going away)
5913 CFArrayRemoveAllValues(array
);
5916 CFMutableDictionaryRef dict
= SPSCreateDict(answer
->rdata
->u
.name
.c
);
5917 if (!dict
) { CFRelease(ifname
); return; }
5921 if (!CFArrayContainsValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), dict
))
5924 for (i
=0; i
<CFArrayGetCount(array
); i
++)
5925 if (CompareSPSEntries(CFArrayGetValueAtIndex(array
, i
), dict
, NULL
) != kCFCompareLessThan
)
5927 CFArrayInsertValueAtIndex(array
, i
, dict
);
5929 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info
->ifname
, answer
->rdata
->u
.name
.c
);
5933 CFIndex i
= CFArrayGetFirstIndexOfValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), dict
);
5934 if (i
!= -1) CFArrayRemoveValueAtIndex(array
, i
);
5935 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info
->ifname
, answer
->rdata
->u
.name
.c
);
5941 if (!m
->ShutdownTime
) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState
, info
->ifname
, array
);
5946 mDNSlocal mDNSs32
GetSystemSleepTimerSetting(void)
5949 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL
, NULL
);
5951 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5954 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_PowerSettings
);
5957 CFNumberRef number
= CFDictionaryGetValue(dict
, CFSTR("System Sleep Timer"));
5958 if (number
) CFNumberGetValue(number
, kCFNumberSInt32Type
, &val
);
5966 mDNSlocal
void SetSPS(mDNS
*const m
)
5968 SCPreferencesSynchronize(m
->p
->SCPrefs
);
5969 CFDictionaryRef dict
= SCPreferencesGetValue(m
->p
->SCPrefs
, CFSTR("NAT"));
5970 mDNSBool natenabled
= (dict
&& (CFGetTypeID(dict
) == CFDictionaryGetTypeID()) && DictionaryIsEnabled(dict
));
5971 mDNSu8 sps
= natenabled
? 50 : (OfferSleepProxyService
&& GetSystemSleepTimerSetting() == 0) ? OfferSleepProxyService
: 0;
5973 // For devices that are not running NAT, but are set to never sleep, we may choose to act
5974 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
5975 if (sps
> 50 && SPMetricPortability
> 35) sps
= 0;
5977 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
5979 // For devices that are unable to sleep at all to save power (e.g. the current Apple TV hardware)
5980 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
5981 // We rate such a device as metric 70 ("Incidentally Available Hardware")
5982 if (SPMetricMarginalPower
== 10 && (!sps
|| sps
> 70)) sps
= 70;
5984 mDNSCoreBeSleepProxyServer(m
, sps
, SPMetricPortability
, SPMetricMarginalPower
, SPMetricTotalPower
);
5987 mDNSlocal
void InternetSharingChanged(SCPreferencesRef prefs
, SCPreferencesNotification notificationType
, void *context
)
5989 (void)prefs
; // Parameter not used
5990 (void)notificationType
; // Parameter not used
5991 mDNS
*const m
= (mDNS
*const)context
;
5995 // Tell platform layer to open or close its BPF fds
5996 if (!m
->p
->NetworkChanged
||
5997 m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2) < 0)
5999 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2);
6000 LogInfo("InternetSharingChanged: Set NetworkChanged to %d (%d)", m
->p
->NetworkChanged
- m
->timenow
, m
->p
->NetworkChanged
);
6004 KQueueUnlock(m
, "InternetSharingChanged");
6007 mDNSlocal mStatus
WatchForInternetSharingChanges(mDNS
*const m
)
6009 SCPreferencesRef SCPrefs
= SCPreferencesCreate(NULL
, CFSTR("mDNSResponder:WatchForInternetSharingChanges"), CFSTR("com.apple.nat.plist"));
6010 if (!SCPrefs
) { LogMsg("SCPreferencesCreate failed: %s", SCErrorString(SCError())); return(mStatus_NoMemoryErr
); }
6012 SCPreferencesContext context
= { 0, m
, NULL
, NULL
, NULL
};
6013 if (!SCPreferencesSetCallback(SCPrefs
, InternetSharingChanged
, &context
))
6014 { LogMsg("SCPreferencesSetCallback failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs
); return(mStatus_NoMemoryErr
); }
6016 #ifdef __LIB_DISPATCH__
6017 if (!SCPreferencesSetDispatchQueue( SCPrefs
, dispatch_get_main_queue()))
6018 { LogMsg("SCPreferencesSetDispatchQueue failed: %s", SCErrorString(SCError())); return(mStatus_NoMemoryErr
); }
6020 if (!SCPreferencesScheduleWithRunLoop(SCPrefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
))
6021 { LogMsg("SCPreferencesScheduleWithRunLoop failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs
); return(mStatus_NoMemoryErr
); }
6024 m
->p
->SCPrefs
= SCPrefs
;
6025 return(mStatus_NoError
);
6028 // The definitions below should eventually come from some externally-supplied header file.
6029 // However, since these definitions can't really be changed without breaking binary compatibility,
6030 // they should never change, so in practice it should not be a big problem to have them defined here.
6032 #define mDNS_IOREG_KEY "mDNS_KEY"
6033 #define mDNS_IOREG_VALUE "2009-07-30"
6034 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
6037 { // commands from the daemon to the driver
6038 cmd_mDNSOffloadRR
= 21, // give the mdns update buffer to the driver
6041 typedef union { void *ptr
; mDNSOpaque64 sixtyfourbits
; } FatPtr
;
6044 { // cmd_mDNSOffloadRR structure
6045 uint32_t command
; // set to OffloadRR
6046 uint32_t rrBufferSize
; // number of bytes of RR records
6047 uint32_t numUDPPorts
; // number of SRV UDP ports
6048 uint32_t numTCPPorts
; // number of SRV TCP ports
6049 uint32_t numRRRecords
; // number of RR records
6050 uint32_t compression
; // rrRecords - compression is base for compressed strings
6051 FatPtr rrRecords
; // address of array of pointers to the rr records
6052 FatPtr udpPorts
; // address of udp port list (SRV)
6053 FatPtr tcpPorts
; // address of tcp port list (SRV)
6056 #include <IOKit/IOKitLib.h>
6057 #include <dns_util.h>
6059 mDNSlocal mDNSu16
GetPortArray(mDNS
*const m
, int trans
, mDNSIPPort
*portarray
)
6061 const domainlabel
*const tp
= (trans
== mDNSTransport_UDP
) ? (const domainlabel
*)"\x4_udp" : (const domainlabel
*)"\x4_tcp";
6064 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6065 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainLabel(ThirdLabel(rr
->resrec
.name
)->c
, tp
->c
))
6067 if (portarray
) portarray
[count
] = rr
->resrec
.rdata
->u
.srv
.port
;
6071 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
6072 if (trans
== mDNSTransport_UDP
&& TunnelServers(m
))
6074 LogSPS("GetPortArray Back to My Mac at %d", count
);
6075 if (portarray
) portarray
[count
] = IPSECPort
;
6081 #define TfrRecordToNIC(RR) \
6082 (((RR)->resrec.InterfaceID && (RR)->resrec.InterfaceID != mDNSInterface_LocalOnly) || \
6083 (!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
6085 mDNSlocal mDNSu32
CountProxyRecords(mDNS
*const m
, uint32_t *const numbytes
)
6090 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6091 if (rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
6092 if (TfrRecordToNIC(rr
))
6094 *numbytes
+= DomainNameLength(rr
->resrec
.name
) + 10 + rr
->resrec
.rdestimate
;
6095 LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
6096 count
, DomainNameLength(rr
->resrec
.name
) + 10 + rr
->resrec
.rdestimate
, *numbytes
, ARDisplayString(m
,rr
));
6102 mDNSlocal
void GetProxyRecords(mDNS
*const m
, DNSMessage
*const msg
, uint32_t *const numbytes
, FatPtr
*const records
)
6104 mDNSu8
*p
= msg
->data
;
6105 const mDNSu8
*const limit
= p
+ *numbytes
;
6106 InitializeDNSMessage(&msg
->h
, zeroID
, zeroID
);
6110 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6111 if (rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
6112 if (TfrRecordToNIC(rr
))
6114 records
[count
].sixtyfourbits
= zeroOpaque64
;
6115 records
[count
].ptr
= p
;
6116 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
6117 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the 'unique' bit so PutResourceRecord will set it
6118 p
= PutResourceRecordTTLWithLimit(msg
, p
, &msg
->h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
, limit
);
6119 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear 'unique' bit back to normal state
6120 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
6121 count
, records
[count
].ptr
, p
, p
- (mDNSu8
*)records
[count
].ptr
, p
- msg
->data
, ARDisplayString(m
,rr
));
6124 *numbytes
= p
- msg
->data
;
6127 // If compiling with old headers and libraries (pre 10.5) that don't include IOConnectCallStructMethod
6128 // then we declare a dummy version here so that the code at least compiles
6129 #ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
6130 static kern_return_t
6131 IOConnectCallStructMethod(
6132 mach_port_t connection
, // In
6133 uint32_t selector
, // In
6134 const void *inputStruct
, // In
6135 size_t inputStructCnt
, // In
6136 void *outputStruct
, // Out
6137 size_t *outputStructCnt
) // In/Out
6142 (void)inputStructCnt
;
6144 (void)outputStructCnt
;
6145 LogMsg("Compiled without IOConnectCallStructMethod");
6146 return(KERN_FAILURE
);
6150 mDNSexport mStatus
ActivateLocalProxy(mDNS
*const m
, char *ifname
) // Called with the lock held
6152 mStatus result
= mStatus_UnknownErr
;
6153 io_service_t service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOBSDNameMatching(kIOMasterPortDefault
, 0, ifname
));
6154 if (!service
) { LogMsg("ActivateLocalProxy: No service for interface %s", ifname
); return(mStatus_UnknownErr
); }
6157 IOObjectGetClass(service
, n1
);
6159 kern_return_t kr
= IORegistryEntryGetParentEntry(service
, kIOServicePlane
, &parent
);
6160 if (kr
!= KERN_SUCCESS
) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", ifname
, n1
, kr
);
6163 IOObjectGetClass(parent
, n2
);
6164 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", ifname
, n1
, n2
);
6165 const CFTypeRef ref
= IORegistryEntryCreateCFProperty(parent
, CFSTR(mDNS_IOREG_KEY
), kCFAllocatorDefault
, mDNSNULL
);
6166 if (!ref
) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", ifname
, n1
, n2
);
6169 if (CFGetTypeID(ref
) != CFStringGetTypeID() || !CFEqual(ref
, CFSTR(mDNS_IOREG_VALUE
)))
6170 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
6171 ifname
, n1
, n2
, CFStringGetCStringPtr(ref
, mDNSNULL
), mDNS_IOREG_VALUE
);
6174 io_connect_t conObj
;
6175 kr
= IOServiceOpen(parent
, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE
, &conObj
);
6176 if (kr
!= KERN_SUCCESS
) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", ifname
, n1
, n2
, kr
);
6180 mDNSPlatformMemZero(&cmd
, sizeof(cmd
)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
6181 cmd
.command
= cmd_mDNSOffloadRR
;
6182 cmd
.numUDPPorts
= GetPortArray(m
, mDNSTransport_UDP
, mDNSNULL
);
6183 cmd
.numTCPPorts
= GetPortArray(m
, mDNSTransport_TCP
, mDNSNULL
);
6184 cmd
.numRRRecords
= CountProxyRecords(m
, &cmd
.rrBufferSize
);
6185 cmd
.compression
= sizeof(DNSMessageHeader
);
6187 DNSMessage
*msg
= (DNSMessage
*)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader
) + cmd
.rrBufferSize
);
6188 cmd
.rrRecords
.ptr
= mallocL("mDNSOffloadCmd rrRecords", cmd
.numRRRecords
* sizeof(FatPtr
));
6189 cmd
.udpPorts
.ptr
= mallocL("mDNSOffloadCmd udpPorts", cmd
.numUDPPorts
* sizeof(mDNSIPPort
));
6190 cmd
.tcpPorts
.ptr
= mallocL("mDNSOffloadCmd tcpPorts", cmd
.numTCPPorts
* sizeof(mDNSIPPort
));
6192 LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
6193 msg
, cmd
.rrBufferSize
,
6194 cmd
.rrRecords
.ptr
, cmd
.numRRRecords
,
6195 cmd
.udpPorts
.ptr
, cmd
.numUDPPorts
,
6196 cmd
.tcpPorts
.ptr
, cmd
.numTCPPorts
);
6198 if (!msg
|| !cmd
.rrRecords
.ptr
|| !cmd
.udpPorts
.ptr
|| !cmd
.tcpPorts
.ptr
)
6199 LogMsg("ActivateLocalProxy: Failed to allocate memory: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
6200 msg
, cmd
.rrBufferSize
,
6201 cmd
.rrRecords
.ptr
, cmd
.numRRRecords
,
6202 cmd
.udpPorts
.ptr
, cmd
.numUDPPorts
,
6203 cmd
.tcpPorts
.ptr
, cmd
.numTCPPorts
);
6206 GetProxyRecords(m
, msg
, &cmd
.rrBufferSize
, cmd
.rrRecords
.ptr
);
6207 GetPortArray(m
, mDNSTransport_UDP
, cmd
.udpPorts
.ptr
);
6208 GetPortArray(m
, mDNSTransport_TCP
, cmd
.tcpPorts
.ptr
);
6210 size_t outputDataSize
= sizeof(outputData
);
6211 kr
= IOConnectCallStructMethod(conObj
, 0, &cmd
, sizeof(cmd
), outputData
, &outputDataSize
);
6212 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", ifname
, n1
, n2
, kr
);
6213 if (kr
== KERN_SUCCESS
) result
= mStatus_NoError
;
6216 if (cmd
.tcpPorts
. ptr
) freeL("mDNSOffloadCmd udpPorts", cmd
.tcpPorts
.ptr
);
6217 if (cmd
.udpPorts
. ptr
) freeL("mDNSOffloadCmd tcpPorts", cmd
.udpPorts
.ptr
);
6218 if (cmd
.rrRecords
.ptr
) freeL("mDNSOffloadCmd rrRecords", cmd
.rrRecords
.ptr
);
6219 if (msg
) freeL("mDNSOffloadCmd msg", msg
);
6220 IOServiceClose(conObj
);
6225 IOObjectRelease(parent
);
6227 IOObjectRelease(service
);
6231 #endif // APPLE_OSX_mDNSResponder
6233 static io_service_t g_rootdomain
= MACH_PORT_NULL
;
6235 mDNSlocal mDNSBool
SystemWakeForNetworkAccess(void)
6238 CFBooleanRef clamshellStop
= NULL
;
6239 mDNSBool retnow
= mDNSfalse
;
6241 if (DisableSleepProxyClient
) { LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option"); return mDNSfalse
; }
6243 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val
);
6244 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", val
);
6245 if (!val
) return mDNSfalse
;
6247 if (!g_rootdomain
) g_rootdomain
= IORegistryEntryFromPath(MACH_PORT_NULL
, kIOPowerPlane
":/IOPowerConnection/IOPMrootDomain");
6248 if (!g_rootdomain
) { LogMsg("SystemWakeForNetworkAccess: IORegistryEntryFromPath failed; assuming no clamshell so can WOMP"); return mDNStrue
; }
6250 clamshellStop
= (CFBooleanRef
)IORegistryEntryCreateCFProperty(g_rootdomain
, CFSTR(kAppleClamshellStateKey
), kCFAllocatorDefault
, 0);
6251 if (!clamshellStop
) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue
; }
6252 retnow
= clamshellStop
== kCFBooleanFalse
;
6253 CFRelease(clamshellStop
);
6254 if (retnow
) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey is false; clamshell is open so can WOMP"); return mDNStrue
; }
6256 clamshellStop
= (CFBooleanRef
)IORegistryEntryCreateCFProperty(g_rootdomain
, CFSTR(kAppleClamshellCausesSleepKey
), kCFAllocatorDefault
, 0);
6257 if (!clamshellStop
) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue
; }
6258 retnow
= (clamshellStop
== kCFBooleanFalse
);
6259 CFRelease(clamshellStop
);
6260 if (retnow
) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey is false; clamshell is closed but can WOMP"); return mDNStrue
; }
6262 LogSPS("SystemWakeForNetworkAccess: clamshell is closed and can't WOMP");
6266 mDNSlocal mDNSBool
SystemSleepOnlyIfWakeOnLAN(void)
6269 GetCurrentPMSetting(CFSTR("Idle Sleep Requires Network Proxy"), &val
);
6270 return val
!= 0 ? mDNStrue
: mDNSfalse
;
6273 #if APPLE_OSX_mDNSResponder
6274 // If the _autotunnel6 record is still there in the list, we are waiting for the ack from
6277 // If we are behind a double-NAT or NAT with no NAT-PMP support, we should make sure that all our
6278 // BTMM records are deregistered so that it does not appear on the Finder sidebar of our peers
6279 // when we go to sleep. First _autotunnel6 and the host record gets deregistered, then SRV
6280 // (UpdateAllSrvRecords) and then PTR and TXT
6282 // Note: We wait up to a maximum of 10 seconds before we ack the sleep. So, returning "false"
6283 // here does not necessarily mean that it will be honored.
6284 mDNSexport mDNSBool
RecordReadyForSleep(mDNS
*const m
, AuthRecord
*rr
)
6286 if (!AuthRecord_uDNS(rr
)) return mDNStrue
;
6288 if (SameDomainLabel(rr
->namestorage
.c
, (const mDNSu8
*)"\x0c_autotunnel6"))
6290 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m
, rr
));
6293 // Just check for the SRV record alone as the PTR and TXT records are dependent on SRV
6294 // and will get deregistered together in a single update. We also don't check for TXT
6295 // records as _kerberos TXT record is always there even when there are no services
6296 // and we don't want to delay the sleep in that case.
6297 if (mDNSIPPortIsZero(m
->LLQNAT
.ExternalPort
) || m
->LLQNAT
.Result
)
6299 if ((rr
->resrec
.rrtype
== kDNSType_SRV
) && rr
->state
!= regState_NoTarget
&& rr
->zone
)
6301 DomainAuthInfo
*info
= GetAuthInfoForName_internal(m
, rr
->zone
);
6302 if (info
&& info
->AutoTunnel
)
6304 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m
, rr
));
6312 // Note: BTMMDict needs to be retained by the caller if needed
6313 mDNSlocal CFDictionaryRef
ParseBackToMyMacKey(CFDictionaryRef connd
)
6315 CFDictionaryRef BTMMDict
= CFDictionaryGetValue(connd
, CFSTR("BackToMyMac"));
6318 LogInfo("ParseBackToMyMacKey: CFDictionaryGetValue No value for BackToMyMac");
6322 // Non-dictionary is treated as non-existent dictionary
6323 if (CFGetTypeID(BTMMDict
) != CFDictionaryGetTypeID())
6324 {LogMsg("ERROR: ParseBackToMyMacKey: CFDictionaryGetValue BackToMyMac not a dictionary"); CFRelease(BTMMDict
); return NULL
;}
6329 mDNSlocal
void ParseBTMMInterfaceKey(CFDictionaryRef BTMMDict
, char *buf
, int buflen
)
6334 ifExists
= CFDictionaryGetValueIfPresent(BTMMDict
, CFSTR("Interface"), &string
);
6337 if (!CFStringGetCString(string
, buf
, buflen
, kCFStringEncodingUTF8
))
6339 LogMsg("ERROR: ParseBTMMInterfaceKey: Could not convert Interface to CString");
6340 if (buflen
) buf
[0] = 0;
6344 debugf("ParseBTMMInterfaceKey: Interface Key exists %s", buf
);
6348 if (buflen
) buf
[0] = 0;
6349 debugf("ParseBTMMInterfaceKey: Interface Key does not exist");
6353 mDNSexport
void RemoveAutoTunnel6Record(mDNS
*const m
)
6355 DomainAuthInfo
*info
;
6358 // Did we parse a non-empty dictionary before ?
6359 if (!m
->p
->ConndBTMMDict
|| (CFDictionaryGetCount(m
->p
->ConndBTMMDict
) == 0))
6361 LogInfo("RemoveAutoTunnel6Record: Never registered any records before, not deregistering %p", m
->p
->ConndBTMMDict
);
6365 // Did we have a non-NULL Interface name before ?
6366 ParseBTMMInterfaceKey(m
->p
->ConndBTMMDict
, buf
, sizeof(buf
));
6369 LogInfo("RemoveAutoTunnel6Record: Interface name already NULL, not deregistering");
6373 // Set the address to zero before calling DeregisterAutoTunnel6Record. If we call
6374 // Deregister too quickly before the previous Register completed (just scheduled
6375 // to be sent out) and when DeregisterAutoTunnel6Record calls mDNS_Register_internal,
6376 // it invokes the AutoTunnelRecordCallback immediately and AutoTunnelRelayAddrIn should
6377 // be zero so that we don't register again.
6378 m
->AutoTunnelRelayAddrIn
= zerov6Addr
;
6379 if (!m
->AuthInfoList
) LogInfo("RemoveAutoTunnel6Record: No Domain AuthInfo");
6380 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
6382 if (!info
->AutoTunnel
) { LogInfo("RemoveAutoTunnel6Record: Domain %##s not an AutoTunnel", info
->domain
.c
); continue;}
6384 if (info
->deltime
) {LogInfo("RemoveAutoTunnel6Record: Domain %##s about to be deleted", info
->domain
.c
); continue;}
6386 LogInfo("RemoveAutoTunnel6Record: Deregistering records for domain %##s", info
->domain
.c
);
6387 DeregisterAutoTunnel6Record(m
, info
);
6389 CFRelease(m
->p
->ConndBTMMDict
);
6390 m
->p
->ConndBTMMDict
= NULL
;
6393 // Returns zero on success
6394 mDNSlocal
int GetIPv6AddressForIfname(char *ifname
, mDNSv6Addr
*ipv6Addr
)
6396 struct ifaddrs
*ifa
;
6397 struct ifaddrs
*ifaddrs
;
6400 if (if_nametoindex(ifname
) == 0) {LogInfo("GetIPv6AddressForIfname: Invalid name %s", ifname
); return (-1);}
6402 if (getifaddrs(&ifaddrs
) < 0) {LogInfo("GetIPv6AddressForIfname: getifaddrs failed"); return (-1);}
6405 * Find the ifaddr entry corresponding to the interface name,
6406 * and return the first matching non-linklocal IPv6 address.
6408 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
6410 if (strncmp(ifa
->ifa_name
, ifname
, IFNAMSIZ
) != 0)
6412 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
&& ifa
->ifa_addr
->sa_family
== AF_INET6
)
6414 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
6415 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
))
6417 if (SetupAddr(&addr
, ifa
->ifa_addr
) != mStatus_NoError
)
6419 LogInfo("GetIPv6AddressForIfname: SetupAddr error, continuing to the next address");
6424 *ipv6Addr
= *(mDNSv6Addr
*)&addr
.ip
.v6
;
6425 LogInfo("GetIPv6AddressForIfname: Returning IPv6 address %.16a", ipv6Addr
);
6426 freeifaddrs(ifaddrs
);
6431 LogInfo("GetIPv6AddressForIfname: No Valid IPv6 address");
6432 freeifaddrs(ifaddrs
);
6436 mDNSlocal
void AddAutoTunnel6Record(mDNS
*const m
, char *ifname
, CFDictionaryRef BTMMDict
)
6439 DomainAuthInfo
*info
;
6441 if (GetIPv6AddressForIfname(ifname
, &v6addr
) != 0)
6443 LogInfo("AddAutoTunnel6Record: No Valid IPv6 addresses found for %s", ifname
);
6444 // If the interface does not exist but the dictionary has the value, we treat
6445 // this case as though the dictionary does not have the value
6446 RemoveAutoTunnel6Record(m
);
6447 // If awacsd crashes or exits for some reason, restart the relay connection
6448 UpdateBTMMRelayConnection(m
);
6452 m
->AutoTunnelRelayAddrOut
= v6addr
;
6454 // if disabled administratively, don't bother to register. RegisterAutoTunnel6Record makes these same
6455 // checks, but we do it here not just as an optimization but mainly to keep AutoTunnelRelayAddrIn zero
6456 // as a non-zero AutoTunnelRelayAddrIn indicates that we have registered _autotunnel6 record and hence
6457 // other hosts can connect to this host through the relay
6458 if (!m
->RegisterAutoTunnel6
|| DisableInboundRelayConnection
)
6460 LogInfo("RegisterAutoTunnel6Record: registration Disabled RegisterAutoTunnel6 %d, DisableInbound %d",
6461 m
->RegisterAutoTunnel6
, DisableInboundRelayConnection
);
6464 m
->AutoTunnelRelayAddrIn
= v6addr
;
6466 if (!m
->AuthInfoList
) LogInfo("AddAutoTunnel6Record: No Domain AuthInfo");
6467 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
6469 // clientContext for a domain tells us that we are listening for at least one Service/Record
6470 // in a domain and SetLocalAutoTunnelInterface_internal was called
6471 if (!info
->AutoTunnel
) { LogInfo("AddAutoTunnel6Record: Domain %##s not an AutoTunnel", info
->domain
.c
); continue;}
6473 if (!info
->AutoTunnelNAT
.clientContext
) {LogInfo("AddAutoTunnel6Record: Domain %##s has no services", info
->domain
.c
); continue;}
6475 if (info
->deltime
) {LogInfo("AddAutoTunnel6Record: Domain %##s about to be deleted", info
->domain
.c
); continue;}
6477 LogInfo("AddAutoTunnel6Record: Registering records for domain %##s", info
->domain
.c
);
6479 RegisterAutoTunnel6Record(m
, info
);
6482 if (m
->p
->ConndBTMMDict
) CFRelease(m
->p
->ConndBTMMDict
);
6483 m
->p
->ConndBTMMDict
= CFRetain(BTMMDict
);
6486 mDNSlocal
void ParseBackToMyMac(mDNS
*const m
, CFDictionaryRef connd
)
6488 CFDictionaryRef BTMMDict
;
6491 BTMMDict
= ParseBackToMyMacKey(connd
);
6494 LogInfo("ParseBackToMyMac: CFDictionaryGetValue No value for BackToMyMac, Removing autotunnel6");
6495 RemoveAutoTunnel6Record(m
);
6496 // Note: AutoTunnelRelayAddrIn is zeroed out in RemoveAutoTunnel6Record as it is called
6497 // from other places.
6498 m
->AutoTunnelRelayAddrOut
= zerov6Addr
;
6502 ParseBTMMInterfaceKey(BTMMDict
, buf
, sizeof(buf
));
6505 LogInfo("ParseBackToMyMac: NULL value for Interface, Removing autotunnel6");
6506 RemoveAutoTunnel6Record(m
);
6507 m
->AutoTunnelRelayAddrOut
= zerov6Addr
;
6508 // We don't have a utun interface, start the relay connection if possible
6509 UpdateBTMMRelayConnection(m
);
6513 LogInfo("ParseBackToMyMac: non-NULL value for Interface, Adding autotunnel6");
6514 AddAutoTunnel6Record(m
, buf
, BTMMDict
);
6518 mDNSexport
void SetupConndConfigChanges(mDNS
*const m
)
6520 CFDictionaryRef connd
;
6521 SCDynamicStoreRef store
;
6523 store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:SetupConndConfigChanges"), NULL
, NULL
);
6524 if (!store
) {LogMsg("SetupConndConfigChanges: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); return;}
6526 connd
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BTMMConnectivity
);
6528 {LogInfo("SetupConndConfigChanges: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError())); CFRelease(store
); return;}
6531 ParseBackToMyMac(m
, connd
);
6536 #endif /* APPLE_OSX_mDNSResponder */
6539 mDNSexport
void mDNSMacOSXNetworkChanged(mDNS
*const m
)
6541 LogInfo("*** Network Configuration Change *** (%d)%s",
6542 m
->p
->NetworkChanged
? mDNS_TimeNow(m
) - m
->p
->NetworkChanged
: 0,
6543 m
->p
->NetworkChanged
? "" : " (no scheduled configuration change)");
6544 m
->p
->NetworkChanged
= 0; // If we received a network change event and deferred processing, we're now dealing with it
6545 mDNSs32 utc
= mDNSPlatformUTC();
6546 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
6547 m
->SystemSleepOnlyIfWakeOnLAN
= SystemSleepOnlyIfWakeOnLAN();
6548 MarkAllInterfacesInactive(m
, utc
);
6549 UpdateInterfaceList(m
, utc
);
6550 ClearInactiveInterfaces(m
, utc
);
6551 SetupActiveInterfaces(m
, utc
);
6553 #if APPLE_OSX_mDNSResponder
6555 SetupConndConfigChanges(m
);
6557 if (m
->AutoTunnelHostAddr
.b
[0])
6560 if (TunnelClients(m
) || TunnelServers(m
))
6561 SetupLocalAutoTunnelInterface_internal(m
, mDNSfalse
);
6565 // Scan to find client tunnels whose questions have completed,
6566 // but whose local inner/outer addresses have changed since the tunnel was set up
6568 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
6569 if (p
->q
.ThisQInterval
< 0)
6571 if (!mDNSIPPortIsZero(p
->rmt_outer_port
))
6573 mDNSAddr tmpSrc
= zeroAddr
;
6574 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
6575 tmpDst
.ip
.v4
= p
->rmt_outer
;
6576 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
6577 if (!mDNSSameIPv6Address(p
->loc_inner
, m
->AutoTunnelHostAddr
) ||
6578 !mDNSSameIPv4Address(p
->loc_outer
, tmpSrc
.ip
.v4
))
6580 AutoTunnelSetKeys(p
, mDNSfalse
);
6581 p
->loc_inner
= m
->AutoTunnelHostAddr
;
6582 p
->loc_outer
= tmpSrc
.ip
.v4
;
6583 AutoTunnelSetKeys(p
, mDNStrue
);
6588 if (!mDNSSameIPv6Address(p
->loc_inner
, m
->AutoTunnelHostAddr
) ||
6589 !mDNSSameIPv6Address(p
->loc_outer6
, m
->AutoTunnelRelayAddrOut
))
6591 AutoTunnelSetKeys(p
, mDNSfalse
);
6592 p
->loc_inner
= m
->AutoTunnelHostAddr
;
6593 p
->loc_outer6
= m
->AutoTunnelRelayAddrOut
;
6594 AutoTunnelSetKeys(p
, mDNStrue
);
6602 NetworkInterfaceInfoOSX
*i
;
6603 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
6605 if (!m
->SPSSocket
) // Not being Sleep Proxy Server; close any open BPF fds
6607 if (i
->BPF_fd
>= 0 && CountProxyTargets(m
, i
, mDNSNULL
, mDNSNULL
) == 0) CloseBPF(i
);
6609 else // else, we're Sleep Proxy Server; open BPF fds
6611 if (i
->Exists
&& i
->Registered
== i
&& i
->ifinfo
.McastTxRx
&& !(i
->ifa_flags
& IFF_LOOPBACK
) && i
->BPF_fd
== -1)
6612 { LogSPS("%s requesting BPF", i
->ifinfo
.ifname
); i
->BPF_fd
= -2; mDNSRequestBPF(); }
6616 #endif // APPLE_OSX_mDNSResponder
6618 uDNS_SetupDNSConfig(m
);
6619 mDNS_ConfigChanged(m
);
6622 // Called with KQueueLock & mDNS lock
6623 mDNSlocal
void SetNetworkChanged(mDNS
*const m
, mDNSs32 delay
)
6625 if (!m
->p
->NetworkChanged
|| m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) < 0)
6627 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
6628 LogInfo("SetNetworkChanged: setting network changed to %d (%d)", delay
, m
->p
->NetworkChanged
);
6633 // Copy the fourth slash-delimited element from either:
6634 // State:/Network/Interface/<bsdname>/IPv4
6636 // Setup:/Network/Service/<servicename>/Interface
6637 mDNSlocal CFStringRef
CopyNameFromKey(CFStringRef key
)
6640 CFStringRef name
= NULL
;
6642 a
= CFStringCreateArrayBySeparatingStrings(NULL
, key
, CFSTR("/"));
6643 if (a
&& CFArrayGetCount(a
) == 5) name
= CFRetain(CFArrayGetValueAtIndex(a
, 3));
6644 if (a
!= NULL
) CFRelease(a
);
6649 // Whether a key from a network change notification corresponds to
6650 // an IP service that is explicitly configured for IPv4 Link Local
6651 mDNSlocal mDNSBool
ChangedKeysHaveIPv4LL(CFArrayRef inkeys
)
6653 SCDynamicStoreRef store
= NULL
;
6654 CFDictionaryRef dict
= NULL
;
6655 CFMutableArrayRef a
;
6656 const void **keys
= NULL
, **vals
= NULL
;
6657 CFStringRef pattern
= NULL
;
6659 mDNSBool found
= mDNSfalse
;
6661 jc
= CFArrayGetCount(inkeys
);
6664 store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:ChangedKeysHaveIPv4LL"), NULL
, NULL
);
6665 if (store
== NULL
) goto done
;
6667 a
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6668 if (a
== NULL
) goto done
;
6670 // Setup:/Network/Service/[^/]+/Interface
6671 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetInterface
);
6672 if (pattern
== NULL
) goto done
;
6673 CFArrayAppendValue(a
, pattern
);
6676 // Setup:/Network/Service/[^/]+/IPv4
6677 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetIPv4
);
6678 if (pattern
== NULL
) goto done
;
6679 CFArrayAppendValue(a
, pattern
);
6682 dict
= SCDynamicStoreCopyMultiple(store
, NULL
, a
);
6687 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
6691 ic
= CFDictionaryGetCount(dict
);
6692 vals
= mDNSPlatformMemAllocate(sizeof (void *) * ic
);
6693 keys
= mDNSPlatformMemAllocate(sizeof (void *) * ic
);
6694 CFDictionaryGetKeysAndValues(dict
, keys
, vals
);
6696 for (j
= 0; j
< jc
&& !found
; j
++)
6698 CFStringRef key
= CFArrayGetValueAtIndex(inkeys
, j
);
6699 CFStringRef ifname
= NULL
;
6703 // It would be nice to use a regex here
6704 if (!CFStringHasPrefix(key
, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key
, kSCEntNetIPv4
)) continue;
6706 if ((ifname
= CopyNameFromKey(key
)) == NULL
) continue;
6707 if (mDNS_LoggingEnabled
)
6709 if (!CFStringGetCString(ifname
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
6710 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf
);
6713 for (i
= 0; i
< ic
; i
++)
6715 CFDictionaryRef ipv4dict
;
6717 CFStringRef serviceid
;
6718 CFStringRef configmethod
;
6720 if (!CFStringHasSuffix(keys
[i
], kSCEntNetInterface
)) continue;
6722 if (CFDictionaryGetTypeID() != CFGetTypeID(vals
[i
])) continue;
6724 if ((name
= CFDictionaryGetValue(vals
[i
], kSCPropNetInterfaceDeviceName
)) == NULL
) continue;
6726 if (!CFEqual(ifname
, name
)) continue;
6728 if ((serviceid
= CopyNameFromKey(keys
[i
])) == NULL
) continue;
6729 if (mDNS_LoggingEnabled
)
6731 if (!CFStringGetCString(serviceid
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
6732 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf
);
6735 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceid
, kSCEntNetIPv4
);
6736 CFRelease(serviceid
);
6737 if (pattern
== NULL
) continue;
6739 ipv4dict
= CFDictionaryGetValue(dict
, pattern
);
6741 if (!ipv4dict
|| CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict
)) continue;
6743 configmethod
= CFDictionaryGetValue(ipv4dict
, kSCPropNetIPv4ConfigMethod
);
6744 if (!configmethod
) continue;
6746 if (mDNS_LoggingEnabled
)
6748 if (!CFStringGetCString(configmethod
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
6749 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf
);
6752 if (CFEqual(configmethod
, kSCValNetIPv4ConfigMethodLinkLocal
)) { found
= mDNStrue
; break; }
6759 if (vals
!= NULL
) mDNSPlatformMemFree(vals
);
6760 if (keys
!= NULL
) mDNSPlatformMemFree(keys
);
6761 if (dict
!= NULL
) CFRelease(dict
);
6762 if (store
!= NULL
) CFRelease(store
);
6767 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
6769 (void)store
; // Parameter not used
6770 mDNS
*const m
= (mDNS
*const)context
;
6774 mDNSs32 delay
= mDNSPlatformOneSecond
* 2; // Start off assuming a two-second delay
6776 int c
= CFArrayGetCount(changedKeys
); // Count changes
6777 CFRange range
= { 0, c
};
6778 int c1
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Hostnames
) != 0);
6779 int c2
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Computername
) != 0);
6780 int c3
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DynamicDNS
) != 0);
6781 int c4
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DNS
) != 0);
6782 if (c
&& c
- c1
- c2
- c3
- c4
== 0) delay
= mDNSPlatformOneSecond
/10; // If these were the only changes, shorten delay
6784 if (mDNS_LoggingEnabled
)
6790 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys
, i
), buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
6791 LogInfo("*** NetworkChanged SC key: %s", buf
);
6793 LogInfo("*** NetworkChanged *** %d change%s %s%s%s%sdelay %d",
6795 c1
? "(Local Hostname) " : "",
6796 c2
? "(Computer Name) " : "",
6797 c3
? "(DynamicDNS) " : "",
6802 SetNetworkChanged(m
, delay
);
6804 // KeyChain frequently fails to notify clients of change events. To work around this
6805 // we set a timer and periodically poll to detect if any changes have occurred.
6806 // Without this Back To My Mac just does't work for a large number of users.
6807 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
6808 if (c3
|| CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_BackToMyMac
))
6810 LogInfo("*** NetworkChanged *** starting KeyChainBugTimer");
6811 m
->p
->KeyChainBugTimer
= NonZeroTime(m
->timenow
+ delay
);
6812 m
->p
->KeyChainBugInterval
= mDNSPlatformOneSecond
;
6817 // If DNS settings changed, immediately force a reconfig (esp. cache flush)
6818 // Similarly, if an interface changed that is explicitly IPv4 link local, immediately force a reconfig
6819 if (c4
|| ChangedKeysHaveIPv4LL(changedKeys
)) mDNSMacOSXNetworkChanged(m
);
6821 KQueueUnlock(m
, "NetworkChanged");
6824 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
6827 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
6828 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
6829 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6830 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
6831 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
6832 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6834 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
6835 if (!keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
6837 CFArrayAppendValue(keys
, NetworkChangedKey_IPv4
);
6838 CFArrayAppendValue(keys
, NetworkChangedKey_IPv6
);
6839 CFArrayAppendValue(keys
, NetworkChangedKey_Hostnames
);
6840 CFArrayAppendValue(keys
, NetworkChangedKey_Computername
);
6841 CFArrayAppendValue(keys
, NetworkChangedKey_DNS
);
6842 CFArrayAppendValue(keys
, NetworkChangedKey_DynamicDNS
);
6843 CFArrayAppendValue(keys
, NetworkChangedKey_BackToMyMac
);
6844 CFArrayAppendValue(keys
, NetworkChangedKey_PowerSettings
); // should remove as part of <rdar://problem/6751656>
6845 CFArrayAppendValue(keys
, NetworkChangedKey_BTMMConnectivity
);
6846 CFArrayAppendValue(patterns
, pattern1
);
6847 CFArrayAppendValue(patterns
, pattern2
);
6848 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
6849 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
6850 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
6852 #ifdef __LIB_DISPATCH__
6853 if (!SCDynamicStoreSetDispatchQueue(store
, dispatch_get_main_queue()))
6854 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
6856 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
6857 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
6858 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
6860 m
->p
->Store
= store
;
6865 if (store
) CFRelease(store
);
6868 if (patterns
) CFRelease(patterns
);
6869 if (pattern2
) CFRelease(pattern2
);
6870 if (pattern1
) CFRelease(pattern1
);
6871 if (keys
) CFRelease(keys
);
6876 #if 0 // <rdar://problem/6751656>
6877 mDNSlocal
void PMChanged(void *context
)
6879 mDNS
*const m
= (mDNS
*const)context
;
6884 LogSPS("PMChanged");
6886 SetNetworkChanged(m
, mDNSPlatformOneSecond
* 2);
6889 KQueueUnlock(m
, "PMChanged");
6892 mDNSlocal mStatus
WatchForPMChanges(mDNS
*const m
)
6894 m
->p
->PMRLS
= IOPMPrefsNotificationCreateRunLoopSource(PMChanged
, m
);
6895 if (!m
->p
->PMRLS
) { LogMsg("IOPMPrefsNotificationCreateRunLoopSource failed!"); return mStatus_UnknownErr
; }
6897 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PMRLS
, kCFRunLoopDefaultMode
);
6899 return mStatus_NoError
;
6903 #ifndef KEV_DL_WAKEFLAGS_CHANGED
6904 #define KEV_DL_WAKEFLAGS_CHANGED 17
6907 mDNSlocal
void SysEventCallBack(int s1
, short __unused filter
, void *context
)
6909 mDNS
*const m
= (mDNS
*const)context
;
6913 struct { struct kern_event_msg k
; char extra
[256]; } msg
;
6914 int bytes
= recv(s1
, &msg
, sizeof(msg
), 0);
6916 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes
, errno
, strerror(errno
));
6919 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
6920 bytes
, msg
.k
.total_size
,
6921 msg
.k
.vendor_code
, msg
.k
.vendor_code
== KEV_VENDOR_APPLE
? "KEV_VENDOR_APPLE" : "?",
6922 msg
.k
.kev_class
, msg
.k
.kev_class
== KEV_NETWORK_CLASS
? "KEV_NETWORK_CLASS" : "?",
6923 msg
.k
.kev_subclass
, msg
.k
.kev_subclass
== KEV_DL_SUBCLASS
? "KEV_DL_SUBCLASS" : "?",
6924 msg
.k
.id
, msg
.k
.event_code
,
6925 msg
.k
.event_code
== KEV_DL_SIFFLAGS
? "KEV_DL_SIFFLAGS" :
6926 msg
.k
.event_code
== KEV_DL_SIFMETRICS
? "KEV_DL_SIFMETRICS" :
6927 msg
.k
.event_code
== KEV_DL_SIFMTU
? "KEV_DL_SIFMTU" :
6928 msg
.k
.event_code
== KEV_DL_SIFPHYS
? "KEV_DL_SIFPHYS" :
6929 msg
.k
.event_code
== KEV_DL_SIFMEDIA
? "KEV_DL_SIFMEDIA" :
6930 msg
.k
.event_code
== KEV_DL_SIFGENERIC
? "KEV_DL_SIFGENERIC" :
6931 msg
.k
.event_code
== KEV_DL_ADDMULTI
? "KEV_DL_ADDMULTI" :
6932 msg
.k
.event_code
== KEV_DL_DELMULTI
? "KEV_DL_DELMULTI" :
6933 msg
.k
.event_code
== KEV_DL_IF_ATTACHED
? "KEV_DL_IF_ATTACHED" :
6934 msg
.k
.event_code
== KEV_DL_IF_DETACHING
? "KEV_DL_IF_DETACHING" :
6935 msg
.k
.event_code
== KEV_DL_IF_DETACHED
? "KEV_DL_IF_DETACHED" :
6936 msg
.k
.event_code
== KEV_DL_LINK_OFF
? "KEV_DL_LINK_OFF" :
6937 msg
.k
.event_code
== KEV_DL_LINK_ON
? "KEV_DL_LINK_ON" :
6938 msg
.k
.event_code
== KEV_DL_PROTO_ATTACHED
? "KEV_DL_PROTO_ATTACHED" :
6939 msg
.k
.event_code
== KEV_DL_PROTO_DETACHED
? "KEV_DL_PROTO_DETACHED" :
6940 msg
.k
.event_code
== KEV_DL_LINK_ADDRESS_CHANGED
? "KEV_DL_LINK_ADDRESS_CHANGED" :
6941 msg
.k
.event_code
== KEV_DL_WAKEFLAGS_CHANGED
? "KEV_DL_WAKEFLAGS_CHANGED" : "?");
6943 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
6944 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
6945 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
6946 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
6947 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
6949 if (msg
.k
.event_code
== KEV_DL_WAKEFLAGS_CHANGED
|| msg
.k
.event_code
== KEV_DL_LINK_ON
)
6950 SetNetworkChanged(m
, mDNSPlatformOneSecond
* 2);
6956 mDNSlocal mStatus
WatchForSysEvents(mDNS
*const m
)
6958 m
->p
->SysEventNotifier
= socket(PF_SYSTEM
, SOCK_RAW
, SYSPROTO_EVENT
);
6959 if (m
->p
->SysEventNotifier
< 0)
6960 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m
->p
->SysEventNotifier
, errno
, strerror(errno
)); return(mStatus_NoMemoryErr
); }
6962 struct kev_request kev_req
= { KEV_VENDOR_APPLE
, KEV_NETWORK_CLASS
, KEV_DL_SUBCLASS
};
6963 int err
= ioctl(m
->p
->SysEventNotifier
, SIOCSKEVFILT
, &kev_req
);
6966 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err
, errno
, strerror(errno
));
6967 close(m
->p
->SysEventNotifier
);
6968 m
->p
->SysEventNotifier
= -1;
6969 return(mStatus_UnknownErr
);
6972 m
->p
->SysEventKQueue
.KQcallback
= SysEventCallBack
;
6973 m
->p
->SysEventKQueue
.KQcontext
= m
;
6974 m
->p
->SysEventKQueue
.KQtask
= "System Event Notifier";
6975 KQueueSet(m
->p
->SysEventNotifier
, EV_ADD
, EVFILT_READ
, &m
->p
->SysEventKQueue
);
6977 return(mStatus_NoError
);
6980 #ifndef NO_SECURITYFRAMEWORK
6981 mDNSlocal OSStatus
KeychainChanged(SecKeychainEvent keychainEvent
, SecKeychainCallbackInfo
*info
, void *context
)
6983 LogInfo("*** Keychain Changed ***");
6984 mDNS
*const m
= (mDNS
*const)context
;
6986 OSStatus err
= SecKeychainCopyDefault(&skc
);
6989 if (info
->keychain
== skc
)
6991 // 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
6992 mDNSBool relevant
= (keychainEvent
== kSecDeleteEvent
);
6995 UInt32 tags
[3] = { kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
};
6996 SecKeychainAttributeInfo attrInfo
= { 3, tags
, NULL
}; // Count, array of tags, array of formats
6997 SecKeychainAttributeList
*a
= NULL
;
6998 err
= SecKeychainItemCopyAttributesAndData(info
->item
, &attrInfo
, NULL
, &a
, NULL
, NULL
);
7001 relevant
= ((a
->attr
[0].length
== 4 && (!strncasecmp(a
->attr
[0].data
, "ddns", 4) || !strncasecmp(a
->attr
[0].data
, "sndd", 4))) ||
7002 (a
->attr
[1].length
>= 4 && (!strncasecmp(a
->attr
[1].data
, "dns:", 4))));
7003 SecKeychainItemFreeAttributesAndData(a
, NULL
);
7008 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
7010 keychainEvent
== kSecAddEvent
? "kSecAddEvent" :
7011 keychainEvent
== kSecDeleteEvent
? "kSecDeleteEvent" :
7012 keychainEvent
== kSecUpdateEvent
? "kSecUpdateEvent" : "<Unknown>");
7013 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
7016 SetDomainSecrets(m
);
7018 KQueueUnlock(m
, "KeychainChanged");
7028 mDNSlocal
void PowerOn(mDNS
*const m
)
7030 mDNSCoreMachineSleep(m
, false); // Will set m->SleepState = SleepState_Awake;
7031 if (m
->p
->WakeAtUTC
)
7033 long utc
= mDNSPlatformUTC();
7034 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
7035 if (m
->p
->WakeAtUTC
- utc
> 30) LogInfo("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m
->p
->WakeAtUTC
- utc
);
7036 else if (utc
- m
->p
->WakeAtUTC
> 30) LogInfo("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc
- m
->p
->WakeAtUTC
);
7040 //int result = mDNSPowerRequest(0, i);
7041 //if (result == kIOReturnNotReady) do i += (i<20) ? 1 : ((i+3)/4); while (mDNSPowerRequest(0, i) == kIOReturnNotReady);
7042 LogMsg("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in %d seconds", m
->p
->WakeAtUTC
- utc
, i
);
7043 m
->p
->RequestReSleep
= mDNS_TimeNow(m
) + i
* mDNSPlatformOneSecond
;
7048 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
7050 mDNS
*const m
= (mDNS
*const)refcon
;
7052 (void)service
; // Parameter not used
7053 debugf("PowerChanged %X %lX", messageType
, messageArgument
);
7055 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
7056 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
7060 case kIOMessageCanSystemPowerOff
: LogInfo("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
7061 case kIOMessageSystemWillPowerOff
: LogInfo("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
7062 mDNSCoreMachineSleep(m
, true);
7063 if (m
->SleepState
== SleepState_Sleeping
) mDNSMacOSXNetworkChanged(m
);
7065 case kIOMessageSystemWillNotPowerOff
: LogInfo("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
7066 case kIOMessageCanSystemSleep
: LogInfo("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
7067 case kIOMessageSystemWillSleep
: LogInfo("PowerChanged kIOMessageSystemWillSleep"); // E0000280
7068 mDNSCoreMachineSleep(m
, true);
7070 case kIOMessageSystemWillNotSleep
: LogInfo("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
7071 case kIOMessageSystemHasPoweredOn
: LogInfo("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
7072 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
7075 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m
->SleepState
);
7078 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
7079 // the System Configuration Framework "network changed" event that we expect
7080 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
7082 if (!m
->p
->NetworkChanged
||
7083 m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2) < 0)
7084 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2);
7088 case kIOMessageSystemWillRestart
: LogInfo("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
7089 case kIOMessageSystemWillPowerOn
: LogInfo("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
7091 #if ! TARGET_OS_EMBEDDED
7092 // On Leopard and earlier, on wake from sleep, instead of reporting link state down, Apple
7093 // Ethernet drivers report "hardware incapable of detecting link state", which the kernel
7094 // interprets as "should assume we have networking", which results in the first 4-5 seconds
7095 // of packets vanishing into a black hole. To work around this, on wake from sleep,
7096 // we block for five seconds to let Ethernet come up, and then resume normal operation.
7097 if (OSXVers
< OSXVers_10_6_SnowLeopard
)
7100 LogMsg("Running on Mac OS X version 10.%d earlier than 10.6; "
7101 "PowerChanged did sleep(5) to wait for Ethernet hardware", OSXVers
- OSXVers_Base
);
7105 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
7106 if (m
->SleepState
!= SleepState_Sleeping
)
7108 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m
->SleepState
);
7109 m
->SleepState
= SleepState_Sleeping
;
7110 mDNSMacOSXNetworkChanged(m
);
7114 default: LogInfo("PowerChanged unknown message %X", messageType
); break;
7117 if (messageType
== kIOMessageSystemWillSleep
) m
->p
->SleepCookie
= (long)messageArgument
;
7118 else IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
7120 KQueueUnlock(m
, "PowerChanged Sleep/Wake");
7123 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
7124 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
7125 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
7126 mDNSlocal
void SnowLeopardPowerChanged(void *refcon
, IOPMConnection connection
, IOPMConnectionMessageToken token
, IOPMSystemPowerStateCapabilities eventDescriptor
)
7128 mDNS
*const m
= (mDNS
*const)refcon
;
7130 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
7131 connection
, token
, eventDescriptor
,
7132 eventDescriptor
& kIOPMSystemPowerStateCapabilityCPU
? " CPU" : "",
7133 eventDescriptor
& kIOPMSystemPowerStateCapabilityVideo
? " Video" : "",
7134 eventDescriptor
& kIOPMSystemPowerStateCapabilityAudio
? " Audio" : "",
7135 eventDescriptor
& kIOPMSystemPowerStateCapabilityNetwork
? " Network" : "",
7136 eventDescriptor
& kIOPMSystemPowerStateCapabilityDisk
? " Disk" : "");
7138 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
7139 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
7141 if (eventDescriptor
& kIOPMSystemPowerStateCapabilityCPU
)
7143 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
7144 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
7145 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
7146 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
7149 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m
->SleepLimit
, m
->SleepState
);
7150 IOPMConnectionAcknowledgeEvent(connection
, m
->p
->SleepCookie
);
7153 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m
->SleepLimit
, m
->SleepState
);
7154 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
7155 if (m
->SleepState
!= SleepState_Awake
) PowerOn(m
);
7156 IOPMConnectionAcknowledgeEvent(connection
, token
);
7160 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
7161 // we should hear nothing more until we're told that the CPU has started executing again.
7162 if (m
->SleepState
) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor
, m
->SleepState
);
7164 //mDNSMacOSXNetworkChanged(m);
7165 mDNSCoreMachineSleep(m
, true);
7166 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
7167 m
->p
->SleepCookie
= token
;
7170 KQueueUnlock(m
, "SnowLeopardPowerChanged Sleep/Wake");
7174 #if COMPILER_LIKES_PRAGMA_MARK
7176 #pragma mark - Initialization & Teardown
7179 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
7180 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
7181 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
7182 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
7184 // Major version 6 is 10.2.x (Jaguar)
7185 // Major version 7 is 10.3.x (Panther)
7186 // Major version 8 is 10.4.x (Tiger)
7187 // Major version 9 is 10.5.x (Leopard)
7188 // Major version 10 is 10.6.x (SnowLeopard)
7189 mDNSexport
int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
7191 int major
= 0, minor
= 0;
7192 char letter
= 0, prodname
[256]="<Unknown>", prodvers
[256]="<Unknown>", buildver
[256]="<Unknown>";
7193 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
7196 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
7197 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
7198 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
7199 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
7200 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
7201 if (cfbuildver
&& CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
))
7202 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
7205 if (!major
) { major
=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
7206 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, STRINGIFY(mDNSResponderVersion
));
7210 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
7211 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
7212 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
7213 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
7216 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
7218 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
7221 struct sockaddr_in s5353
;
7222 s5353
.sin_family
= AF_INET
;
7223 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
7224 s5353
.sin_addr
.s_addr
= 0;
7225 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
7229 if (err
) LogMsg("No unicast UDP responses");
7230 else debugf("Unicast UDP responses okay");
7234 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
7235 // 1) query for b._dns-sd._udp.local on LocalOnly interface
7236 // (.local manually generated via explicit callback)
7237 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
7238 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
7239 // 4) result above should generate a callback from question in (1). result added to global list
7240 // 5) global list delivered to client via GetSearchDomainList()
7241 // 6) client calls to enumerate domains now go over LocalOnly interface
7242 // (!!!KRS may add outgoing interface in addition)
7244 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
7247 m
->p
->CFRunLoop
= CFRunLoopGetCurrent();
7249 char HINFO_SWstring
[256] = "";
7250 OSXVers
= mDNSMacOSXSystemBuildNumber(HINFO_SWstring
);
7252 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
7253 // 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.
7255 for (i
=0; i
<100; i
++)
7257 domainlabel testlabel
;
7259 GetUserSpecifiedLocalHostName(&testlabel
);
7260 if (testlabel
.c
[0]) break;
7264 m
->hostlabel
.c
[0] = 0;
7266 int get_model
[2] = { CTL_HW
, HW_MODEL
};
7267 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
7269 // Normal Apple model names are of the form "iPhone2,1", and
7270 // internal code names are strings containing no commas, e.g. "N88AP".
7271 // We used to ignore internal code names, but Apple now uses these internal code names
7272 // even in released shipping products, so we no longer ignore strings containing no commas.
7273 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
7274 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
7275 HINFO_HWstring
= HINFO_HWstring_buffer
;
7276 HINFO_HWstring_prefixlen
= strcspn(HINFO_HWstring
, "0123456789");
7278 if (OSXVers
< OSXVers_10_3_Panther
) m
->KnownBugs
|= mDNS_KnownBug_PhantomInterfaces
;
7279 if (OSXVers
<= OSXVers_10_6_SnowLeopard
) m
->KnownBugs
|= mDNS_KnownBug_LimitedIPv6
;
7280 if (OSXVers
>= OSXVers_10_6_SnowLeopard
) m
->KnownBugs
|= mDNS_KnownBug_LossySyslog
;
7281 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
7283 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
7284 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
7285 if (hlen
+ slen
< 254)
7287 m
->HIHardware
.c
[0] = hlen
;
7288 m
->HISoftware
.c
[0] = slen
;
7289 mDNSPlatformMemCopy(&m
->HIHardware
.c
[1], HINFO_HWstring
, hlen
);
7290 mDNSPlatformMemCopy(&m
->HISoftware
.c
[1], HINFO_SWstring
, slen
);
7293 m
->p
->permanentsockets
.port
= MulticastDNSPort
;
7294 m
->p
->permanentsockets
.m
= m
;
7295 m
->p
->permanentsockets
.sktv4
= -1;
7296 m
->p
->permanentsockets
.kqsv4
.KQcallback
= myKQSocketCallBack
;
7297 m
->p
->permanentsockets
.kqsv4
.KQcontext
= &m
->p
->permanentsockets
;
7298 m
->p
->permanentsockets
.kqsv4
.KQtask
= "UDP packet reception";
7300 m
->p
->permanentsockets
.sktv6
= -1;
7301 m
->p
->permanentsockets
.kqsv6
.KQcallback
= myKQSocketCallBack
;
7302 m
->p
->permanentsockets
.kqsv6
.KQcontext
= &m
->p
->permanentsockets
;
7303 m
->p
->permanentsockets
.kqsv6
.KQtask
= "UDP packet reception";
7306 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET
, mDNSNULL
);
7308 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET6
, mDNSNULL
);
7311 struct sockaddr_in s4
;
7312 socklen_t n4
= sizeof(s4
);
7313 if (getsockname(m
->p
->permanentsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0) LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
7314 else m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
7316 if (m
->p
->permanentsockets
.sktv6
>= 0)
7318 struct sockaddr_in6 s6
;
7319 socklen_t n6
= sizeof(s6
);
7320 if (getsockname(m
->p
->permanentsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
7321 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
7325 m
->p
->InterfaceList
= mDNSNULL
;
7326 m
->p
->userhostlabel
.c
[0] = 0;
7327 m
->p
->usernicelabel
.c
[0] = 0;
7328 m
->p
->prevoldnicelabel
.c
[0] = 0;
7329 m
->p
->prevnewnicelabel
.c
[0] = 0;
7330 m
->p
->prevoldhostlabel
.c
[0] = 0;
7331 m
->p
->prevnewhostlabel
.c
[0] = 0;
7332 m
->p
->NotifyUser
= 0;
7333 m
->p
->KeyChainBugTimer
= 0;
7334 m
->p
->WakeAtUTC
= 0;
7335 m
->p
->RequestReSleep
= 0;
7337 #if APPLE_OSX_mDNSResponder
7338 uuid_generate(m
->asl_uuid
);
7341 m
->AutoTunnelHostAddr
.b
[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
7342 m
->AutoTunnelRelayAddrIn
= zerov6Addr
;
7343 m
->AutoTunnelRelayAddrOut
= zerov6Addr
;
7345 NetworkChangedKey_IPv4
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
7346 NetworkChangedKey_IPv6
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
7347 NetworkChangedKey_Hostnames
= SCDynamicStoreKeyCreateHostNames(NULL
);
7348 NetworkChangedKey_Computername
= SCDynamicStoreKeyCreateComputerName(NULL
);
7349 NetworkChangedKey_DNS
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
7350 if (!NetworkChangedKey_IPv4
|| !NetworkChangedKey_IPv6
|| !NetworkChangedKey_Hostnames
|| !NetworkChangedKey_Computername
|| !NetworkChangedKey_DNS
)
7351 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr
); }
7353 err
= WatchForNetworkChanges(m
);
7354 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err
); return(err
); }
7356 #if 0 // <rdar://problem/6751656>
7357 err
= WatchForPMChanges(m
);
7358 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForPMChanges failed %d", err
); return(err
); }
7361 err
= WatchForSysEvents(m
);
7362 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err
); return(err
); }
7364 mDNSs32 utc
= mDNSPlatformUTC();
7365 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
7366 UpdateInterfaceList(m
, utc
);
7367 SetupActiveInterfaces(m
, utc
);
7369 // Explicitly ensure that our Keychain operations utilize the system domain.
7370 #ifndef NO_SECURITYFRAMEWORK
7371 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
7375 SetDomainSecrets(m
);
7379 #ifndef NO_SECURITYFRAMEWORK
7380 err
= SecKeychainAddCallback(KeychainChanged
, kSecAddEventMask
|kSecDeleteEventMask
|kSecUpdateEventMask
, m
);
7381 if (err
) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err
); return(err
); }
7384 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
7385 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
7388 IOReturn iopmerr
= IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU
, &c
);
7389 if (iopmerr
) LogMsg("IOPMConnectionCreate failed %d", iopmerr
);
7392 iopmerr
= IOPMConnectionSetNotification(c
, m
, SnowLeopardPowerChanged
);
7393 if (iopmerr
) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr
);
7396 iopmerr
= IOPMConnectionScheduleWithRunLoop(c
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
);
7397 if (iopmerr
) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr
);
7400 m
->p
->IOPMConnection
= iopmerr
? mDNSNULL
: c
;
7401 if (iopmerr
) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
7402 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
7404 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &m
->p
->PowerPortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
7405 if (!m
->p
->PowerConnection
) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
7408 #ifdef __LIB_DISPATCH__
7409 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, dispatch_get_main_queue());
7411 CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
7412 #endif /* __LIB_DISPATCH__ */
7416 #if APPLE_OSX_mDNSResponder
7417 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
7418 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
7419 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
7420 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
7421 if (!strncasecmp(HINFO_HWstring
, "Xserve", 6)) { SPMetricPortability
= 25 /* 30kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
7422 else if (!strncasecmp(HINFO_HWstring
, "RackMac", 7)) { SPMetricPortability
= 25 /* 30kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
7423 else if (!strncasecmp(HINFO_HWstring
, "MacPro", 6)) { SPMetricPortability
= 27 /* 20kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
7424 else if (!strncasecmp(HINFO_HWstring
, "PowerMac", 8)) { SPMetricPortability
= 27 /* 20kg */; SPMetricMarginalPower
= 82 /* 160W */; SPMetricTotalPower
= 83 /* 200W */; }
7425 else if (!strncasecmp(HINFO_HWstring
, "iMac", 4)) { SPMetricPortability
= 30 /* 10kg */; SPMetricMarginalPower
= 77 /* 50W */; SPMetricTotalPower
= 78 /* 60W */; }
7426 else if (!strncasecmp(HINFO_HWstring
, "Macmini", 7)) { SPMetricPortability
= 33 /* 5kg */; SPMetricMarginalPower
= 73 /* 20W */; SPMetricTotalPower
= 74 /* 25W */; }
7427 else if (!strncasecmp(HINFO_HWstring
, "TimeCapsule", 11)) { SPMetricPortability
= 34 /* 4kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 70 /* 13W */; }
7428 else if (!strncasecmp(HINFO_HWstring
, "AirPort", 7)) { SPMetricPortability
= 35 /* 3kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 70 /* 12W */; }
7429 else if (!strncasecmp(HINFO_HWstring
, "AppleTV", 7)) { SPMetricPortability
= 35 /* 3kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 73 /* 20W */; }
7430 else if (!strncasecmp(HINFO_HWstring
, "MacBook", 7)) { SPMetricPortability
= 37 /* 2kg */; SPMetricMarginalPower
= 71 /* 13W */; SPMetricTotalPower
= 72 /* 15W */; }
7431 else if (!strncasecmp(HINFO_HWstring
, "PowerBook", 9)) { SPMetricPortability
= 37 /* 2kg */; SPMetricMarginalPower
= 71 /* 13W */; SPMetricTotalPower
= 72 /* 15W */; }
7432 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d",
7433 HINFO_HWstring_prefixlen
, HINFO_HWstring
, HINFO_HWstring
, SPMetricPortability
, SPMetricMarginalPower
, SPMetricTotalPower
);
7435 err
= WatchForInternetSharingChanges(m
);
7436 if (err
) { LogMsg("WatchForInternetSharingChanges failed %d", err
); return(err
); }
7438 m
->p
->ConndBTMMDict
= mDNSNULL
;
7439 #endif // APPLE_OSX_mDNSResponder
7441 #ifdef __LIB_DISPATCH__
7442 // Currently this is not defined. SSL code will eventually fix this. If it becomes
7443 // critical, we will define this to workaround the bug in SSL.
7444 #ifdef __SSL_NEEDS_SERIALIZATION__
7445 SSLqueue
= dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL
);
7447 SSLqueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
7449 if (SSLqueue
== mDNSNULL
) LogMsg("dispatch_queue_create: SSL queue NULL");
7451 return(mStatus_NoError
);
7454 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
7457 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
7460 // Adding interfaces will use this flag, so set it now.
7461 m
->DivertMulticastAdvertisements
= !m
->AdvertiseLocalAddresses
;
7463 #if APPLE_OSX_mDNSResponder
7464 m
->SPSBrowseCallback
= UpdateSPSStatus
;
7465 #endif // APPLE_OSX_mDNSResponder
7467 mStatus result
= mDNSPlatformInit_setup(m
);
7469 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
7470 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
7471 if (result
== mStatus_NoError
)
7473 mDNSCoreInitComplete(m
, mStatus_NoError
);
7476 // We only initialize if mDNSCore successfully initialized.
7477 CHECK_D2D_FUNCTION(D2DInitialize
)
7479 D2DStatus ds
= D2DInitialize(m
->p
->CFRunLoop
, xD2DServiceCallback
, m
) ;
7480 if (ds
!= kD2DSuccess
)
7481 LogMsg("D2DInitialiize failed: %d", ds
);
7483 LogMsg("D2DInitialize succeeded");
7491 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
7493 if (m
->p
->PowerConnection
)
7495 #ifdef __LIB_DISPATCH__
7496 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, NULL
);
7498 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
7500 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
7501 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
7502 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
7503 IOServiceClose ( m
->p
->PowerConnection
);
7504 IONotificationPortDestroy ( m
->p
->PowerPortRef
);
7505 m
->p
->PowerConnection
= 0;
7510 #ifdef __LIB_DISPATCH__
7511 if (!SCDynamicStoreSetDispatchQueue(m
->p
->Store
, NULL
))
7512 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
7514 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
7515 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
7516 CFRelease(m
->p
->StoreRLS
);
7517 m
->p
->StoreRLS
= NULL
;
7519 CFRelease(m
->p
->Store
);
7525 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PMRLS
, kCFRunLoopDefaultMode
);
7526 CFRunLoopSourceInvalidate(m
->p
->PMRLS
);
7527 CFRelease(m
->p
->PMRLS
);
7531 if (m
->p
->SysEventNotifier
>= 0) { close(m
->p
->SysEventNotifier
); m
->p
->SysEventNotifier
= -1; }
7534 CHECK_D2D_FUNCTION(D2DTerminate
)
7536 D2DStatus ds
= D2DTerminate();
7537 if (ds
!= kD2DSuccess
)
7538 LogMsg("D2DTerminate failed: %d", ds
);
7540 LogMsg("D2DTerminate succeeded");
7544 mDNSs32 utc
= mDNSPlatformUTC();
7545 MarkAllInterfacesInactive(m
, utc
);
7546 ClearInactiveInterfaces(m
, utc
);
7547 CloseSocketSet(&m
->p
->permanentsockets
);
7549 #if APPLE_OSX_mDNSResponder
7551 while (m
->TunnelClients
)
7553 ClientTunnel
*cur
= m
->TunnelClients
;
7554 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur
, cur
->dstname
.c
);
7555 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
7556 AutoTunnelSetKeys(cur
, mDNSfalse
);
7557 m
->TunnelClients
= cur
->next
;
7558 freeL("ClientTunnel", cur
);
7561 if (AnonymousRacoonConfig
)
7563 AnonymousRacoonConfig
= mDNSNULL
;
7564 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel");
7565 (void)mDNSConfigureServer(kmDNSDown
, mDNSNULL
);
7568 if (m
->AutoTunnelHostAddrActive
&& m
->AutoTunnelHostAddr
.b
[0])
7570 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
7571 LogInfo("mDNSPlatformClose: Removing AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
7572 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
7574 if (m
->p
->ConndBTMMDict
) CFRelease(m
->p
->ConndBTMMDict
);
7575 #endif // APPLE_OSX_mDNSResponder
7578 #if COMPILER_LIKES_PRAGMA_MARK
7580 #pragma mark - General Platform Support Layer functions
7583 mDNSexport mDNSu32
mDNSPlatformRandomNumber(void)
7585 return(arc4random());
7588 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
7589 mDNSexport mDNSu32 mDNSPlatformClockDivisor
= 0;
7591 mDNSexport mStatus
mDNSPlatformTimeInit(void)
7593 // Notes: Typical values for mach_timebase_info:
7594 // tbi.numer = 1000 million
7595 // tbi.denom = 33 million
7596 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
7597 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
7598 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
7599 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
7600 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
7602 // Arithmetic notes:
7603 // tbi.denom is at least 1, and not more than 2^32-1.
7604 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
7605 // tbi.denom is at least 1, and not more than 2^32-1.
7606 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
7607 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
7608 // which is unlikely on any current or future Macintosh.
7609 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
7610 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
7611 struct mach_timebase_info tbi
;
7612 kern_return_t result
= mach_timebase_info(&tbi
);
7613 if (result
== KERN_SUCCESS
) mDNSPlatformClockDivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
7617 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
7619 if (mDNSPlatformClockDivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
7621 static uint64_t last_mach_absolute_time
= 0;
7622 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
7623 uint64_t this_mach_absolute_time
= mach_absolute_time();
7624 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
7626 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
7627 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
7628 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
7629 last_mach_absolute_time
= this_mach_absolute_time
;
7630 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later.
7631 // (This bug happens all the time on 10.3, and we know that's not going to be fixed.)
7632 if (OSXVers
>= OSXVers_10_4_Tiger
)
7633 NotifyOfElusiveBug("mach_absolute_time went backwards!",
7634 "This error occurs from time to time, often on newly released hardware, "
7635 "and usually the exact cause is different in each instance.\r\r"
7636 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
7637 "and assign it to Radar Component “Kernel” Version “X”.");
7639 last_mach_absolute_time
= this_mach_absolute_time
;
7641 return((mDNSs32
)(this_mach_absolute_time
/ mDNSPlatformClockDivisor
));
7644 mDNSexport mDNSs32
mDNSPlatformUTC(void)
7649 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
7650 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
7651 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
7652 mDNSexport
void mDNSPlatformStrCopy( void *dst
, const void *src
) { strcpy((char *)dst
, (char *)src
); }
7653 mDNSexport mDNSu32
mDNSPlatformStrLen ( const void *src
) { return(strlen((char*)src
)); }
7654 mDNSexport
void mDNSPlatformMemCopy( void *dst
, const void *src
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
7655 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *dst
, const void *src
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
7656 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { memset(dst
, 0, len
); }
7657 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
7658 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
7660 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }
7662 mDNSexport
void mDNSPlatformSetAllowSleep(mDNS
*const m
, mDNSBool allowSleep
)
7664 if (allowSleep
&& m
->p
->IOPMAssertion
)
7666 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__
);
7667 IOPMAssertionRelease(m
->p
->IOPMAssertion
);
7668 m
->p
->IOPMAssertion
= 0;
7670 else if (!allowSleep
&& m
->p
->IOPMAssertion
== 0)
7672 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep
, kIOPMAssertionLevelOn
, CFSTR("mDNSResponder"), &m
->p
->IOPMAssertion
);
7673 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__
);
7677 mDNSexport
void mDNSPlatformSendWakeupPacket(mDNS
*const m
, mDNSInterfaceID InterfaceID
, char *EthAddr
, char *IPAddr
, int iteration
)
7682 ifindex
= mDNSPlatformInterfaceIndexfromInterfaceID(m
, InterfaceID
);
7685 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex
);
7688 mDNSSendWakeupPacket(ifindex
, EthAddr
, IPAddr
, iteration
);