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
69 #include <netdb.h> // for getaddrinfo
71 #include <netinet/in.h> // For IP_RECVTTL
73 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
76 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
77 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
78 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
79 #include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
81 #if TARGET_OS_EMBEDDED
82 #define NO_SECURITYFRAMEWORK 1
83 #define NO_CFUSERNOTIFICATION 1
86 #ifndef NO_SECURITYFRAMEWORK
87 #include <Security/SecureTransport.h>
88 #include <Security/Security.h>
89 #endif /* NO_SECURITYFRAMEWORK */
91 #include <DebugServices.h>
94 // Code contributed by Dave Heller:
95 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
96 // work on Mac OS X 10.1, which does not have the getifaddrs call.
97 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
98 #if RUN_ON_PUMA_WITHOUT_IFADDRS
99 #include "mDNSMacOSXPuma.c"
104 #include <IOKit/IOKitLib.h>
105 #include <IOKit/IOMessage.h>
107 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
108 // This is currently defined in IOKit/PrivateHeaders/IOKitLibPrivate.h. Till it becomes an Public
109 // API, we will have our own declaration
110 void IONotificationPortSetDispatchQueue(IONotificationPortRef notify
, dispatch_queue_t queue
);
113 #if USE_IOPMCOPYACTIVEPMPREFERENCES
114 #include <IOKit/ps/IOPowerSources.h>
115 #include <IOKit/ps/IOPowerSourcesPrivate.h>
118 #include <mach/mach_error.h>
119 #include <mach/mach_port.h>
120 #include <mach/mach_time.h>
122 #include "P2PPacketFilter.h"
126 #include <SystemConfiguration/SCDynamicStorePrivate.h>
128 #if APPLE_OSX_mDNSResponder
129 #include <DeviceToDeviceManager/DeviceToDeviceManager.h>
133 D2DStatus
D2DInitialize(CFRunLoopRef runLoop
, D2DServiceCallback serviceCallback
, void* userData
) __attribute__((weak_import
));
134 D2DStatus
D2DTerminate() __attribute__((weak_import
));
135 D2DStatus
D2DStartAdvertisingPair(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
) __attribute__((weak_import
));
136 D2DStatus
D2DStopAdvertisingPair(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
) __attribute__((weak_import
));
137 D2DStatus
D2DStartBrowsingForKey(const Byte
*key
, const size_t keySize
) __attribute__((weak_import
));
138 D2DStatus
D2DStopBrowsingForKey(const Byte
*key
, const size_t keySize
) __attribute__((weak_import
));
139 void D2DStartResolvingPair(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
) __attribute__((weak_import
));
140 void D2DStopResolvingPair(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
) __attribute__((weak_import
));
141 D2DStatus
D2DRetain(D2DServiceInstance instanceHandle
, D2DTransportType transportType
) __attribute__((weak_import
));
142 D2DStatus
D2DRelease(D2DServiceInstance instanceHandle
, D2DTransportType transportType
) __attribute__((weak_import
));
144 #define CHECK_D2D_FUNCTION(X) if (X)
151 #endif // APPLE_OSX_mDNSResponder
153 #define kInterfaceSpecificOption "interface="
155 // ***************************************************************************
158 #if COMPILER_LIKES_PRAGMA_MARK
159 #pragma mark - Globals
162 // By default we don't offer sleep proxy service
163 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
164 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
165 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
166 mDNSexport
int OfferSleepProxyService
= 0;
167 mDNSexport
int DisableSleepProxyClient
= 0;
168 mDNSexport
int UseInternalSleepProxy
= 1; // Set to non-zero to use internal (in-NIC) Sleep Proxy
170 // We disable inbound relay connection if this value is set to true (typically via command-line switch).
171 mDNSBool DisableInboundRelayConnection
= mDNSfalse
;
172 mDNSexport
int OSXVers
, iOSVers
;
173 mDNSexport
int KQueueFD
;
175 #ifndef NO_SECURITYFRAMEWORK
176 static CFArrayRef ServerCerts
;
177 OSStatus
SSLSetAllowAnonymousCiphers(SSLContextRef context
, Boolean enable
);
178 #endif /* NO_SECURITYFRAMEWORK */
180 static CFStringRef NetworkChangedKey_IPv4
;
181 static CFStringRef NetworkChangedKey_IPv6
;
182 static CFStringRef NetworkChangedKey_Hostnames
;
183 static CFStringRef NetworkChangedKey_Computername
;
184 static CFStringRef NetworkChangedKey_DNS
;
185 static CFStringRef NetworkChangedKey_DynamicDNS
= CFSTR("Setup:/Network/DynamicDNS");
186 static CFStringRef NetworkChangedKey_BackToMyMac
= CFSTR("Setup:/Network/BackToMyMac");
187 static CFStringRef NetworkChangedKey_BTMMConnectivity
= CFSTR("State:/Network/Connectivity");
188 static CFStringRef NetworkChangedKey_PowerSettings
= CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
190 static char HINFO_HWstring_buffer
[32];
191 static char *HINFO_HWstring
= "Device";
192 static int HINFO_HWstring_prefixlen
= 6;
194 mDNSexport
int WatchDogReportingThreshold
= 250;
196 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
197 dispatch_queue_t SSLqueue
;
200 #if APPLE_OSX_mDNSResponder
201 static mDNSu8 SPMetricPortability
= 99;
202 static mDNSu8 SPMetricMarginalPower
= 99;
203 static mDNSu8 SPMetricTotalPower
= 99;
204 mDNSexport domainname ActiveDirectoryPrimaryDomain
;
205 mDNSexport
int ActiveDirectoryPrimaryDomainLabelCount
;
206 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer
;
207 #endif // APPLE_OSX_mDNSResponder
209 // Used by AutoTunnel
210 const char btmmprefix
[] = "btmmdns:";
211 const char dnsprefix
[] = "dns:";
213 // ***************************************************************************
214 #if COMPILER_LIKES_PRAGMA_MARK
216 #pragma mark - D2D Support
221 // Name compression items for fake packet version number 1
222 static const mDNSu8 compression_packet_v1
= 0x01;
224 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" };
225 static mDNSu8
*const compression_limit
= (mDNSu8
*) &compression_base_msg
+ sizeof(DNSMessage
);
226 static mDNSu8
*const compression_lhs
= (mDNSu8
*const) compression_base_msg
.data
+ 27;
228 mDNSlocal
void FreeD2DARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
229 mDNSlocal
void PrintHex(mDNSu8
*data
, mDNSu16 len
);
231 static ARListElem
*D2DRecords
= NULL
; // List of locally-generated PTR records to records found via D2D
233 typedef struct D2DBrowseListElem
235 struct D2DBrowseListElem
*next
;
238 unsigned int refCount
;
241 D2DBrowseListElem
* D2DBrowseList
= NULL
;
243 mDNSlocal mDNSu8
*putVal16(mDNSu8
*ptr
, mDNSu16 val
)
245 ptr
[0] = (mDNSu8
)((val
>> 8 ) & 0xFF);
246 ptr
[1] = (mDNSu8
)((val
) & 0xFF);
247 return ptr
+ sizeof(mDNSu16
);
250 mDNSlocal mDNSu8
*putVal32(mDNSu8
*ptr
, mDNSu32 val
)
252 ptr
[0] = (mDNSu8
)((val
>> 24) & 0xFF);
253 ptr
[1] = (mDNSu8
)((val
>> 16) & 0xFF);
254 ptr
[2] = (mDNSu8
)((val
>> 8) & 0xFF);
255 ptr
[3] = (mDNSu8
)((val
) & 0xFF);
256 return ptr
+ sizeof(mDNSu32
);
259 mDNSlocal
void DomainnameToLower(const domainname
* const in
, domainname
* const out
)
261 const mDNSu8
* const start
= (const mDNSu8
* const)in
;
262 mDNSu8
*ptr
= (mDNSu8
*)start
;
266 out
->c
[ptr
-start
] = *ptr
;
268 for (;c
;c
--,ptr
++) out
->c
[ptr
-start
] = mDNSIsUpperCase(*ptr
) ? (*ptr
- 'A' + 'a') : *ptr
;
270 out
->c
[ptr
-start
] = *ptr
;
273 mDNSlocal mStatus
DNSNameCompressionParseBytes(mDNS
*const m
, const mDNSu8
*const lhs
, const mDNSu16 lhs_len
, const mDNSu8
*const rhs
, const mDNSu16 rhs_len
, AuthRecord
*rr
)
275 if (mDNS_LoggingEnabled
)
277 LogInfo("%s", __func__
);
278 LogInfo(" Static Bytes: ");
279 PrintHex((mDNSu8
*)&compression_base_msg
, compression_lhs
- (mDNSu8
*)&compression_base_msg
);
282 mDNSu8
*ptr
= compression_lhs
; // pointer to the end of our fake packet
284 // Check to make sure we're not going to go past the end of the DNSMessage data
285 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
286 if (ptr
+ lhs_len
- 7 + rhs_len
>= compression_limit
) return mStatus_NoMemoryErr
;
288 // Copy the LHS onto our fake wire packet
289 mDNSPlatformMemCopy(ptr
, lhs
, lhs_len
);
292 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
293 if (*ptr
!= compression_packet_v1
) return mStatus_Incompatible
;
295 // two bytes of CLASS
296 ptr
= putVal16(ptr
, kDNSClass_IN
| kDNSClass_UniqueRRSet
);
299 ptr
= putVal32(ptr
, 120);
301 // Copy the RHS length into the RDLENGTH of our fake wire packet
302 ptr
= putVal16(ptr
, rhs_len
);
304 // Copy the RHS onto our fake wire packet
305 mDNSPlatformMemCopy(ptr
, rhs
, rhs_len
);
308 if (mDNS_LoggingEnabled
)
310 LogInfo(" Our Bytes %d: ", __LINE__
);
311 PrintHex(compression_lhs
, ptr
- compression_lhs
);
314 ptr
= (mDNSu8
*) GetLargeResourceRecord(m
, &compression_base_msg
, compression_lhs
, ptr
, mDNSInterface_Any
, kDNSRecordTypePacketAns
, &m
->rec
);
315 if (!ptr
|| m
->rec
.r
.resrec
.RecordType
== kDNSRecordTypePacketNegative
)
316 { LogMsg("DNSNameCompressionParseBytes: failed to get large RR"); m
->rec
.r
.resrec
.RecordType
= 0; return mStatus_UnknownErr
; }
317 else LogInfo("DNSNameCompressionParseBytes: got rr: %s", CRDisplayString(m
, &m
->rec
.r
));
319 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_P2P
, m
->rec
.r
.resrec
.rrtype
, 7200, kDNSRecordTypeShared
, AuthRecordP2P
, FreeD2DARElemCallback
, NULL
);
320 AssignDomainName(&rr
->namestorage
, &m
->rec
.namestorage
);
321 rr
->resrec
.rdlength
= m
->rec
.r
.resrec
.rdlength
;
322 rr
->resrec
.rdata
->MaxRDLength
= m
->rec
.r
.resrec
.rdlength
;
323 mDNSPlatformMemCopy(rr
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdlength
);
324 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
325 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
327 m
->rec
.r
.resrec
.RecordType
= 0; // Mark m->rec as no longer in use
329 return mStatus_NoError
;
332 mDNSlocal mDNSu8
* DNSNameCompressionBuildLHS(const domainname
const *typeDomain
, DNS_TypeValues qtype
)
334 mDNSu8
*ptr
= putDomainNameAsLabels(&compression_base_msg
, compression_lhs
, compression_limit
, typeDomain
);
335 if (!ptr
) return ptr
;
336 *ptr
= (qtype
>> 8) & 0xff;
340 *ptr
= compression_packet_v1
;
344 mDNSlocal mDNSu8
* DNSNameCompressionBuildRHS(mDNSu8
*start
, const ResourceRecord
*const resourceRecord
)
346 return putRData(&compression_base_msg
, start
, compression_limit
, resourceRecord
);
349 mDNSlocal
void PrintHex(mDNSu8
*data
, mDNSu16 len
)
351 mDNSu8
*end
= data
+ len
;
352 char buffer
[49] = {0};
353 char *bufend
= buffer
+ sizeof(buffer
);
357 for(; data
< end
&& ptr
< bufend
-1; ptr
+=3,data
++)
358 mDNS_snprintf(ptr
, bufend
- ptr
, "%02X ", *data
);
359 LogInfo(" %s", buffer
);
363 mDNSlocal
void PrintHelper(const char *const tag
, mDNSu8
*lhs
, mDNSu16 lhs_len
, mDNSu8
*rhs
, mDNSu16 rhs_len
)
365 if (!mDNS_LoggingEnabled
) return;
369 PrintHex(lhs
, lhs_len
);
374 PrintHex(rhs
, rhs_len
);
377 mDNSlocal
void FreeD2DARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
380 if (result
== mStatus_MemFree
)
382 ARListElem
**ptr
= &D2DRecords
;
384 while (*ptr
&& &(*ptr
)->ar
!= rr
) ptr
= &(*ptr
)->next
;
385 if (!*ptr
) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m
, rr
)); return; }
386 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m
, rr
));
389 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
390 mDNSPlatformMemFree(tmp
);
394 mDNSlocal
void xD2DClearCache(mDNS
*const m
, const domainname
*regType
)
396 ARListElem
*ptr
= D2DRecords
;
397 for ( ; ptr
; ptr
= ptr
->next
)
399 if (SameDomainName(&ptr
->ar
.namestorage
, regType
))
401 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
402 mDNS_Deregister(m
, &ptr
->ar
);
403 ConvertDomainNameToCString(regType
, buffer
);
404 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", buffer
);
409 mDNSlocal D2DBrowseListElem
** D2DFindInBrowseList(const domainname
*const name
, mDNSu16 type
)
411 D2DBrowseListElem
**ptr
= &D2DBrowseList
;
413 for ( ; *ptr
; ptr
= &(*ptr
)->next
)
414 if ((*ptr
)->type
== type
&& SameDomainName(&(*ptr
)->name
, name
))
420 mDNSlocal
unsigned int D2DBrowseListRefCount(const domainname
*const name
, mDNSu16 type
)
422 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
423 return *ptr
? (*ptr
)->refCount
: 0;
426 mDNSlocal
void D2DBrowseListRetain(const domainname
*const name
, mDNSu16 type
)
428 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
432 *ptr
= mDNSPlatformMemAllocate(sizeof(**ptr
));
433 mDNSPlatformMemZero(*ptr
, sizeof(**ptr
));
435 AssignDomainName(&(*ptr
)->name
, name
);
437 (*ptr
)->refCount
+= 1;
439 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
442 mDNSlocal
void D2DBrowseListRelease(const domainname
*const name
, mDNSu16 type
)
444 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
446 if (!*ptr
) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name
->c
, DNSTypeName(type
)); return; }
448 (*ptr
)->refCount
-= 1;
450 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
452 if (!(*ptr
)->refCount
)
454 D2DBrowseListElem
*tmp
= *ptr
;
456 mDNSPlatformMemFree(tmp
);
460 mDNSlocal mStatus
xD2DParse(mDNS
*const m
, const mDNSu8
* const lhs
, const mDNSu16 lhs_len
, const mDNSu8
* const rhs
, const mDNSu16 rhs_len
, AuthRecord
*rr
)
462 if (*(lhs
+ (lhs_len
- 1)) == compression_packet_v1
)
463 return DNSNameCompressionParseBytes(m
, lhs
, lhs_len
, rhs
, rhs_len
, rr
);
465 return mStatus_Incompatible
;
468 mDNSlocal
void xD2DAddToCache(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
470 (void)transportType
; // We don't care about this, yet.
471 (void)instanceHandle
; // We don't care about this, yet.
473 if (result
== kD2DSuccess
)
475 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
478 ARListElem
*ptr
= mDNSPlatformMemAllocate(sizeof(ARListElem
) + (valueSize
< sizeof(RData
) ? 0 : valueSize
- sizeof(RData
)));
480 if (ptr
== NULL
) { LogMsg("xD2DAddToCache: memory allocation failure"); return; }
482 err
= xD2DParse(m
, (const mDNSu8
* const)key
, (const mDNSu16
)keySize
, (const mDNSu8
* const)value
, (const mDNSu16
)valueSize
, &ptr
->ar
);
485 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err
);
486 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
487 mDNSPlatformMemFree(ptr
);
490 err
= mDNS_Register(m
, &ptr
->ar
);
493 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err
, ARDisplayString(m
, &ptr
->ar
));
494 mDNSPlatformMemFree(ptr
);
498 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m
, &ptr
->ar
));
499 ptr
->next
= D2DRecords
;
503 LogMsg("xD2DAddToCache: Unexpected result %d", result
);
506 mDNSlocal ARListElem
* xD2DFindInList(mDNS
*const m
, const Byte
*const key
, const size_t keySize
, const Byte
*const value
, const size_t valueSize
)
508 ARListElem
*ptr
= D2DRecords
;
511 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL
; }
513 arptr
= mDNSPlatformMemAllocate(sizeof(ARListElem
) + (valueSize
< sizeof(RData
) ? 0 : valueSize
- sizeof(RData
)));
514 if (arptr
== NULL
) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL
; }
516 if (xD2DParse(m
, (const mDNSu8
*const)key
, (const mDNSu16
)keySize
, (const mDNSu8
*const)value
, (const mDNSu16
)valueSize
, &arptr
->ar
) != mStatus_NoError
)
518 LogMsg("xD2DFindInList: xD2DParse failed for key: %p (%u) value: %p (%u)", key
, keySize
, value
, valueSize
);
519 mDNSPlatformMemFree(arptr
);
525 if (IdenticalResourceRecord(&arptr
->ar
.resrec
, &ptr
->ar
.resrec
)) break;
529 if (!ptr
) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(m
, &arptr
->ar
));
530 mDNSPlatformMemFree(arptr
);
534 mDNSlocal
void xD2DRemoveFromCache(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
536 (void)transportType
; // We don't care about this, yet.
537 (void)instanceHandle
; // We don't care about this, yet.
539 if (result
== kD2DSuccess
)
541 ARListElem
*ptr
= xD2DFindInList(m
, key
, keySize
, value
, valueSize
);
544 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m
, &ptr
->ar
));
545 mDNS_Deregister(m
, &ptr
->ar
);
549 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result
);
552 mDNSlocal
void xD2DServiceResolved(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
560 if (result
== kD2DSuccess
)
562 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle
);
563 CHECK_D2D_FUNCTION(D2DRetain
) D2DRetain(instanceHandle
, transportType
);
565 else LogMsg("xD2DServiceResolved: Unexpected result %d", result
);
568 mDNSlocal
void xD2DRetainHappened(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
571 (void)instanceHandle
;
578 if (result
== kD2DSuccess
) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle
);
579 else LogMsg("xD2DRetainHappened: Unexpected result %d", result
);
582 mDNSlocal
void xD2DReleaseHappened(mDNS
*const m
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
585 (void)instanceHandle
;
592 if (result
== kD2DSuccess
) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle
);
593 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result
);
596 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
)
598 mDNS
*m
= (mDNS
*) userData
;
599 const char *eventString
= "unknown";
603 if (keySize
> 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize
);
604 if (valueSize
> 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize
);
608 case D2DServiceFound
:
609 eventString
= "D2DServiceFound";
612 eventString
= "D2DServiceLost";
614 case D2DServiceResolved
:
615 eventString
= "D2DServiceResolved";
617 case D2DServiceRetained
:
618 eventString
= "D2DServiceRetained";
620 case D2DServiceReleased
:
621 eventString
= "D2DServiceReleased";
627 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
);
628 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
632 case D2DServiceFound
:
633 xD2DAddToCache(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
636 xD2DRemoveFromCache(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
638 case D2DServiceResolved
:
639 xD2DServiceResolved(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
641 case D2DServiceRetained
:
642 xD2DRetainHappened(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
644 case D2DServiceReleased
:
645 xD2DReleaseHappened(m
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
651 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
652 KQueueUnlock(m
, "xD2DServiceCallback");
655 mDNSexport
void external_start_browsing_for_service(mDNS
*const m
, const domainname
*const typeDomain
, DNS_TypeValues qtype
)
660 if (qtype
== kDNSServiceType_A
|| qtype
== kDNSServiceType_AAAA
)
662 LogInfo("external_start_browsing_for_service: ignoring address record");
666 DomainnameToLower(typeDomain
, &lower
);
668 if (!D2DBrowseListRefCount(&lower
, qtype
))
670 LogInfo("external_start_browsing_for_service: Starting browse for: %##s %s", lower
.c
, DNSTypeName(qtype
));
671 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
672 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
673 CHECK_D2D_FUNCTION(D2DStartBrowsingForKey
) D2DStartBrowsingForKey(compression_lhs
, end
- compression_lhs
);
675 D2DBrowseListRetain(&lower
, qtype
);
678 mDNSexport
void external_stop_browsing_for_service(mDNS
*const m
, const domainname
*const typeDomain
, DNS_TypeValues qtype
)
682 if (qtype
== kDNSServiceType_A
|| qtype
== kDNSServiceType_AAAA
)
684 LogInfo("external_stop_browsing_for_service: ignoring address record");
688 DomainnameToLower(typeDomain
, &lower
);
690 D2DBrowseListRelease(&lower
, qtype
);
691 if (!D2DBrowseListRefCount(&lower
, qtype
))
693 LogInfo("external_stop_browsing_for_service: Stopping browse for: %##s %s", lower
.c
, DNSTypeName(qtype
));
694 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
695 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
696 CHECK_D2D_FUNCTION(D2DStopBrowsingForKey
) D2DStopBrowsingForKey(compression_lhs
, end
- compression_lhs
);
697 xD2DClearCache(m
, &lower
);
701 mDNSexport
void external_start_advertising_service(const ResourceRecord
*const resourceRecord
)
706 DomainnameToLower(resourceRecord
->name
, &lower
);
708 LogInfo("external_start_advertising_service: %s", RRDisplayString(&mDNSStorage
, resourceRecord
));
709 // For SRV records, update packet filter if p2p interface already exists, otherwise,
710 // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface.
711 // Bonjour filter rules are removed when p2p interface KEV_DL_IF_DETACHED event is received.
712 if (resourceRecord
->rrtype
== kDNSType_SRV
)
713 mDNSInitPacketFilter();
715 if (resourceRecord
->rrtype
== kDNSServiceType_A
|| resourceRecord
->rrtype
== kDNSServiceType_AAAA
)
717 LogInfo("external_start_advertising_service: ignoring address record");
720 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
721 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
722 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
723 CHECK_D2D_FUNCTION(D2DStartAdvertisingPair
) D2DStartAdvertisingPair(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
726 mDNSexport
void external_stop_advertising_service(const ResourceRecord
*const resourceRecord
)
731 DomainnameToLower(resourceRecord
->name
, &lower
);
733 LogInfo("external_stop_advertising_service: %s", RRDisplayString(&mDNSStorage
, resourceRecord
));
734 if (resourceRecord
->rrtype
== kDNSServiceType_A
|| resourceRecord
->rrtype
== kDNSServiceType_AAAA
)
736 LogInfo("external_stop_advertising_service: ignoring address record");
739 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
740 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
741 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
742 CHECK_D2D_FUNCTION(D2DStopAdvertisingPair
) D2DStopAdvertisingPair(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
745 mDNSexport
void external_start_resolving_service(const domainname
*const fqdn
)
750 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
752 LogInfo("external_start_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(D2DStartResolvingPair
) D2DStartResolvingPair(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
759 mDNSexport
void external_stop_resolving_service(const domainname
*const fqdn
)
764 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
766 LogInfo("external_stop_resolving_service: %##s", fqdn
->c
);
767 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
768 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
769 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
770 CHECK_D2D_FUNCTION(D2DStopResolvingPair
) D2DStopResolvingPair(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
773 #elif APPLE_OSX_mDNSResponder
775 mDNSexport
void external_start_browsing_for_service(mDNS
*const m
, const domainname
*const type
, DNS_TypeValues qtype
) { (void)m
; (void)type
; (void)qtype
; }
776 mDNSexport
void external_stop_browsing_for_service(mDNS
*const m
, const domainname
*const type
, DNS_TypeValues qtype
) { (void)m
; (void)type
; (void)qtype
; }
777 mDNSexport
void external_start_advertising_service(const ResourceRecord
*const resourceRecord
) { (void)resourceRecord
; }
778 mDNSexport
void external_stop_advertising_service(const ResourceRecord
*const resourceRecord
) { (void)resourceRecord
; }
779 mDNSexport
void external_start_resolving_service(const domainname
*const fqdn
) { (void)fqdn
; }
780 mDNSexport
void external_stop_resolving_service(const domainname
*const fqdn
) { (void)fqdn
; }
784 // ***************************************************************************
787 #if COMPILER_LIKES_PRAGMA_MARK
789 #pragma mark - Utility Functions
792 // We only attempt to send and receive multicast packets on interfaces that are
793 // (a) flagged as multicast-capable
794 // (b) *not* flagged as point-to-point (e.g. modem)
795 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
796 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
797 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
798 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
800 mDNSexport
void NotifyOfElusiveBug(const char *title
, const char *msg
) // Both strings are UTF-8 text
802 static int notifyCount
= 0;
803 if (notifyCount
) return;
805 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
806 // To avoid this, we don't try to display alerts in the first three minutes after boot.
807 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return;
809 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
812 // Determine if we're at Apple (17.*.*.*)
813 extern mDNS mDNSStorage
;
814 NetworkInterfaceInfoOSX
*i
;
815 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
816 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& i
->ifinfo
.ip
.ip
.v4
.b
[0] == 17)
818 if (!i
) return; // If not at Apple, don't show the alert
824 // Display a notification to the user
827 #ifndef NO_CFUSERNOTIFICATION
828 mDNSNotify(title
, msg
);
829 #endif /* NO_CFUSERNOTIFICATION */
832 mDNSlocal
struct ifaddrs
*myGetIfAddrs(int refresh
)
834 static struct ifaddrs
*ifa
= NULL
;
842 if (ifa
== NULL
) getifaddrs(&ifa
);
847 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
848 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, const char *ifname
, int type
)
850 NetworkInterfaceInfoOSX
*i
;
851 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
852 if (i
->Exists
&& !strcmp(i
->ifinfo
.ifname
, ifname
) &&
853 ((type
== AF_UNSPEC
) ||
854 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
855 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
))) return(i
);
859 mDNSlocal
int myIfIndexToName(u_short ifindex
, char *name
)
862 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
863 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
864 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== ifindex
)
865 { strlcpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
869 mDNSexport NetworkInterfaceInfoOSX
*IfindexToInterfaceInfoOSX(const mDNS
*const m
, mDNSInterfaceID ifindex
)
871 mDNSu32 scope_id
= (mDNSu32
)(uintptr_t)ifindex
;
872 NetworkInterfaceInfoOSX
*i
;
874 // Don't get tricked by inactive interfaces
875 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
876 if (i
->Registered
&& i
->scope_id
== scope_id
) return(i
);
881 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS
*const m
, mDNSu32 ifindex
)
883 if (ifindex
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
884 if (ifindex
== kDNSServiceInterfaceIndexP2P
) return(mDNSInterface_P2P
);
885 if (ifindex
== kDNSServiceInterfaceIndexAny
) return(mDNSNULL
);
887 NetworkInterfaceInfoOSX
* ifi
= IfindexToInterfaceInfoOSX(m
, (mDNSInterfaceID
)(uintptr_t)ifindex
);
890 // Not found. Make sure our interface list is up to date, then try again.
891 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex
);
892 mDNSMacOSXNetworkChanged(m
);
893 ifi
= IfindexToInterfaceInfoOSX(m
, (mDNSInterfaceID
)(uintptr_t)ifindex
);
896 if (!ifi
) return(mDNSNULL
);
898 return(ifi
->ifinfo
.InterfaceID
);
902 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS
*const m
, mDNSInterfaceID id
, mDNSBool suppressNetworkChange
)
904 NetworkInterfaceInfoOSX
*i
;
905 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
906 if (id
== mDNSInterface_P2P
) return(kDNSServiceInterfaceIndexP2P
);
907 if (id
== mDNSInterface_Any
) return(0);
909 mDNSu32 scope_id
= (mDNSu32
)(uintptr_t)id
;
911 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
912 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
913 if (i
->scope_id
== scope_id
) return(i
->scope_id
);
915 // If we are supposed to suppress network change, return "id" back
916 if (suppressNetworkChange
) return scope_id
;
918 // Not found. Make sure our interface list is up to date, then try again.
919 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id
);
920 mDNSMacOSXNetworkChanged(m
);
921 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
922 if (i
->scope_id
== scope_id
) return(i
->scope_id
);
927 #if APPLE_OSX_mDNSResponder
928 mDNSexport
void mDNSASLLog(uuid_t
*uuid
, const char *subdomain
, const char *result
, const char *signature
, const char *fmt
, ...)
930 if (OSXVers
< OSXVers_10_6_SnowLeopard
) return; // Only do ASL on Mac OS X 10.6 and later (not on iOS)
932 static char buffer
[512];
933 aslmsg asl_msg
= asl_new(ASL_TYPE_MSG
);
935 if (!asl_msg
) { LogMsg("mDNSASLLog: asl_new failed"); return; }
939 uuid_unparse(*uuid
, uuidStr
);
940 asl_set (asl_msg
, "com.apple.message.uuid", uuidStr
);
943 static char domainBase
[] = "com.apple.mDNSResponder.%s";
944 mDNS_snprintf (buffer
, sizeof(buffer
), domainBase
, subdomain
);
945 asl_set (asl_msg
, "com.apple.message.domain", buffer
);
947 if (result
) asl_set(asl_msg
, "com.apple.message.result", result
);
948 if (signature
) asl_set(asl_msg
, "com.apple.message.signature", signature
);
952 mDNS_vsnprintf(buffer
, sizeof(buffer
), fmt
, ptr
);
955 int old_filter
= asl_set_filter(NULL
,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
));
956 asl_log(NULL
, asl_msg
, ASL_LEVEL_DEBUG
, "%s", buffer
);
957 asl_set_filter(NULL
, old_filter
);
960 #endif // APPLE_OSX_mDNSResponder
962 #if COMPILER_LIKES_PRAGMA_MARK
964 #pragma mark - UDP & TCP send & receive
967 mDNSlocal mDNSBool
AddrRequiresPPPConnection(const struct sockaddr
*addr
)
969 mDNSBool result
= mDNSfalse
;
970 SCNetworkConnectionFlags flags
;
971 SCNetworkReachabilityRef ReachRef
= NULL
;
973 ReachRef
= SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault
, addr
);
974 if (!ReachRef
) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end
; }
975 if (!SCNetworkReachabilityGetFlags(ReachRef
, &flags
)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end
; }
976 result
= flags
& kSCNetworkFlagsConnectionRequired
;
979 if (ReachRef
) CFRelease(ReachRef
);
983 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
984 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
985 // OR send via our primary v4 unicast socket
986 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
987 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
988 mDNSInterfaceID InterfaceID
, UDPSocket
*src
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
990 NetworkInterfaceInfoOSX
*info
= mDNSNULL
;
991 struct sockaddr_storage to
;
993 mStatus result
= mStatus_NoError
;
997 info
= IfindexToInterfaceInfoOSX(m
, InterfaceID
);
1000 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID
);
1001 return mStatus_BadParamErr
;
1005 char *ifa_name
= InterfaceID
? info
->ifinfo
.ifname
: "unicast";
1007 if (dst
->type
== mDNSAddrType_IPv4
)
1009 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
1010 sin_to
->sin_len
= sizeof(*sin_to
);
1011 sin_to
->sin_family
= AF_INET
;
1012 sin_to
->sin_port
= dstPort
.NotAnInteger
;
1013 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1014 s
= (src
? src
->ss
: m
->p
->permanentsockets
).sktv4
;
1016 if (info
) // Specify outgoing interface
1018 if (!mDNSAddrIsDNSMulticast(dst
))
1021 if (info
->scope_id
== 0)
1022 LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info
, ifa_name
);
1024 setsockopt(s
, IPPROTO_IP
, IP_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1027 static int displayed
= 0;
1028 if (displayed
< 1000)
1031 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
1037 #ifdef IP_MULTICAST_IFINDEX
1039 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IFINDEX
, &info
->scope_id
, sizeof(info
->scope_id
));
1040 // We get an error when we compile on a machine that supports this option and run the binary on
1041 // a different machine that does not support it
1044 if (errno
!= ENOPROTOOPT
) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno
);
1045 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
1046 if (err
< 0 && !m
->p
->NetworkChanged
)
1047 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
1052 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
1053 if (err
< 0 && !m
->p
->NetworkChanged
)
1054 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
1061 else if (dst
->type
== mDNSAddrType_IPv6
)
1063 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
1064 sin6_to
->sin6_len
= sizeof(*sin6_to
);
1065 sin6_to
->sin6_family
= AF_INET6
;
1066 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
1067 sin6_to
->sin6_flowinfo
= 0;
1068 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1069 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
1070 s
= (src
? src
->ss
: m
->p
->permanentsockets
).sktv6
;
1071 if (info
&& mDNSAddrIsDNSMulticast(dst
)) // Specify outgoing interface
1073 err
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1076 char name
[IFNAMSIZ
];
1077 if (if_indextoname(info
->scope_id
, name
) != NULL
)
1078 LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err
, errno
, strerror(errno
));
1080 LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info
->scope_id
);
1087 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1091 return mStatus_BadParamErr
;
1095 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1096 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
1098 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1099 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
1101 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1102 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1103 if (s
< 0) return(mStatus_Invalid
);
1105 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
1108 static int MessageCount
= 0;
1109 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1110 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
1111 if (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== EHOSTUNREACH
|| errno
== ENETUNREACH
) return(mStatus_TransientErr
);
1112 // Don't report EHOSTUNREACH in the first three minutes after boot
1113 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1114 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1115 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(mStatus_TransientErr
);
1116 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1117 if (errno
== EADDRNOTAVAIL
&& m
->p
->NetworkChanged
) return(mStatus_TransientErr
);
1118 if (MessageCount
< 1000)
1121 if (errno
== EHOSTUNREACH
|| errno
== EADDRNOTAVAIL
|| errno
== ENETDOWN
)
1122 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1123 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
1125 LogMsg("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1126 s
, InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
1128 result
= mStatus_UnknownErr
;
1132 if (dst
->type
== mDNSAddrType_IPv4
&& info
&& !mDNSAddrIsDNSMulticast(dst
))
1134 static const mDNSu32 ifindex
= 0;
1135 setsockopt(s
, IPPROTO_IP
, IP_BOUND_IF
, &ifindex
, sizeof(ifindex
));
1142 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
1143 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
1145 static unsigned int numLogMessages
= 0;
1146 struct iovec databuffers
= { (char *)buffer
, max
};
1149 struct cmsghdr
*cmPtr
;
1150 char ancillary
[1024];
1152 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1154 // Set up the message
1155 msg
.msg_name
= (caddr_t
)from
;
1156 msg
.msg_namelen
= *fromlen
;
1157 msg
.msg_iov
= &databuffers
;
1159 msg
.msg_control
= (caddr_t
)&ancillary
;
1160 msg
.msg_controllen
= sizeof(ancillary
);
1164 n
= recvmsg(s
, &msg
, 0);
1167 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
1170 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
1172 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1173 s
, n
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
1176 if (msg
.msg_flags
& MSG_CTRUNC
)
1178 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
1182 *fromlen
= msg
.msg_namelen
;
1184 // Parse each option out of the ancillary data.
1185 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
1187 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1188 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
1190 dstaddr
->type
= mDNSAddrType_IPv4
;
1191 dstaddr
->ip
.v4
= *(mDNSv4Addr
*)CMSG_DATA(cmPtr
);
1192 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
1194 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
1196 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
1197 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
1199 mDNSPlatformMemCopy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
1200 ifname
[sdl
->sdl_nlen
] = 0;
1201 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1204 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
1205 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
1206 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
1208 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
1209 dstaddr
->type
= mDNSAddrType_IPv6
;
1210 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
1211 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
1213 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
1214 *ttl
= *(int*)CMSG_DATA(cmPtr
);
1220 mDNSlocal
void myKQSocketCallBack(int s1
, short filter
, void *context
)
1222 KQSocketSet
*const ss
= (KQSocketSet
*)context
;
1223 mDNS
*const m
= ss
->m
;
1224 int err
= 0, count
= 0, closed
= 0;
1226 if (filter
!= EVFILT_READ
)
1227 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter
, EVFILT_READ
);
1235 LogMsg("myKQSocketCallBack: native socket %d", s1
);
1236 LogMsg("myKQSocketCallBack: sktv4 %d", ss
->sktv4
);
1238 LogMsg("myKQSocketCallBack: sktv6 %d", ss
->sktv6
);
1244 mDNSAddr senderAddr
, destAddr
;
1245 mDNSIPPort senderPort
;
1246 struct sockaddr_storage from
;
1247 size_t fromlen
= sizeof(from
);
1248 char packetifname
[IF_NAMESIZE
] = "";
1250 err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
1254 if (from
.ss_family
== AF_INET
)
1256 struct sockaddr_in
*s
= (struct sockaddr_in
*)&from
;
1257 senderAddr
.type
= mDNSAddrType_IPv4
;
1258 senderAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
1259 senderPort
.NotAnInteger
= s
->sin_port
;
1260 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1262 else if (from
.ss_family
== AF_INET6
)
1264 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
1265 senderAddr
.type
= mDNSAddrType_IPv6
;
1266 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
1267 senderPort
.NotAnInteger
= sin6
->sin6_port
;
1268 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1272 LogMsg("myKQSocketCallBack from is unknown address family %d", from
.ss_family
);
1276 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1277 mDNSInterfaceID InterfaceID
= mDNSNULL
;
1278 //NetworkInterfaceInfo *intf = m->HostInterfaces;
1279 //while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
1281 NetworkInterfaceInfoOSX
*intf
= m
->p
->InterfaceList
;
1282 while (intf
&& strcmp(intf
->ifinfo
.ifname
, packetifname
)) intf
= intf
->next
;
1284 // When going to sleep we deregister all our interfaces, but if the machine
1285 // takes a few seconds to sleep we may continue to receive multicasts
1286 // during that time, which would confuse mDNSCoreReceive, because as far
1287 // as it's concerned, we should have no active interfaces any more.
1288 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1289 if (intf
) InterfaceID
= intf
->ifinfo
.InterfaceID
;
1290 else if (mDNSAddrIsDNSMulticast(&destAddr
)) continue;
1292 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1293 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
1295 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
1296 // loop when that happens, or we may try to read from an invalid FD. We do this by
1297 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
1298 // if it closes the socketset.
1299 ss
->closeFlag
= &closed
;
1301 mDNSCoreReceive(m
, &m
->imsg
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, ss
->port
, InterfaceID
);
1303 // if we didn't close, we can safely dereference the socketset, and should to
1304 // reset the closeFlag, since it points to something on the stack
1305 if (!closed
) ss
->closeFlag
= mDNSNULL
;
1308 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
1310 // Something is busted here.
1311 // kqueue says there is a packet, but myrecvfrom says there is not.
1312 // Try calling select() to get another opinion.
1313 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1314 // All of this is racy, as data may have arrived after the call to select()
1315 static unsigned int numLogMessages
= 0;
1316 int save_errno
= errno
;
1320 socklen_t solen
= sizeof(int);
1322 struct timeval timeout
;
1325 FD_SET(s1
, &readfds
);
1327 timeout
.tv_usec
= 0;
1328 selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
1329 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
1330 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
1331 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
1332 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
1333 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
1334 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno
);
1335 if (numLogMessages
++ < 100)
1336 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1337 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
1338 if (numLogMessages
> 5)
1339 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1340 "Congratulations, you've reproduced an elusive bug.\r"
1341 "Please contact the current assignee of <rdar://problem/3375328>.\r"
1342 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1343 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1345 sleep(1); // After logging this error, rate limit so we don't flood syslog
1349 // TCP socket support
1354 handshake_in_progress
,
1355 handshake_completed
,
1356 handshake_to_be_closed
1359 struct TCPSocket_struct
1361 TCPSocketFlags flags
; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
1362 TCPConnectionCallback callback
;
1364 KQueueEntry
*kqEntry
;
1366 #ifndef NO_SECURITYFRAMEWORK
1367 SSLContextRef tlsContext
;
1368 pthread_t handshake_thread
;
1369 #endif /* NO_SECURITYFRAMEWORK */
1370 domainname hostname
;
1374 handshakeStatus handshake
;
1375 mDNS
*m
; // So we can call KQueueLock from the SSLHandshake thread
1379 mDNSlocal
void doTcpSocketCallback(TCPSocket
*sock
)
1381 mDNSBool c
= !sock
->connected
;
1382 sock
->connected
= mDNStrue
;
1383 sock
->callback(sock
, sock
->context
, c
, sock
->err
);
1384 // Note: the callback may call CloseConnection here, which frees the context structure!
1387 #ifndef NO_SECURITYFRAMEWORK
1389 mDNSlocal OSStatus
tlsWriteSock(SSLConnectionRef connection
, const void *data
, size_t *dataLength
)
1391 int ret
= send(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1392 if (ret
>= 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1393 if (ret
>= 0) { *dataLength
= ret
; return(noErr
); }
1395 if (errno
== EAGAIN
) return(errSSLWouldBlock
);
1396 if (errno
== ENOENT
) return(errSSLClosedGraceful
);
1397 if (errno
== EPIPE
|| errno
== ECONNRESET
) return(errSSLClosedAbort
);
1398 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket
*)connection
)->fd
, errno
, strerror(errno
));
1399 return(errSSLClosedAbort
);
1402 mDNSlocal OSStatus
tlsReadSock(SSLConnectionRef connection
, void *data
, size_t *dataLength
)
1404 int ret
= recv(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1405 if (ret
> 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1406 if (ret
> 0) { *dataLength
= ret
; return(noErr
); }
1408 if (ret
== 0 || errno
== ENOENT
) return(errSSLClosedGraceful
);
1409 if ( errno
== EAGAIN
) return(errSSLWouldBlock
);
1410 if ( errno
== ECONNRESET
) return(errSSLClosedAbort
);
1411 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno
, strerror(errno
));
1412 return(errSSLClosedAbort
);
1415 mDNSlocal OSStatus
tlsSetupSock(TCPSocket
*sock
, mDNSBool server
)
1417 char domname_cstr
[MAX_ESCAPED_DOMAIN_NAME
];
1419 mStatus err
= SSLNewContext(server
, &sock
->tlsContext
);
1420 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err
); return(err
); }
1422 err
= SSLSetIOFuncs(sock
->tlsContext
, tlsReadSock
, tlsWriteSock
);
1423 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err
); return(err
); }
1425 err
= SSLSetConnection(sock
->tlsContext
, (SSLConnectionRef
) sock
);
1426 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err
); return(err
); }
1428 // Instead of listing all the acceptable ciphers, we just disable the bad ciphers. It does not disable
1429 // all the bad ciphers like RC4_MD5, but it assumes that the servers don't offer them.
1430 err
= SSLSetAllowAnonymousCiphers(sock
->tlsContext
, 0);
1431 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err
); return(err
); }
1433 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
1434 // (error not in OSStatus space) is okay.
1435 if (!sock
->hostname
.c
[0]) {LogMsg("ERROR: tlsSetupSock: hostname NULL"); return -1; }
1437 ConvertDomainNameToCString(&sock
->hostname
, domname_cstr
);
1438 err
= SSLSetPeerDomainName(sock
->tlsContext
, domname_cstr
, strlen(domname_cstr
));
1439 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr
, err
); return(err
); }
1444 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1445 mDNSlocal
void doSSLHandshake(void *ctx
)
1447 TCPSocket
*sock
= (TCPSocket
*)ctx
;
1448 mStatus err
= SSLHandshake(sock
->tlsContext
);
1450 //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
1451 //defined, KQueueLock is a noop. Hence we need to serialize here
1453 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
1454 //We need the rest of the logic also. Otherwise, we can enable the READ
1455 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
1456 //ConnFailed which means we are going to free the tcpInfo. While it
1457 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
1458 //and potentially call doTCPCallback with error which can close the fd and free the
1459 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
1462 dispatch_async(dispatch_get_main_queue(), ^{
1464 LogInfo("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
1466 if (sock
->handshake
== handshake_to_be_closed
)
1468 LogInfo("SSLHandshake completed after close");
1469 mDNSPlatformTCPCloseConnection(sock
);
1473 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1474 else LogMsg("doSSLHandshake: sock->fd is -1");
1476 if (err
== errSSLWouldBlock
)
1477 sock
->handshake
= handshake_required
;
1482 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
1483 SSLDisposeContext(sock
->tlsContext
);
1484 sock
->tlsContext
= NULL
;
1487 sock
->err
= err
? mStatus_ConnFailed
: 0;
1488 sock
->handshake
= handshake_completed
;
1490 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
1491 doTcpSocketCallback(sock
);
1495 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
1500 mDNSlocal
void *doSSLHandshake(void *ctx
)
1502 // Warning: Touching sock without the kqueue lock!
1503 // We're protected because sock->handshake == handshake_in_progress
1504 TCPSocket
*sock
= (TCPSocket
*)ctx
;
1505 mDNS
* const m
= sock
->m
; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
1506 mStatus err
= SSLHandshake(sock
->tlsContext
);
1509 debugf("doSSLHandshake %p: got lock", sock
); // Log *after* we get the lock
1511 if (sock
->handshake
== handshake_to_be_closed
)
1513 LogInfo("SSLHandshake completed after close");
1514 mDNSPlatformTCPCloseConnection(sock
);
1518 if (sock
->fd
!= -1) KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1519 else LogMsg("doSSLHandshake: sock->fd is -1");
1521 if (err
== errSSLWouldBlock
)
1522 sock
->handshake
= handshake_required
;
1527 LogMsg("SSLHandshake failed: %d%s", err
, err
== errSSLPeerInternalError
? " (server busy)" : "");
1528 SSLDisposeContext(sock
->tlsContext
);
1529 sock
->tlsContext
= NULL
;
1532 sock
->err
= err
? mStatus_ConnFailed
: 0;
1533 sock
->handshake
= handshake_completed
;
1535 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock
, sock
->fd
);
1536 doTcpSocketCallback(sock
);
1540 debugf("SSLHandshake %p: dropping lock for fd %d", sock
, sock
->fd
);
1541 KQueueUnlock(m
, "doSSLHandshake");
1546 mDNSlocal mStatus
spawnSSLHandshake(TCPSocket
* sock
)
1548 debugf("spawnSSLHandshake %p: entry", sock
);
1551 if (sock
->handshake
!= handshake_required
) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock
->handshake
);
1552 sock
->handshake
= handshake_in_progress
;
1553 KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_READ
, sock
->kqEntry
);
1554 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1556 // Dispatch it on a separate serial queue to avoid deadlocks with threads running on main queue
1557 dispatch_async(SSLqueue
, ^{doSSLHandshake(sock
);});
1560 pthread_attr_t attr
;
1561 pthread_attr_init(&attr
);
1562 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
1563 err
= pthread_create(&sock
->handshake_thread
, &attr
, doSSLHandshake
, sock
);
1564 pthread_attr_destroy(&attr
);
1567 LogMsg("Could not start SSLHandshake thread: (%d) %s", err
, strerror(err
));
1568 sock
->handshake
= handshake_completed
;
1570 KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, sock
->kqEntry
);
1573 debugf("spawnSSLHandshake %p: done for %d", sock
, sock
->fd
);
1577 mDNSlocal mDNSBool
IsTunnelModeDomain(const domainname
*d
)
1579 static const domainname
*mmc
= (const domainname
*) "\x7" "members" "\x3" "mac" "\x3" "com";
1580 const domainname
*d1
= mDNSNULL
; // TLD
1581 const domainname
*d2
= mDNSNULL
; // SLD
1582 const domainname
*d3
= mDNSNULL
;
1583 while (d
->c
[0]) { d3
= d2
; d2
= d1
; d1
= d
; d
= (const domainname
*)(d
->c
+ 1 + d
->c
[0]); }
1584 return(d3
&& SameDomainName(d3
, mmc
));
1587 #endif /* NO_SECURITYFRAMEWORK */
1589 mDNSlocal
void tcpKQSocketCallback(__unused
int fd
, short filter
, void *context
)
1591 TCPSocket
*sock
= context
;
1592 sock
->err
= mStatus_NoError
;
1594 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1595 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1596 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1597 if (filter
== EVFILT_WRITE
) KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_WRITE
, sock
->kqEntry
);
1599 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1601 #ifndef NO_SECURITYFRAMEWORK
1602 if (!sock
->setup
) { sock
->setup
= mDNStrue
; tlsSetupSock(sock
, mDNSfalse
); }
1604 if (sock
->handshake
== handshake_required
) { if (spawnSSLHandshake(sock
) == 0) return; }
1605 else if (sock
->handshake
== handshake_in_progress
|| sock
->handshake
== handshake_to_be_closed
) return;
1606 else if (sock
->handshake
!= handshake_completed
)
1608 if (!sock
->err
) sock
->err
= mStatus_UnknownErr
;
1609 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock
->handshake
);
1612 sock
->err
= mStatus_UnsupportedErr
;
1613 #endif /* NO_SECURITYFRAMEWORK */
1616 doTcpSocketCallback(sock
);
1619 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1620 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, KQueueEntry
*const entryRef
)
1622 dispatch_queue_t queue
= dispatch_get_main_queue();
1623 dispatch_source_t source
;
1624 if (flags
== EV_DELETE
)
1626 if (filter
== EVFILT_READ
)
1628 dispatch_source_cancel(entryRef
->readSource
);
1629 dispatch_release(entryRef
->readSource
);
1630 entryRef
->readSource
= mDNSNULL
;
1631 debugf("KQueueSet: source cancel for read %p, %p", entryRef
->readSource
, entryRef
->writeSource
);
1633 else if (filter
== EVFILT_WRITE
)
1635 dispatch_source_cancel(entryRef
->writeSource
);
1636 dispatch_release(entryRef
->writeSource
);
1637 entryRef
->writeSource
= mDNSNULL
;
1638 debugf("KQueueSet: source cancel for write %p, %p", entryRef
->readSource
, entryRef
->writeSource
);
1641 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter
);
1644 if (flags
!= EV_ADD
) LogMsg("KQueueSet: Invalid flags %d", flags
);
1646 if (filter
== EVFILT_READ
)
1648 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, fd
, 0, queue
);
1650 else if (filter
== EVFILT_WRITE
)
1652 source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE
, fd
, 0, queue
);
1656 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter
);
1659 if (!source
) return -1;
1660 dispatch_source_set_event_handler(source
, ^{
1662 mDNSs32 stime
= mDNSPlatformRawTime();
1663 entryRef
->KQcallback(fd
, filter
, entryRef
->KQcontext
);
1664 mDNSs32 etime
= mDNSPlatformRawTime();
1665 if (etime
- stime
>= WatchDogReportingThreshold
)
1666 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime
- stime
);
1668 // Trigger the event delivery to the application. Even though we trigger the
1669 // event completion after handling every event source, these all will hopefully
1671 TriggerEventCompletion();
1674 dispatch_source_set_cancel_handler(source
, ^{
1675 if (entryRef
->fdClosed
)
1677 //LogMsg("CancelHandler: closing fd %d", fd);
1681 dispatch_resume(source
);
1682 if (filter
== EVFILT_READ
)
1683 entryRef
->readSource
= source
;
1685 entryRef
->writeSource
= source
;
1690 mDNSexport
void KQueueLock(mDNS
*const m
)
1694 mDNSexport
void KQueueUnlock(mDNS
*const m
, const char const *task
)
1697 (void)task
; //unused
1700 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, const KQueueEntry
*const entryRef
)
1702 struct kevent new_event
;
1703 EV_SET(&new_event
, fd
, filter
, flags
, 0, 0, (void*)entryRef
);
1704 return (kevent(KQueueFD
, &new_event
, 1, NULL
, 0, NULL
) < 0) ? errno
: 0;
1707 mDNSexport
void KQueueLock(mDNS
*const m
)
1709 pthread_mutex_lock(&m
->p
->BigMutex
);
1710 m
->p
->BigMutexStartTime
= mDNSPlatformRawTime();
1713 mDNSexport
void KQueueUnlock(mDNS
*const m
, const char const *task
)
1715 mDNSs32 end
= mDNSPlatformRawTime();
1717 if (end
- m
->p
->BigMutexStartTime
>= WatchDogReportingThreshold
)
1718 LogInfo("WARNING: %s took %dms to complete", task
, end
- m
->p
->BigMutexStartTime
);
1720 pthread_mutex_unlock(&m
->p
->BigMutex
);
1723 if (send(m
->p
->WakeKQueueLoopFD
, &wake
, sizeof(wake
), 0) == -1)
1724 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno
, strerror(errno
));
1728 mDNSexport
void mDNSPlatformCloseFD(KQueueEntry
*kq
, int fd
)
1730 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1734 dispatch_source_cancel(kq
->readSource
);
1735 kq
->readSource
= mDNSNULL
;
1737 if (kq
->writeSource
)
1739 dispatch_source_cancel(kq
->writeSource
);
1740 kq
->writeSource
= mDNSNULL
;
1742 // Close happens in the cancellation handler
1743 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd
);
1744 kq
->fdClosed
= mDNStrue
;
1751 mDNSlocal mStatus
SetupTCPSocket(TCPSocket
*sock
, u_short sa_family
, mDNSIPPort
*port
)
1753 KQSocketSet
*cp
= &sock
->ss
;
1755 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1756 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1758 int *s
= &cp
->sktv4
;
1759 KQueueEntry
*k
= &cp
->kqsv4
;
1761 const int on
= 1; // "on" for setsockopt
1764 int skt
= socket(sa_family
, SOCK_STREAM
, IPPROTO_TCP
);
1765 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
1766 if (sa_family
== AF_INET
)
1769 struct sockaddr_in addr
;
1770 mDNSPlatformMemZero(&addr
, sizeof(addr
));
1771 addr
.sin_family
= AF_INET
;
1772 addr
.sin_port
= port
->NotAnInteger
;
1773 err
= bind(skt
, (struct sockaddr
*) &addr
, sizeof(addr
));
1774 if (err
< 0) { LogMsg("ERROR: bind %s", strerror(errno
)); return err
; }
1776 // Receive interface identifiers
1777 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1778 if (err
< 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
)); return err
; }
1780 mDNSPlatformMemZero(&addr
, sizeof(addr
));
1781 socklen_t len
= sizeof(addr
);
1782 err
= getsockname(skt
, (struct sockaddr
*) &addr
, &len
);
1783 if (err
< 0) { LogMsg("getsockname - %s", strerror(errno
)); return err
; }
1785 port
->NotAnInteger
= addr
.sin_port
;
1790 struct sockaddr_in6 addr6
;
1791 mDNSPlatformMemZero(&addr6
, sizeof(addr6
));
1792 addr6
.sin6_family
= AF_INET6
;
1793 addr6
.sin6_port
= port
->NotAnInteger
;
1794 err
= bind(skt
, (struct sockaddr
*) &addr6
, sizeof(addr6
));
1795 if (err
< 0) { LogMsg("ERROR: bind6 %s", strerror(errno
)); return err
; }
1797 // We want to receive destination addresses and receive interface identifiers
1798 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
1799 if (err
< 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno
)); return err
; }
1801 mDNSPlatformMemZero(&addr6
, sizeof(addr6
));
1802 socklen_t len
= sizeof(addr6
);
1803 err
= getsockname(skt
, (struct sockaddr
*) &addr6
, &len
);
1804 if (err
< 0) { LogMsg("getsockname6 - %s", strerror(errno
)); return err
; }
1806 port
->NotAnInteger
= addr6
.sin6_port
;
1810 k
->KQcallback
= tcpKQSocketCallback
;
1811 k
->KQcontext
= sock
;
1812 k
->KQtask
= "mDNSPlatformTCPSocket";
1813 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1814 k
->readSource
= mDNSNULL
;
1815 k
->writeSource
= mDNSNULL
;
1816 k
->fdClosed
= mDNSfalse
;
1818 return mStatus_NoError
;
1821 mDNSexport TCPSocket
*mDNSPlatformTCPSocket(mDNS
*const m
, TCPSocketFlags flags
, mDNSIPPort
*port
)
1826 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket
));
1827 if (!sock
) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL
); }
1829 mDNSPlatformMemZero(sock
, sizeof(TCPSocket
));
1832 sock
->ss
.sktv4
= -1;
1834 sock
->ss
.sktv6
= -1;
1836 err
= SetupTCPSocket(sock
, AF_INET
, port
);
1840 err
= SetupTCPSocket(sock
, AF_INET6
, port
);
1841 if (err
) { mDNSPlatformCloseFD(&sock
->ss
.kqsv4
, sock
->ss
.sktv4
); sock
->ss
.sktv4
= -1; }
1846 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock
->fd
, errno
, strerror(errno
));
1847 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1851 sock
->callback
= mDNSNULL
;
1852 sock
->flags
= flags
;
1853 sock
->context
= mDNSNULL
;
1854 sock
->setup
= mDNSfalse
;
1855 sock
->connected
= mDNSfalse
;
1856 sock
->handshake
= handshake_required
;
1858 sock
->err
= mStatus_NoError
;
1863 mDNSexport mStatus
mDNSPlatformTCPConnect(TCPSocket
*sock
, const mDNSAddr
*dst
, mDNSOpaque16 dstport
, domainname
*hostname
, mDNSInterfaceID InterfaceID
, TCPConnectionCallback callback
, void *context
)
1865 KQSocketSet
*cp
= &sock
->ss
;
1867 int *s
= (dst
->type
== mDNSAddrType_IPv4
) ? &cp
->sktv4
: &cp
->sktv6
;
1868 KQueueEntry
*k
= (dst
->type
== mDNSAddrType_IPv4
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1870 int *s
= &cp
->sktv4
;
1871 KQueueEntry
*k
= &cp
->kqsv4
;
1873 mStatus err
= mStatus_NoError
;
1874 struct sockaddr_storage ss
;
1876 sock
->callback
= callback
;
1877 sock
->context
= context
;
1878 sock
->setup
= mDNSfalse
;
1879 sock
->connected
= mDNSfalse
;
1880 sock
->handshake
= handshake_required
;
1881 sock
->err
= mStatus_NoError
;
1883 if (hostname
) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname
->c
); AssignDomainName(&sock
->hostname
, hostname
); }
1885 if (dst
->type
== mDNSAddrType_IPv4
)
1887 struct sockaddr_in
*saddr
= (struct sockaddr_in
*)&ss
;
1888 mDNSPlatformMemZero(saddr
, sizeof(*saddr
));
1889 saddr
->sin_family
= AF_INET
;
1890 saddr
->sin_port
= dstport
.NotAnInteger
;
1891 saddr
->sin_len
= sizeof(*saddr
);
1892 saddr
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1896 struct sockaddr_in6
*saddr6
= (struct sockaddr_in6
*)&ss
;
1897 mDNSPlatformMemZero(saddr6
, sizeof(*saddr6
));
1898 saddr6
->sin6_family
= AF_INET6
;
1899 saddr6
->sin6_port
= dstport
.NotAnInteger
;
1900 saddr6
->sin6_len
= sizeof(*saddr6
);
1901 saddr6
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1904 // Watch for connect complete (write is ready)
1905 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1906 if (KQueueSet(*s
, EV_ADD
/* | EV_ONESHOT */, EVFILT_WRITE
, k
))
1908 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1912 // Watch for incoming data
1913 if (KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
))
1915 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1919 if (fcntl(*s
, F_SETFL
, fcntl(*s
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
1921 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1922 return mStatus_UnknownErr
;
1925 // We bind to the interface and all subsequent packets including the SYN will be sent out
1926 // on this interface
1928 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
1929 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
1930 if (InterfaceID
&& InterfaceID
!= mDNSInterface_Unicast
)
1932 extern mDNS mDNSStorage
;
1933 NetworkInterfaceInfoOSX
*info
= IfindexToInterfaceInfoOSX(&mDNSStorage
, InterfaceID
);
1934 if (dst
->type
== mDNSAddrType_IPv4
)
1937 if (info
) setsockopt(*s
, IPPROTO_IP
, IP_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1938 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID
); return mStatus_BadParamErr
; }
1940 (void)InterfaceID
; // Unused
1941 (void)info
; // Unused
1946 #ifdef IPV6_BOUND_IF
1947 if (info
) setsockopt(*s
, IPPROTO_IPV6
, IPV6_BOUND_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1948 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID
); return mStatus_BadParamErr
; }
1950 (void)InterfaceID
; // Unused
1951 (void)info
; // Unused
1956 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
1957 // from which we can infer the destination address family. Hence we need to remember that here.
1958 // Instead of remembering the address family, we remember the right fd.
1961 // initiate connection wth peer
1962 if (connect(*s
, (struct sockaddr
*)&ss
, ss
.ss_len
) < 0)
1964 if (errno
== EINPROGRESS
) return mStatus_ConnPending
;
1965 if (errno
== EHOSTUNREACH
|| errno
== EADDRNOTAVAIL
|| errno
== ENETDOWN
)
1966 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock
->fd
, errno
, strerror(errno
));
1968 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock
->fd
, errno
, strerror(errno
), ss
.ss_len
);
1969 return mStatus_ConnFailed
;
1972 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1973 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1977 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1978 mDNSexport TCPSocket
*mDNSPlatformTCPAccept(TCPSocketFlags flags
, int fd
)
1980 mStatus err
= mStatus_NoError
;
1982 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket
));
1983 if (!sock
) return(mDNSNULL
);
1985 mDNSPlatformMemZero(sock
, sizeof(*sock
));
1987 sock
->flags
= flags
;
1989 if (flags
& kTCPSocketFlags_UseTLS
)
1991 #ifndef NO_SECURITYFRAMEWORK
1992 if (!ServerCerts
) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err
= mStatus_UnknownErr
; goto exit
; }
1994 err
= tlsSetupSock(sock
, mDNStrue
);
1995 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err
); goto exit
; }
1997 err
= SSLSetCertificate(sock
->tlsContext
, ServerCerts
);
1998 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err
); goto exit
; }
2000 err
= mStatus_UnsupportedErr
;
2001 #endif /* NO_SECURITYFRAMEWORK */
2003 #ifndef NO_SECURITYFRAMEWORK
2007 if (err
) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock
); return(mDNSNULL
); }
2011 mDNSlocal
void CloseSocketSet(KQSocketSet
*ss
)
2013 if (ss
->sktv4
!= -1)
2015 mDNSPlatformCloseFD(&ss
->kqsv4
, ss
->sktv4
);
2019 if (ss
->sktv6
!= -1)
2021 mDNSPlatformCloseFD(&ss
->kqsv6
, ss
->sktv6
);
2025 if (ss
->closeFlag
) *ss
->closeFlag
= 1;
2028 mDNSexport
void mDNSPlatformTCPCloseConnection(TCPSocket
*sock
)
2032 #ifndef NO_SECURITYFRAMEWORK
2033 if (sock
->tlsContext
)
2035 if (sock
->handshake
== handshake_in_progress
) // SSLHandshake thread using this sock (esp. tlsContext)
2037 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
2038 // When we come back from SSLHandshake, we will notice that a close was here and
2039 // call this function again which will do the cleanup then.
2040 sock
->handshake
= handshake_to_be_closed
;
2044 SSLClose(sock
->tlsContext
);
2045 SSLDisposeContext(sock
->tlsContext
);
2046 sock
->tlsContext
= NULL
;
2048 #endif /* NO_SECURITYFRAMEWORK */
2049 if (sock
->ss
.sktv4
!= -1) shutdown(sock
->ss
.sktv4
, 2);
2051 if (sock
->ss
.sktv6
!= -1) shutdown(sock
->ss
.sktv6
, 2);
2053 CloseSocketSet(&sock
->ss
);
2056 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock
);
2060 mDNSexport
long mDNSPlatformReadTCP(TCPSocket
*sock
, void *buf
, unsigned long buflen
, mDNSBool
*closed
)
2063 *closed
= mDNSfalse
;
2065 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
2067 #ifndef NO_SECURITYFRAMEWORK
2068 if (sock
->handshake
== handshake_required
) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
2069 else if (sock
->handshake
== handshake_in_progress
) return 0;
2070 else if (sock
->handshake
!= handshake_completed
) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock
->handshake
);
2072 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
2073 mStatus err
= SSLRead(sock
->tlsContext
, buf
, buflen
, &nread
);
2074 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
2075 if (err
== errSSLClosedGraceful
) { nread
= 0; *closed
= mDNStrue
; }
2076 else if (err
&& err
!= errSSLWouldBlock
)
2077 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err
); nread
= -1; *closed
= mDNStrue
; }
2081 #endif /* NO_SECURITYFRAMEWORK */
2085 static int CLOSEDcount
= 0;
2086 static int EAGAINcount
= 0;
2087 nread
= recv(sock
->fd
, buf
, buflen
, 0);
2089 if (nread
> 0) { CLOSEDcount
= 0; EAGAINcount
= 0; } // On success, clear our error counters
2090 else if (nread
== 0)
2093 if ((++CLOSEDcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock
->fd
, CLOSEDcount
); sleep(1); }
2095 // else nread is negative -- see what kind of error we got
2096 else if (errno
== ECONNRESET
) { nread
= 0; *closed
= mDNStrue
; }
2097 else if (errno
!= EAGAIN
) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno
, strerror(errno
)); nread
= -1; }
2098 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
2101 if ((++EAGAINcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock
->fd
, EAGAINcount
); sleep(1); }
2108 mDNSexport
long mDNSPlatformWriteTCP(TCPSocket
*sock
, const char *msg
, unsigned long len
)
2112 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
2114 #ifndef NO_SECURITYFRAMEWORK
2116 if (sock
->handshake
== handshake_required
) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
2117 if (sock
->handshake
== handshake_in_progress
) return 0;
2118 else if (sock
->handshake
!= handshake_completed
) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock
->handshake
);
2120 mStatus err
= SSLWrite(sock
->tlsContext
, msg
, len
, &processed
);
2122 if (!err
) nsent
= (int) processed
;
2123 else if (err
== errSSLWouldBlock
) nsent
= 0;
2124 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err
); nsent
= -1; }
2127 #endif /* NO_SECURITYFRAMEWORK */
2131 nsent
= send(sock
->fd
, msg
, len
, 0);
2134 if (errno
== EAGAIN
) nsent
= 0;
2135 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno
)); nsent
= -1; }
2142 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
2147 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
2148 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
2149 mDNSlocal mStatus
SetupSocket(KQSocketSet
*cp
, const mDNSIPPort port
, u_short sa_family
, mDNSIPPort
*const outport
)
2152 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
2153 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
2155 int *s
= &cp
->sktv4
;
2156 KQueueEntry
*k
= &cp
->kqsv4
;
2159 const int twofivefive
= 255;
2160 mStatus err
= mStatus_NoError
;
2161 char *errstr
= mDNSNULL
;
2164 if (sa_family
!= AF_INET
) return -1;
2167 cp
->closeFlag
= mDNSNULL
;
2169 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
2170 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
2172 // ... with a shared UDP port, if it's for multicast receiving
2173 if (mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSSameIPPort(port
, NATPMPAnnouncementPort
)) err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
2174 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
2176 if (sa_family
== AF_INET
)
2178 // We want to receive destination addresses
2179 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
2180 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
2182 // We want to receive interface identifiers
2183 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
2184 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
2186 // We want to receive packet TTL value so we can check it
2187 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
2188 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
2190 // Send unicast packets with TTL 255
2191 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
2192 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
2194 // And multicast packets with TTL 255 too
2195 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
2196 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
2198 // And start listening for packets
2199 struct sockaddr_in listening_sockaddr
;
2200 listening_sockaddr
.sin_family
= AF_INET
;
2201 listening_sockaddr
.sin_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
2202 listening_sockaddr
.sin_addr
.s_addr
= mDNSSameIPPort(port
, NATPMPAnnouncementPort
) ? AllHosts_v4
.NotAnInteger
: 0;
2203 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
2204 if (err
) { errstr
= "bind"; goto fail
; }
2205 if (outport
) outport
->NotAnInteger
= listening_sockaddr
.sin_port
;
2208 else if (sa_family
== AF_INET6
)
2210 // NAT-PMP Announcements make no sense on IPv6, so bail early w/o error
2211 if (mDNSSameIPPort(port
, NATPMPAnnouncementPort
)) { if (outport
) *outport
= zeroIPPort
; return mStatus_NoError
; }
2213 // We want to receive destination addresses and receive interface identifiers
2214 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
2215 if (err
< 0) { errstr
= "setsockopt - IPV6_RECVPKTINFO"; goto fail
; }
2217 // We want to receive packet hop count value so we can check it
2218 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &on
, sizeof(on
));
2219 if (err
< 0) { errstr
= "setsockopt - IPV6_RECVHOPLIMIT"; goto fail
; }
2221 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
2222 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
2223 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
2224 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
2226 // Send unicast packets with TTL 255
2227 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
2228 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
2230 // And multicast packets with TTL 255 too
2231 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
2232 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
2234 // Want to receive our own packets
2235 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
2236 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
2238 // And start listening for packets
2239 struct sockaddr_in6 listening_sockaddr6
;
2240 mDNSPlatformMemZero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
2241 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
2242 listening_sockaddr6
.sin6_family
= AF_INET6
;
2243 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
2244 listening_sockaddr6
.sin6_flowinfo
= 0;
2245 listening_sockaddr6
.sin6_addr
= in6addr_any
; // Want to receive multicasts AND unicasts on this socket
2246 listening_sockaddr6
.sin6_scope_id
= 0;
2247 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
2248 if (err
) { errstr
= "bind"; goto fail
; }
2249 if (outport
) outport
->NotAnInteger
= listening_sockaddr6
.sin6_port
;
2253 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
2254 fcntl(skt
, F_SETFD
, 1); // set close-on-exec
2256 k
->KQcallback
= myKQSocketCallBack
;
2258 k
->KQtask
= "UDP packet reception";
2259 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2260 k
->readSource
= mDNSNULL
;
2261 k
->writeSource
= mDNSNULL
;
2262 k
->fdClosed
= mDNSfalse
;
2264 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
2269 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
2270 if (strcmp(errstr
, "bind") || mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSIPPortIsZero(port
))
2271 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr
, skt
, mDNSVal16(port
), err
, errno
, strerror(errno
));
2273 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
2274 if (!strcmp(errstr
, "bind") && errno
== EADDRINUSE
)
2277 if (mDNSSameIPPort(port
, MulticastDNSPort
))
2278 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
2279 "Congratulations, you've reproduced an elusive bug.\r"
2280 "Please contact the current assignee of <rdar://problem/3814904>.\r"
2281 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2282 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2285 mDNSPlatformCloseFD(k
, skt
);
2289 mDNSexport UDPSocket
*mDNSPlatformUDPSocket(mDNS
*const m
, const mDNSIPPort requestedport
)
2292 mDNSIPPort port
= requestedport
;
2293 mDNSBool randomizePort
= mDNSIPPortIsZero(requestedport
);
2294 int i
= 10000; // Try at most 10000 times to get a unique random port
2295 UDPSocket
*p
= mallocL("UDPSocket", sizeof(UDPSocket
));
2296 if (!p
) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL
); }
2297 mDNSPlatformMemZero(p
, sizeof(UDPSocket
));
2298 p
->ss
.port
= zeroIPPort
;
2307 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
2308 if (randomizePort
) port
= mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
2309 err
= SetupSocket(&p
->ss
, port
, AF_INET
, &p
->ss
.port
);
2313 err
= SetupSocket(&p
->ss
, port
, AF_INET6
, &p
->ss
.port
);
2314 if (err
) { mDNSPlatformCloseFD(&p
->ss
.kqsv4
, p
->ss
.sktv4
); p
->ss
.sktv4
= -1; }
2318 } while (err
== EADDRINUSE
&& randomizePort
&& i
);
2322 // In customer builds we don't want to log failures with port 5351, because this is a known issue
2323 // of failing to bind to this port when Internet Sharing has already bound to it
2324 // We also don't want to log about port 5350, due to a known bug when some other
2325 // process is bound to it.
2326 if (mDNSSameIPPort(requestedport
, NATPMPPort
) || mDNSSameIPPort(requestedport
, NATPMPAnnouncementPort
))
2327 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
2328 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
2329 freeL("UDPSocket", p
);
2335 mDNSexport
void mDNSPlatformUDPClose(UDPSocket
*sock
)
2337 CloseSocketSet(&sock
->ss
);
2338 freeL("UDPSocket", sock
);
2341 #if COMPILER_LIKES_PRAGMA_MARK
2343 #pragma mark - BPF Raw packet sending/receiving
2346 #if APPLE_OSX_mDNSResponder
2348 mDNSexport
void mDNSPlatformSendRawPacket(const void *const msg
, const mDNSu8
*const end
, mDNSInterfaceID InterfaceID
)
2350 if (!InterfaceID
) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2351 NetworkInterfaceInfoOSX
*info
;
2353 extern mDNS mDNSStorage
;
2354 info
= IfindexToInterfaceInfoOSX(&mDNSStorage
, InterfaceID
);
2357 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID
);
2360 if (info
->BPF_fd
< 0)
2361 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info
->ifinfo
.ifname
, info
->BPF_fd
);
2364 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
2365 if (write(info
->BPF_fd
, msg
, end
- (mDNSu8
*)msg
) < 0)
2366 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info
->BPF_fd
, errno
, strerror(errno
));
2370 mDNSexport
void mDNSPlatformSetLocalAddressCacheEntry(mDNS
*const m
, const mDNSAddr
*const tpa
, const mDNSEthAddr
*const tha
, mDNSInterfaceID InterfaceID
)
2372 if (!InterfaceID
) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
2373 NetworkInterfaceInfoOSX
*info
;
2374 info
= IfindexToInterfaceInfoOSX(m
, InterfaceID
);
2375 if (info
== NULL
) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID
); return; }
2376 // Manually inject an entry into our local ARP cache.
2377 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
2378 if (!mDNS_AddressIsLocalSubnet(m
, InterfaceID
, tpa
))
2379 LogSPS("Don't need address cache entry for %s %#a %.6a", info
->ifinfo
.ifname
, tpa
, tha
);
2382 int result
= mDNSSetLocalAddressCacheEntry(info
->scope_id
, tpa
->type
, tpa
->ip
.v6
.b
, tha
->b
);
2383 if (result
) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info
->ifinfo
.ifname
, tpa
, tha
, result
);
2384 else LogSPS("Set local address cache entry for %s %#a %.6a", info
->ifinfo
.ifname
, tpa
, tha
);
2388 mDNSlocal
void CloseBPF(NetworkInterfaceInfoOSX
*const i
)
2390 LogSPS("%s closing BPF fd %d", i
->ifinfo
.ifname
, i
->BPF_fd
);
2391 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2392 // close will happen in the cancel handler
2393 dispatch_source_cancel(i
->BPF_source
);
2396 // Note: MUST NOT close() the underlying native BSD sockets.
2397 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
2398 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
2399 CFRunLoopRemoveSource(i
->m
->p
->CFRunLoop
, i
->BPF_rls
, kCFRunLoopDefaultMode
);
2400 CFRelease(i
->BPF_rls
);
2401 CFSocketInvalidate(i
->BPF_cfs
);
2402 CFRelease(i
->BPF_cfs
);
2405 if (i
->BPF_mcfd
>= 0) { close(i
->BPF_mcfd
); i
->BPF_mcfd
= -1; }
2408 mDNSlocal
void bpf_callback_common(NetworkInterfaceInfoOSX
*info
)
2410 KQueueLock(info
->m
);
2412 // 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
2413 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
2414 if (info
->BPF_fd
< 0) goto exit
;
2416 ssize_t n
= read(info
->BPF_fd
, &info
->m
->imsg
, info
->BPF_len
);
2417 const mDNSu8
*ptr
= (const mDNSu8
*)&info
->m
->imsg
;
2418 const mDNSu8
*end
= (const mDNSu8
*)&info
->m
->imsg
+ n
;
2419 debugf("%3d: bpf_callback got %d bytes on %s", info
->BPF_fd
, n
, info
->ifinfo
.ifname
);
2423 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info
->ifinfo
.ifname
, info
->BPF_fd
, errno
, strerror(errno
));
2430 const struct bpf_hdr
*const bh
= (const struct bpf_hdr
*)ptr
;
2431 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
2432 info
->BPF_fd
, ptr
, bh
->bh_hdrlen
, ptr
+ bh
->bh_hdrlen
, bh
->bh_caplen
, bh
->bh_datalen
,
2433 ptr
+ BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
), end
- (ptr
+ BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
)));
2434 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
2435 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
2436 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
2437 mDNSCoreReceiveRawPacket(info
->m
, ptr
+ bh
->bh_hdrlen
, ptr
+ bh
->bh_hdrlen
+ bh
->bh_caplen
, info
->ifinfo
.InterfaceID
);
2438 ptr
+= BPF_WORDALIGN(bh
->bh_hdrlen
+ bh
->bh_caplen
);
2441 KQueueUnlock(info
->m
, "bpf_callback");
2443 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2444 mDNSlocal
void bpf_callback_dispatch(NetworkInterfaceInfoOSX
*const info
)
2446 bpf_callback_common(info
);
2449 mDNSlocal
void bpf_callback(const CFSocketRef cfs
, const CFSocketCallBackType CallBackType
, const CFDataRef address
, const void *const data
, void *const context
)
2455 bpf_callback_common((NetworkInterfaceInfoOSX
*)context
);
2459 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2461 mDNSlocal
int CountProxyTargets(mDNS
*const m
, NetworkInterfaceInfoOSX
*x
, int *p4
, int *p6
)
2463 int numv4
= 0, numv6
= 0;
2466 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2467 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2469 if (p4
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv4
, &rr
->AddressProxy
.ip
.v4
);
2473 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2474 if (rr
->resrec
.InterfaceID
== x
->ifinfo
.InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
2476 if (p6
) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x
->BPF_fd
, x
->ifinfo
.ifname
, numv6
, &rr
->AddressProxy
.ip
.v6
);
2480 if (p4
) *p4
= numv4
;
2481 if (p6
) *p6
= numv6
;
2482 return(numv4
+ numv6
);
2485 mDNSexport
void mDNSPlatformUpdateProxyList(mDNS
*const m
, const mDNSInterfaceID InterfaceID
)
2487 NetworkInterfaceInfoOSX
*x
;
2489 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
2490 for (x
= m
->p
->InterfaceList
; x
; x
= x
->next
) if (x
->ifinfo
.InterfaceID
== InterfaceID
) break;
2492 if (!x
) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID
); return; }
2494 #define MAX_BPF_ADDRS 250
2495 int numv4
= 0, numv6
= 0;
2497 if (CountProxyTargets(m
, x
, &numv4
, &numv6
) > MAX_BPF_ADDRS
)
2499 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4
, numv6
);
2500 if (numv4
> MAX_BPF_ADDRS
) numv4
= MAX_BPF_ADDRS
;
2501 numv6
= MAX_BPF_ADDRS
- numv4
;
2504 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x
->BPF_fd
, x
->ifinfo
.ifname
, &x
->ifinfo
.MAC
, numv4
, numv6
);
2506 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
2507 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
2508 static struct bpf_insn filter
[17 + MAX_BPF_ADDRS
] =
2510 BPF_STMT(BPF_LD
+ BPF_H
+ BPF_ABS
, 12), // 0 Read Ethertype (bytes 12,13)
2512 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
2513 BPF_STMT(BPF_RET
+ BPF_K
, 42), // 2 Return 42-byte ARP
2515 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
2517 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
2518 BPF_STMT(BPF_LD
+ BPF_H
+ BPF_ABS
, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
2519 BPF_JUMP(BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
2520 BPF_STMT(BPF_RET
+ BPF_K
, 86), // 7 Return 86-byte ND
2522 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
2523 BPF_STMT(BPF_LD
+ BPF_W
+ BPF_ABS
, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
2526 struct bpf_insn
*pc
= &filter
[9];
2527 struct bpf_insn
*chk6
= pc
+ numv4
+ 1; // numv4 address checks, plus a "return 0"
2528 struct bpf_insn
*fail
= chk6
+ 1 + numv6
; // Get v6 Dst LSW, plus numv6 address checks
2529 struct bpf_insn
*ret4
= fail
+ 1;
2530 struct bpf_insn
*ret6
= ret4
+ 4;
2532 static const struct bpf_insn rf
= BPF_STMT(BPF_RET
+ BPF_K
, 0); // No match: Return nothing
2534 static const struct bpf_insn g6
= BPF_STMT(BPF_LD
+ BPF_W
+ BPF_ABS
, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
2536 static const struct bpf_insn r4a
= BPF_STMT(BPF_LDX
+ BPF_B
+ BPF_MSH
, 14); // Get IP Header length (normally 20)
2537 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)
2538 static const struct bpf_insn r4c
= BPF_STMT(BPF_ALU
+ BPF_ADD
+ BPF_X
, 0); // A += IP Header length
2539 static const struct bpf_insn r4d
= BPF_STMT(BPF_RET
+ BPF_A
, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
2541 static const struct bpf_insn r6a
= BPF_STMT(BPF_RET
+ BPF_K
, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
2543 BPF_SetOffset(&filter
[4], jf
, fail
); // If Ethertype not ARP, IPv4, or IPv6, fail
2544 BPF_SetOffset(&filter
[6], jf
, chk6
); // If IPv6 but not ICMPv6, go to IPv6 address list check
2546 // BPF Byte-Order Note
2547 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
2548 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
2549 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
2550 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
2551 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
2552 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
2553 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
2554 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
2555 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
2556 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
2558 // IPSEC capture size notes:
2559 // 8 bytes UDP header
2560 // 4 bytes Non-ESP Marker
2561 // 28 bytes IKE Header
2563 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
2566 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2567 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2569 mDNSv4Addr a
= rr
->AddressProxy
.ip
.v4
;
2570 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
2571 BPF_SetOffset(pc
, jt
, ret4
);
2573 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];
2578 if (pc
!= chk6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc
, chk6
);
2579 *pc
++ = g6
; // chk6 points here
2581 // First cancel any previous ND group memberships we had, then create a fresh socket
2582 if (x
->BPF_mcfd
>= 0) close(x
->BPF_mcfd
);
2583 x
->BPF_mcfd
= socket(AF_INET6
, SOCK_DGRAM
, 0);
2585 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2586 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
2588 const mDNSv6Addr
*const a
= &rr
->AddressProxy
.ip
.v6
;
2589 pc
->code
= BPF_JMP
+ BPF_JEQ
+ BPF_K
;
2590 BPF_SetOffset(pc
, jt
, ret6
);
2592 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];
2595 struct ipv6_mreq i6mr
;
2596 i6mr
.ipv6mr_interface
= x
->scope_id
;
2597 i6mr
.ipv6mr_multiaddr
= *(const struct in6_addr
*)&NDP_prefix
;
2598 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xD] = a
->b
[0xD];
2599 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xE] = a
->b
[0xE];
2600 i6mr
.ipv6mr_multiaddr
.s6_addr
[0xF] = a
->b
[0xF];
2602 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
2603 mStatus err
= setsockopt(x
->BPF_mcfd
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
2604 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
2605 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2607 err
= setsockopt(x
->BPF_mcfd
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
2608 if (err
< 0 && (errno
!= EADDRINUSE
)) // Joining same group twice can give "Address already in use" error -- no need to report that
2609 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2611 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr
.ipv6mr_multiaddr
, a
);
2614 if (pc
!= fail
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc
, fail
);
2615 *pc
++ = rf
; // fail points here
2617 if (pc
!= ret4
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc
, ret4
);
2618 *pc
++ = r4a
; // ret4 points here
2623 if (pc
!= ret6
) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc
, ret6
);
2624 *pc
++ = r6a
; // ret6 points here
2626 struct bpf_program prog
= { pc
- filter
, filter
};
2629 // For debugging BPF filter program
2631 for (q
=0; q
<prog
.bf_len
; q
++)
2632 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
);
2635 if (!numv4
&& !numv6
)
2637 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
2638 if (m
->timenow
== 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
2639 // Schedule check to see if we can close this BPF_fd now
2640 if (!m
->p
->NetworkChanged
) m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2);
2641 // prog.bf_len = 0; This seems to panic the kernel
2642 if (x
->BPF_fd
< 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
2645 if (ioctl(x
->BPF_fd
, BIOCSETF
, &prog
) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETF(%d) failed %d (%s)", prog
.bf_len
, errno
, strerror(errno
));
2646 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETF(%d) successful", prog
.bf_len
);
2649 mDNSexport
void mDNSPlatformReceiveBPF_fd(mDNS
*const m
, int fd
)
2653 NetworkInterfaceInfoOSX
*i
;
2654 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
) if (i
->BPF_fd
== -2) break;
2655 if (!i
) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd
); close(fd
); }
2658 LogSPS("%s using BPF fd %d", i
->ifinfo
.ifname
, fd
);
2660 struct bpf_version v
;
2661 if (ioctl(fd
, BIOCVERSION
, &v
) < 0)
2662 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2663 else if (BPF_MAJOR_VERSION
!= v
.bv_major
|| BPF_MINOR_VERSION
!= v
.bv_minor
)
2664 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
2665 fd
, i
->ifinfo
.ifname
, BPF_MAJOR_VERSION
, BPF_MINOR_VERSION
, v
.bv_major
, v
.bv_minor
);
2667 if (ioctl(fd
, BIOCGBLEN
, &i
->BPF_len
) < 0)
2668 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2670 if (i
->BPF_len
> sizeof(m
->imsg
))
2672 i
->BPF_len
= sizeof(m
->imsg
);
2673 if (ioctl(fd
, BIOCSBLEN
, &i
->BPF_len
) < 0)
2674 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2676 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd
, i
->ifinfo
.ifname
, i
->BPF_len
);
2679 static const u_int opt_one
= 1;
2680 if (ioctl(fd
, BIOCIMMEDIATE
, &opt_one
) < 0)
2681 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
));
2683 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
2684 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2686 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
2687 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2690 mDNSPlatformMemZero(&ifr
, sizeof(ifr
));
2691 strlcpy(ifr
.ifr_name
, i
->ifinfo
.ifname
, sizeof(ifr
.ifr_name
));
2692 if (ioctl(fd
, BIOCSETIF
, &ifr
) < 0)
2693 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd
, i
->ifinfo
.ifname
, errno
, strerror(errno
)); i
->BPF_fd
= -3; }
2696 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2698 i
->BPF_source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, fd
, 0, dispatch_get_main_queue());
2699 if (!i
->BPF_source
) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed");return;}
2700 dispatch_source_set_event_handler(i
->BPF_source
, ^{bpf_callback_dispatch(i
);});
2701 dispatch_source_set_cancel_handler(i
->BPF_source
, ^{close(fd
);});
2702 dispatch_resume(i
->BPF_source
);
2704 CFSocketContext myCFSocketContext
= { 0, i
, NULL
, NULL
, NULL
};
2706 i
->BPF_cfs
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
, bpf_callback
, &myCFSocketContext
);
2707 i
->BPF_rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, i
->BPF_cfs
, 0);
2708 CFRunLoopAddSource(i
->m
->p
->CFRunLoop
, i
->BPF_rls
, kCFRunLoopDefaultMode
);
2710 mDNSPlatformUpdateProxyList(m
, i
->ifinfo
.InterfaceID
);
2717 #endif // APPLE_OSX_mDNSResponder
2719 #if COMPILER_LIKES_PRAGMA_MARK
2721 #pragma mark - Key Management
2724 #ifndef NO_SECURITYFRAMEWORK
2725 mDNSlocal CFArrayRef
GetCertChain(SecIdentityRef identity
)
2727 CFMutableArrayRef certChain
= NULL
;
2728 if (!identity
) { LogMsg("getCertChain: identity is NULL"); return(NULL
); }
2729 SecCertificateRef cert
;
2730 OSStatus err
= SecIdentityCopyCertificate(identity
, &cert
);
2731 if (err
|| !cert
) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err
);
2734 SecPolicySearchRef searchRef
;
2735 err
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, &CSSMOID_APPLE_X509_BASIC
, NULL
, &searchRef
);
2736 if (err
|| !searchRef
) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err
);
2739 SecPolicyRef policy
;
2740 err
= SecPolicySearchCopyNext(searchRef
, &policy
);
2741 if (err
|| !policy
) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err
);
2744 CFArrayRef wrappedCert
= CFArrayCreate(NULL
, (const void**) &cert
, 1, &kCFTypeArrayCallBacks
);
2745 if (!wrappedCert
) LogMsg("getCertChain: wrappedCert is NULL");
2749 err
= SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
);
2750 if (err
|| !trust
) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err
);
2753 err
= SecTrustEvaluate(trust
, NULL
);
2754 if (err
) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err
);
2757 CFArrayRef rawCertChain
;
2758 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
2759 err
= SecTrustGetResult(trust
, NULL
, &rawCertChain
, &statusChain
);
2760 if (err
|| !rawCertChain
|| !statusChain
) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err
);
2763 certChain
= CFArrayCreateMutableCopy(NULL
, 0, rawCertChain
);
2764 if (!certChain
) LogMsg("getCertChain: certChain is NULL");
2767 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
2768 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
2769 CFArraySetValueAtIndex(certChain
, 0, identity
);
2770 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
2771 if (CFArrayGetCount(certChain
) > 1) CFArrayRemoveValueAtIndex(certChain
, CFArrayGetCount(certChain
) - 1);
2773 CFRelease(rawCertChain
);
2774 // Do not free statusChain:
2775 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
2776 // certChain: Call the CFRelease function to release this object when you are finished with it.
2777 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
2782 CFRelease(wrappedCert
);
2786 CFRelease(searchRef
);
2792 #endif /* NO_SECURITYFRAMEWORK */
2794 mDNSexport mStatus
mDNSPlatformTLSSetupCerts(void)
2796 #ifdef NO_SECURITYFRAMEWORK
2797 return mStatus_UnsupportedErr
;
2799 SecIdentityRef identity
= nil
;
2800 SecIdentitySearchRef srchRef
= nil
;
2803 // search for "any" identity matching specified key use
2804 // In this app, we expect there to be exactly one
2805 err
= SecIdentitySearchCreate(NULL
, CSSM_KEYUSE_DECRYPT
, &srchRef
);
2806 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err
); return err
; }
2808 err
= SecIdentitySearchCopyNext(srchRef
, &identity
);
2809 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err
); return err
; }
2811 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
2812 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr
; }
2814 // Found one. Call getCertChain to create the correct certificate chain.
2815 ServerCerts
= GetCertChain(identity
);
2816 if (ServerCerts
== nil
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr
; }
2818 return mStatus_NoError
;
2819 #endif /* NO_SECURITYFRAMEWORK */
2822 mDNSexport
void mDNSPlatformTLSTearDownCerts(void)
2824 #ifndef NO_SECURITYFRAMEWORK
2825 if (ServerCerts
) { CFRelease(ServerCerts
); ServerCerts
= NULL
; }
2826 #endif /* NO_SECURITYFRAMEWORK */
2829 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
2830 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
2832 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
2833 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
2836 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
2841 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
2842 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
2844 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
2847 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
2852 mDNSexport mDNSBool
DictionaryIsEnabled(CFDictionaryRef dict
)
2855 CFNumberRef state
= (CFNumberRef
)CFDictionaryGetValue(dict
, CFSTR("Enabled"));
2856 if (!state
) return mDNSfalse
;
2857 if (!CFNumberGetValue(state
, kCFNumberSInt32Type
, &val
))
2858 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse
; }
2859 return val
? mDNStrue
: mDNSfalse
;
2862 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
2864 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
2866 if (sa
->sa_family
== AF_INET
)
2868 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
2869 ip
->type
= mDNSAddrType_IPv4
;
2870 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
2871 return(mStatus_NoError
);
2874 if (sa
->sa_family
== AF_INET6
)
2876 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
2877 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
2878 // value into the second word of the IPv6 link-local address, so they can just
2879 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
2880 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
2881 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
2882 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
2883 ip
->type
= mDNSAddrType_IPv6
;
2884 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
2885 return(mStatus_NoError
);
2888 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
2889 return(mStatus_Invalid
);
2892 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
2894 mDNSEthAddr eth
= zeroEthAddr
;
2895 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetBSSID"), NULL
, NULL
);
2897 LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
2900 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
2903 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, entityname
);
2906 CFRange range
= { 0, 6 }; // Offset, length
2907 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
2908 if (data
&& CFDataGetLength(data
) == 6) CFDataGetBytes(data
, range
, eth
.b
);
2911 CFRelease(entityname
);
2918 mDNSlocal
int GetMAC(mDNSEthAddr
*eth
, u_short ifindex
)
2920 struct ifaddrs
*ifa
;
2921 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
2922 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2924 const struct sockaddr_dl
*const sdl
= (const struct sockaddr_dl
*)ifa
->ifa_addr
;
2925 if (sdl
->sdl_index
== ifindex
)
2926 { mDNSPlatformMemCopy(eth
->b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6); return 0; }
2932 #ifndef SIOCGIFWAKEFLAGS
2933 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
2936 #ifndef IF_WAKE_ON_MAGIC_PACKET
2937 #define IF_WAKE_ON_MAGIC_PACKET 0x01
2940 #ifndef ifr_wake_flags
2941 #define ifr_wake_flags ifr_ifru.ifru_intval
2944 mDNSlocal mDNSBool
NetWakeInterface(NetworkInterfaceInfoOSX
*i
)
2946 if (!MulticastInterface(i
) ) return(mDNSfalse
); // We only use Sleep Proxy Service on multicast-capable interfaces
2947 if (i
->ifa_flags
& IFF_LOOPBACK
) return(mDNSfalse
); // except loopback
2949 int s
= socket(AF_INET
, SOCK_DGRAM
, 0);
2950 if (s
< 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i
->ifinfo
.ifname
, s
, errno
, strerror(errno
)); return(mDNSfalse
); }
2953 strlcpy(ifr
.ifr_name
, i
->ifinfo
.ifname
, sizeof(ifr
.ifr_name
));
2954 if (ioctl(s
, SIOCGIFWAKEFLAGS
, &ifr
) < 0)
2956 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
2957 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
2958 // error code is being returned from the kernel, we need to use the kernel version.
2959 #define KERNEL_EOPNOTSUPP 102
2960 if (errno
!= KERNEL_EOPNOTSUPP
) // "Operation not supported on socket", the expected result on Leopard and earlier
2961 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i
->ifinfo
.ifname
, errno
, strerror(errno
));
2962 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
2963 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
2964 ifr
.ifr_wake_flags
= (errno
== KERNEL_EOPNOTSUPP
&& !(i
)->BSSID
.l
[0] && i
->m
->SystemWakeOnLANEnabled
) ? IF_WAKE_ON_MAGIC_PACKET
: 0;
2969 // 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
2971 LogSPS("%-6s %#-14a %s WOMP", i
->ifinfo
.ifname
, &i
->ifinfo
.ip
, (ifr
.ifr_wake_flags
& IF_WAKE_ON_MAGIC_PACKET
) ? "supports" : "no");
2973 return((ifr
.ifr_wake_flags
& IF_WAKE_ON_MAGIC_PACKET
) != 0);
2976 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
2977 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
2978 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
2979 // (e.g. sa_family not AF_INET or AF_INET6)
2980 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
, mDNSs32 utc
)
2982 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
2983 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
2986 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
2987 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
2989 NetworkInterfaceInfoOSX
**p
;
2990 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
2991 if (scope_id
== (*p
)->scope_id
&&
2992 mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) &&
2993 mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
2995 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p, ifname before %s, after %s", scope_id
, &bssid
, &ip
, *p
, (*p
)->ifinfo
.ifname
, ifa
->ifa_name
);
2996 // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
2997 // When interfaces are created with same MAC address, kernel resurrects the old interface.
2998 // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
2999 // we get the corresponding name for the interface index on which the packet was received and check against
3000 // the InterfaceList for a matching name. So, keep the name in sync
3001 strlcpy((*p
)->ifinfo
.ifname
, ifa
->ifa_name
, sizeof((*p
)->ifinfo
.ifname
));
3002 (*p
)->Exists
= mDNStrue
;
3003 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
3004 if ((*p
)->LastSeen
!= utc
) (*p
)->AppearanceTime
= utc
;
3006 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
3007 // we may need to start or stop or sleep proxy browse operation
3008 const mDNSBool NetWake
= NetWakeInterface(*p
);
3009 if ((*p
)->ifinfo
.NetWake
!= NetWake
)
3011 (*p
)->ifinfo
.NetWake
= NetWake
;
3012 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
3013 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
3014 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
3015 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
3016 if ((*p
)->Registered
)
3019 if (NetWake
) mDNS_ActivateNetWake_internal (m
, &(*p
)->ifinfo
);
3020 else mDNS_DeactivateNetWake_internal(m
, &(*p
)->ifinfo
);
3028 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
3029 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
3030 if (!i
) return(mDNSNULL
);
3031 mDNSPlatformMemZero(i
, sizeof(NetworkInterfaceInfoOSX
));
3032 i
->ifinfo
.InterfaceID
= (mDNSInterfaceID
)(uintptr_t)scope_id
;
3034 i
->ifinfo
.mask
= mask
;
3035 strlcpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
3036 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
3037 // We can be configured to disable multicast advertisement, but we want to to support
3038 // local-only services, which need a loopback address record.
3039 i
->ifinfo
.Advertise
= m
->DivertMulticastAdvertisements
? ((ifa
->ifa_flags
& IFF_LOOPBACK
) ? mDNStrue
: mDNSfalse
) : m
->AdvertiseLocalAddresses
;
3040 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
3041 i
->ifinfo
.Loopback
= ((ifa
->ifa_flags
& IFF_LOOPBACK
) != 0) ? mDNStrue
: mDNSfalse
;
3045 i
->Exists
= mDNStrue
;
3046 i
->Flashing
= mDNSfalse
;
3047 i
->Occulting
= mDNSfalse
;
3048 i
->AppearanceTime
= utc
; // Brand new interface; AppearanceTime is now
3050 i
->ifa_flags
= ifa
->ifa_flags
;
3051 i
->scope_id
= scope_id
;
3053 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
3057 i
->Registered
= mDNSNULL
;
3059 // Do this AFTER i->BSSID has been set up
3060 i
->ifinfo
.NetWake
= NetWakeInterface(i
);
3061 GetMAC(&i
->ifinfo
.MAC
, scope_id
);
3062 if (i
->ifinfo
.NetWake
&& !i
->ifinfo
.MAC
.l
[0])
3063 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i
->ifinfo
.MAC
, scope_id
, i
->ifinfo
.ifname
, &ip
);
3069 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
3070 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
3072 NetworkInterfaceInfoOSX
*i
;
3073 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
3074 if (i
->Exists
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
3075 if (!mDNSv4AddressIsLinkLocal(&i
->ifinfo
.ip
.ip
.v4
))
3081 #if APPLE_OSX_mDNSResponder
3083 #if COMPILER_LIKES_PRAGMA_MARK
3085 #pragma mark - AutoTunnel
3088 #define kRacoonPort 4500
3090 static DomainAuthInfo
* AnonymousRacoonConfig
= mDNSNULL
;
3092 #ifndef NO_SECURITYFRAMEWORK
3094 static CFMutableDictionaryRef domainStatusDict
= NULL
;
3096 // MUST be called with lock held
3097 mDNSlocal
void RemoveAutoTunnelDomainStatus(const mDNS
*const m
, const DomainAuthInfo
*const info
)
3103 LogInfo("RemoveAutoTunnelDomainStatus: %##s", info
->domain
.c
);
3105 if (!domainStatusDict
) { LogMsg("RemoveAutoTunnelDomainStatus: No domainStatusDict"); return; }
3107 buflen
= mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", info
->domain
.c
);
3108 if (info
->AutoTunnel
== dnsprefix
) buffer
[buflen
-1] = 0; // Strip the trailing dot for Classic
3109 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3110 if (!domain
) { LogMsg("RemoveAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3112 if (CFDictionaryContainsKey(domainStatusDict
, domain
))
3114 CFDictionaryRemoveValue(domainStatusDict
, domain
);
3115 if (!m
->ShutdownTime
) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, mDNSNULL
, domainStatusDict
);
3120 mDNSlocal mStatus
CheckQuestionForStatus(const DNSQuestion
*const q
)
3124 if (q
->servAddr
.type
== mDNSAddrType_IPv4
&& mDNSIPv4AddressIsOnes(q
->servAddr
.ip
.v4
))
3125 return mStatus_NoSuchRecord
;
3126 else if (q
->state
== LLQ_Poll
)
3127 return mStatus_PollingMode
;
3128 else if (q
->state
!= LLQ_Established
&& !q
->DuplicateOf
)
3129 return mStatus_TransientErr
;
3132 return mStatus_NoError
;
3135 mDNSlocal mStatus
UpdateLLQStatus(const mDNS
*const m
, char *buffer
, int bufsz
, const DomainAuthInfo
*const info
)
3137 mStatus status
= mStatus_NoError
;
3138 DNSQuestion
* q
, *worst_q
= mDNSNULL
;
3139 for (q
= m
->Questions
; q
; q
=q
->next
)
3140 if (q
->AuthInfo
== info
)
3142 mStatus newStatus
= CheckQuestionForStatus(q
);
3143 if (newStatus
== mStatus_NoSuchRecord
) { status
= newStatus
; worst_q
= q
; break; }
3144 else if (newStatus
== mStatus_PollingMode
) { status
= newStatus
; worst_q
= q
; }
3145 else if (newStatus
== mStatus_TransientErr
&& status
== mStatus_NoError
) { status
= newStatus
; worst_q
= q
; }
3148 if (status
== mStatus_NoError
) mDNS_snprintf(buffer
, bufsz
, "Success");
3149 else if (status
== mStatus_NoSuchRecord
) mDNS_snprintf(buffer
, bufsz
, "GetZoneData %s: %##s", worst_q
->nta
? "not yet complete" : "failed", worst_q
->qname
.c
);
3150 else if (status
== mStatus_PollingMode
) mDNS_snprintf(buffer
, bufsz
, "Query polling %##s", worst_q
->qname
.c
);
3151 else if (status
== mStatus_TransientErr
) mDNS_snprintf(buffer
, bufsz
, "Query not yet established %##s", worst_q
->qname
.c
);
3155 mDNSlocal mStatus
UpdateRRStatus(const mDNS
*const m
, char *buffer
, int bufsz
, const DomainAuthInfo
*const info
)
3159 if (info
->deltime
) return mStatus_NoError
;
3160 for (r
= m
->ResourceRecords
; r
; r
= r
->next
)
3162 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
3163 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
3164 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
3165 // has already checked
3166 const domainname
*n
= r
->resrec
.name
;
3169 DomainAuthInfo
*ptr
;
3170 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
3171 if (SameDomainName(&ptr
->domain
, n
))
3173 if (ptr
== info
&& (r
->updateError
== mStatus_BadSig
|| r
->updateError
== mStatus_BadKey
))
3175 mDNS_snprintf(buffer
, bufsz
, "Resource record update failed for %##s", r
->resrec
.name
);
3176 return r
->updateError
;
3179 n
= (const domainname
*)(n
->c
+ 1 + n
->c
[0]);
3182 return mStatus_NoError
;
3185 #endif // ndef NO_SECURITYFRAMEWORK
3187 // MUST be called with lock held
3188 mDNSlocal
void UpdateAutoTunnelDomainStatus(const mDNS
*const m
, const DomainAuthInfo
*const info
)
3190 #ifdef NO_SECURITYFRAMEWORK
3194 const NATTraversalInfo
*const llq
= m
->LLQNAT
.clientContext
? &m
->LLQNAT
: mDNSNULL
;
3195 const NATTraversalInfo
*const tun
= info
->AutoTunnelNAT
.clientContext
? &info
->AutoTunnelNAT
: mDNSNULL
;
3198 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3199 CFStringRef domain
= NULL
;
3200 CFStringRef tmp
= NULL
;
3201 CFNumberRef num
= NULL
;
3202 mStatus status
= mStatus_NoError
;
3203 mStatus llqStatus
= mStatus_NoError
;
3204 char llqBuffer
[1024];
3206 if (!m
->mDNS_busy
) LogMsg("UpdateAutoTunnelDomainStatus: ERROR!! Lock not held");
3207 if (!domainStatusDict
)
3209 domainStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3210 if (!domainStatusDict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
3213 if (!dict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
3215 buflen
= mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", info
->domain
.c
);
3216 if (info
->AutoTunnel
== dnsprefix
) buffer
[buflen
-1] = 0; // Strip the trailing dot for Classic
3217 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3218 if (!domain
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3220 mDNS_snprintf(buffer
, sizeof(buffer
), "%#a", &m
->Router
);
3221 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3223 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
3226 CFDictionarySetValue(dict
, CFSTR("RouterAddress"), tmp
);
3230 mDNS_snprintf(buffer
, sizeof(buffer
), "%.4a", &m
->ExternalAddress
);
3231 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3233 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
3236 CFDictionarySetValue(dict
, CFSTR("ExternalAddress"), tmp
);
3242 mDNSu32 port
= mDNSVal16(llq
->ExternalPort
);
3244 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
3246 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
3249 CFDictionarySetValue(dict
, CFSTR("LLQExternalPort"), num
);
3255 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &llq
->Result
);
3257 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
3260 CFDictionarySetValue(dict
, CFSTR("LLQNPMStatus"), num
);
3268 mDNSu32 port
= mDNSVal16(tun
->ExternalPort
);
3270 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
3272 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
3275 CFDictionarySetValue(dict
, CFSTR("AutoTunnelExternalPort"), num
);
3281 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tun
->Result
);
3283 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
3286 CFDictionarySetValue(dict
, CFSTR("AutoTunnelNPMStatus"), num
);
3293 mDNSu32 code
= m
->LastNATMapResultCode
;
3295 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &code
);
3297 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
3300 CFDictionarySetValue(dict
, CFSTR("LastNATMapResultCode"), num
);
3305 mDNS_snprintf(buffer
, sizeof(buffer
), "Success");
3306 llqStatus
= UpdateLLQStatus(m
, llqBuffer
, sizeof(llqBuffer
), info
);
3307 status
= UpdateRRStatus(m
, buffer
, sizeof(buffer
), info
);
3309 // If we have a bad signature error updating a RR, it overrides any error as it needs to be
3310 // reported so that it can be fixed automatically (or the user needs to be notified)
3311 if (status
!= mStatus_NoError
)
3313 LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status
, buffer
);
3315 else if (m
->Router
.type
== mDNSAddrType_None
)
3317 status
= mStatus_NoRouter
;
3318 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - none");
3320 else if (m
->Router
.type
== mDNSAddrType_IPv4
&& mDNSIPv4AddressIsZero(m
->Router
.ip
.v4
))
3322 status
= mStatus_NoRouter
;
3323 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - v4 zero");
3325 else if (mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddrOut
))
3327 status
= info
->AutoTunnel
== btmmprefix
? mStatus_ServiceNotRunning
: mStatus_PollingMode
;
3328 mDNS_snprintf(buffer
, sizeof(buffer
), "No relay connection");
3330 else if (!llq
&& !tun
)
3332 status
= mStatus_NotInitializedErr
;
3333 mDNS_snprintf(buffer
, sizeof(buffer
), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
3335 else if (llqStatus
== mStatus_NoSuchRecord
)
3338 mDNS_snprintf(buffer
, sizeof(buffer
), llqBuffer
);
3340 else if (info
->AutoTunnel
== btmmprefix
&& ((llq
&& llq
->Result
== mStatus_DoubleNAT
) || (tun
&& tun
->Result
== mStatus_DoubleNAT
)))
3342 status
= mStatus_DoubleNAT
;
3343 mDNS_snprintf(buffer
, sizeof(buffer
), "Double NAT: Router is reporting an external address");
3345 else if (info
->AutoTunnel
== btmmprefix
&& ((llq
&& llq
->Result
== mStatus_NATPortMappingDisabled
) || (tun
&& tun
->Result
== mStatus_NATPortMappingDisabled
) ||
3346 (m
->LastNATMapResultCode
== NATErr_Refused
&& ((llq
&& !llq
->Result
&& mDNSIPPortIsZero(llq
->ExternalPort
)) || (tun
&& !tun
->Result
&& mDNSIPPortIsZero(tun
->ExternalPort
))))))
3348 status
= mStatus_NATPortMappingDisabled
;
3349 mDNS_snprintf(buffer
, sizeof(buffer
), "NAT-PMP is disabled on the router");
3351 else if (info
->AutoTunnel
== btmmprefix
&& ((llq
&& llq
->Result
) || (tun
&& tun
->Result
)))
3353 status
= mStatus_NATTraversal
;
3354 mDNS_snprintf(buffer
, sizeof(buffer
), "Error obtaining NAT port mapping from router");
3356 else if (info
->AutoTunnel
== btmmprefix
&& ((llq
&& mDNSIPPortIsZero(llq
->ExternalPort
)) || (tun
&& mDNSIPPortIsZero(tun
->ExternalPort
))))
3358 status
= mStatus_NATTraversal
;
3359 mDNS_snprintf(buffer
, sizeof(buffer
), "Unable to obtain NAT port mapping from router");
3361 else if (info
->AutoTunnel
== btmmprefix
|| llqStatus
!= mStatus_PollingMode
)
3364 mDNS_snprintf(buffer
, sizeof(buffer
), llqBuffer
);
3365 LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status
, buffer
);
3369 mDNS_snprintf(buffer
, sizeof(buffer
), "Polling success");
3372 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
);
3374 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
3377 CFDictionarySetValue(dict
, CFSTR("StatusCode"), num
);
3381 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
3383 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
3386 CFDictionarySetValue(dict
, CFSTR("StatusMessage"), tmp
);
3390 if (!CFDictionaryContainsKey(domainStatusDict
, domain
) ||
3391 !CFEqual(dict
, (CFMutableDictionaryRef
)CFDictionaryGetValue(domainStatusDict
, domain
)))
3393 CFDictionarySetValue(domainStatusDict
, domain
, dict
);
3394 if (!m
->ShutdownTime
)
3396 static char statusBuf
[16];
3397 mDNS_snprintf(statusBuf
, sizeof(statusBuf
), "%d", (int)status
);
3398 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.domainstatus", status
? "failure" : "success", statusBuf
, "");
3399 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, mDNSNULL
, domainStatusDict
);
3406 debugf("UpdateAutoTunnelDomainStatus: %s", buffer
);
3407 #endif // def NO_SECURITYFRAMEWORK
3410 // MUST be called with lock held
3411 mDNSexport
void UpdateAutoTunnelDomainStatuses(const mDNS
*const m
)
3413 #ifdef NO_SECURITYFRAMEWORK
3416 if (!m
->mDNS_busy
) LogMsg("UpdateAutoTunnelDomainStatuses: ERROR!! Lock not held");
3417 DomainAuthInfo
* info
;
3418 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
3419 if (info
->AutoTunnel
&& !info
->deltime
)
3420 UpdateAutoTunnelDomainStatus(m
, info
);
3421 #endif // def NO_SECURITYFRAMEWORK
3424 // MUST be called with lock held
3425 mDNSlocal mDNSBool
TunnelServers(mDNS
*const m
)
3428 for (r
= m
->ResourceRecords
; r
; r
= r
->next
)
3429 if (r
->resrec
.rrtype
== kDNSType_SRV
)
3431 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, r
->resrec
.name
);
3432 if (AuthInfo
&& AuthInfo
->AutoTunnel
&& !AuthInfo
->deltime
) return(mDNStrue
);
3438 // MUST be called with lock held
3439 mDNSlocal mDNSBool
TunnelClients(mDNS
*const m
)
3442 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
3443 if (p
->q
.ThisQInterval
< 0)
3448 mDNSlocal
void UpdateAnonymousRacoonConfig(mDNS
*m
) // Determine whether we need racoon to accept incoming connections
3450 DomainAuthInfo
*info
;
3452 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
3453 if (info
->AutoTunnel
&& !info
->deltime
&& (!mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) || !mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddrIn
)))
3456 if (info
!= AnonymousRacoonConfig
)
3458 AnonymousRacoonConfig
= info
;
3459 // Create or revert configuration file, and start (or SIGHUP) Racoon
3460 (void)mDNSConfigureServer(AnonymousRacoonConfig
? kmDNSUp
: kmDNSDown
, AnonymousRacoonConfig
? AnonymousRacoonConfig
->AutoTunnel
: mDNSNULL
, AnonymousRacoonConfig
? &AnonymousRacoonConfig
->domain
: mDNSNULL
);
3464 // Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
3465 // sometimes the caller may already be holding the lock e.g., RegisterAutoTunnel6Record and sometimes
3466 // not e.g., RegisterAutoTunnelServiceRecord
3467 mDNSlocal
void RegisterAutoTunnelHostRecord(mDNS
*m
, DomainAuthInfo
*info
)
3470 mDNSBool NATProblem
;
3472 if (!m
->mDNS_busy
) LogMsg("RegisterAutoTunnelHostRecord: ERROR!! Lock not held");
3474 // We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
3475 // called at least once with some Services/Records in the domain and hence it is safe to register
3476 // records when this function is called.
3477 if (!info
->AutoTunnelNAT
.clientContext
) { LogInfo("RegisterAutoTunnelHostRecord: No services registered, not registering the record\n"); return; }
3479 // Are we behind a NAT with no NAT-PMP support or behind a Double NAT ? Double NATs may have
3480 // NAT-PMP support but it still does not provide inbound connectivity. If there is no NAT-PMP
3481 // support, ExternalPort is zero. If we are behind a Double NAT, then the NATResult is non-zero.
3483 NATProblem
= mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) || info
->AutoTunnelNAT
.Result
;
3485 if (mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddrIn
))
3487 // If we don't have a relay address, check to see if we are behind a Double NAT or NAT with no NAT-PMP
3491 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
);
3497 // Relay address may be non-zero but we might be going to sleep as the utun interface is not removed
3498 // when going to sleep. If we are awake, we don't care about the NATProblem as the relay connnection
3499 // is up. If we are going to sleep, we should not register the host record if we have a NAT problem.
3500 if (m
->SleepState
!= SleepState_Awake
&& NATProblem
)
3502 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
);
3509 // We use zero Requested port to infer that we should not be calling Register anymore as it might
3510 // be shutdown or the DomainAuthInfo is going away.
3512 // We can use a different set of state variables to track the above as the records registered in
3513 // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
3514 // reuse the NAT variables.
3516 // Set up our address record for the internal tunnel address
3517 // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
3518 if (!mDNSIPPortIsZero(info
->AutoTunnelNAT
.RequestedPort
) && info
->AutoTunnelHostRecord
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3520 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
3521 AppendDomainLabel(&info
->AutoTunnelHostRecord
.namestorage
, &m
->hostlabel
);
3522 AppendDomainName (&info
->AutoTunnelHostRecord
.namestorage
, &info
->domain
);
3523 info
->AutoTunnelHostRecord
.resrec
.rdata
->u
.ipv6
= m
->AutoTunnelHostAddr
;
3524 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
3526 err
= mDNS_Register_internal(m
, &info
->AutoTunnelHostRecord
);
3528 if (err
) LogMsg("RegisterAutoTunnelHostRecord error %d registering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
3531 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
3532 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
3533 LogInfo("RegisterAutoTunnelHostRecord registering AutoTunnelHostRecord %##s", info
->AutoTunnelHostRecord
.namestorage
.c
);
3536 else LogInfo("RegisterAutoTunnelHostRecord: Not registering Context %p Port %d Type %d", info
->AutoTunnelNAT
.clientContext
, mDNSVal16(info
->AutoTunnelNAT
.RequestedPort
), info
->AutoTunnelHostRecord
.resrec
.RecordType
);
3539 mDNSlocal
void DeregisterAutoTunnelHostRecord(mDNS
*m
, DomainAuthInfo
*info
)
3541 LogInfo("DeregisterAutoTunnelHostRecord %##s", info
->domain
.c
);
3543 // Don't deregister if we have the AutoTunnel6 or AutoTunnelService records are registered.
3544 // They indicate that BTMM is working
3545 if (info
->AutoTunnel6Record
.resrec
.RecordType
> kDNSRecordTypeDeregistering
||
3546 info
->AutoTunnelService
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
3548 LogInfo("DeregisterAutoTunnelHostRecord %##s, not deregistering the Host Record AutoTunnel6 RecordType:%d AutoTunnel RecordType: %d", info
->domain
.c
,
3549 info
->AutoTunnel6Record
.resrec
.RecordType
, info
->AutoTunnelService
.resrec
.RecordType
);
3553 if (info
->AutoTunnelHostRecord
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
3555 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelHostRecord
);
3558 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
3559 LogMsg("DeregisterAutoTunnelHostRecord error %d deregistering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
3561 else LogInfo("DeregisterAutoTunnelHostRecord: Deregistered AutoTunnel Host Record");
3563 else LogInfo("DeregisterAutoTunnelHostRecord: Not deregistering Host Record state:%d", info
->AutoTunnelHostRecord
.resrec
.RecordType
);
3566 mDNSlocal
void RegisterAutoTunnelServiceRecords(mDNS
*m
, DomainAuthInfo
*info
)
3570 //if (m->mDNS_busy) LogMsg("RegisterAutoTunnelServiceRecords: ERROR!! Lock already held");
3572 if (info
->AutoTunnelNAT
.clientContext
&& !info
->AutoTunnelNAT
.Result
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) && info
->AutoTunnelTarget
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3574 LogInfo("RegisterAutoTunnelServiceRecords %##s (%#s)", info
->domain
.c
, m
->hostlabel
.c
);
3576 // 1. Set up our address record for the external tunnel address
3577 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
3578 info
->AutoTunnelTarget
.namestorage
.c
[0] = 0;
3579 AppendDomainLabel(&info
->AutoTunnelTarget
.namestorage
, &m
->AutoTunnelLabel
);
3580 AppendDomainName (&info
->AutoTunnelTarget
.namestorage
, &info
->domain
);
3581 info
->AutoTunnelTarget
.resrec
.rdata
->u
.ipv4
= info
->AutoTunnelNAT
.ExternalAddress
;
3582 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
3584 err
= mDNS_Register(m
, &info
->AutoTunnelTarget
);
3585 if (err
) LogMsg("RegisterAutoTunnelServiceRecords error %d registering AutoTunnelTarget %##s", err
, info
->AutoTunnelTarget
.namestorage
.c
);
3586 else LogInfo("RegisterAutoTunnelServiceRecords registering AutoTunnelTarget %##s", info
->AutoTunnelTarget
.namestorage
.c
);
3590 if (info
->AutoTunnelNAT
.clientContext
&& !info
->AutoTunnelNAT
.Result
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) && info
->AutoTunnelService
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3592 // 2. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
3593 AssignDomainName (&info
->AutoTunnelService
.namestorage
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
3594 AppendDomainLabel(&info
->AutoTunnelService
.namestorage
, &m
->hostlabel
);
3595 AppendDomainName (&info
->AutoTunnelService
.namestorage
, &info
->domain
);
3596 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.priority
= 0;
3597 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.weight
= 0;
3598 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.port
= info
->AutoTunnelNAT
.ExternalPort
;
3599 AssignDomainName(&info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.target
, &info
->AutoTunnelTarget
.namestorage
);
3600 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
3601 err
= mDNS_Register(m
, &info
->AutoTunnelService
);
3602 if (err
) LogMsg("RegisterAutoTunnelServiceRecords error %d registering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
3603 else LogInfo("RegisterAutoTunnelServiceRecords registering AutoTunnelService %##s", info
->AutoTunnelService
.namestorage
.c
);
3605 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
3606 info
->AutoTunnelTarget
.namestorage
.c
, &m
->AdvertisedV4
.ip
.v4
, mDNSVal16(info
->AutoTunnelNAT
.IntPort
),
3607 info
->AutoTunnelHostRecord
.namestorage
.c
, &m
->AutoTunnelHostAddr
);
3610 RegisterAutoTunnelHostRecord(m
, info
);
3614 mDNSlocal
void DeregisterAutoTunnelServiceRecords(mDNS
*m
, DomainAuthInfo
*info
)
3616 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info
->domain
.c
);
3617 if (info
->AutoTunnelTarget
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
3619 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelTarget
);
3622 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
3623 LogMsg("DeregisterAutoTunnelServiceRecords error %d deregistering AutoTunnelTarget %##s", err
, info
->AutoTunnelTarget
.namestorage
.c
);
3625 else LogInfo("DeregisterAutoTunnelServiceRecords: Deregistered AutoTunnel Target Record");
3628 else LogInfo("DeregisterAutoTunnelServiceRecords: Not deregistering Target record state:%d", info
->AutoTunnelService
.resrec
.RecordType
);
3630 if (info
->AutoTunnelService
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
3632 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelService
);
3635 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
3636 LogMsg("DeregisterAutoTunnelServiceRecords error %d deregistering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
3638 else LogInfo("DeregisterAutoTunnelServiceRecords: Deregistered AutoTunnel Service Record");
3641 else LogInfo("DeregisterAutoTunnelServiceRecords: Not deregistering service records state:%d", info
->AutoTunnelService
.resrec
.RecordType
);
3643 DeregisterAutoTunnelHostRecord(m
, info
);
3646 // Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
3647 // sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
3648 // not e.g., AutoTunnelHostNameChanged
3649 mDNSlocal
void RegisterAutoTunnelDevInfoRecord(mDNS
*m
, DomainAuthInfo
*info
)
3653 if (!m
->mDNS_busy
) LogMsg("RegisterAutoTunnelDevInfoRecord: Lock not held");
3655 // a. We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
3656 // called at least once with some Services/Records in the domain and hence it is safe to register
3657 // records when this function is called.
3659 // b. We use zero Requested port to infer that we should not be calling Register anymore as it might
3660 // be shutdown or the DomainAuthInfo is going away.
3662 // We can use a different set of state variables to track the above as the records registered in
3663 // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
3664 // reuse the NAT variables.
3666 // Set up device info record
3667 if (info
->AutoTunnelNAT
.clientContext
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.RequestedPort
) && info
->AutoTunnelDeviceInfo
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3669 ConstructServiceName(&info
->AutoTunnelDeviceInfo
.namestorage
, &m
->nicelabel
, &DeviceInfoName
, &info
->domain
);
3670 mDNSu8 len
= m
->HIHardware
.c
[0] < 255 - 6 ? m
->HIHardware
.c
[0] : 255 - 6;
3671 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 1, "model=", 6);
3672 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 7, m
->HIHardware
.c
+ 1, len
);
3673 info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
[0] = 6 + len
; // "model=" plus the device string
3674 info
->AutoTunnelDeviceInfo
.resrec
.rdlength
= 7 + len
; // One extra for the length byte at the start of the string
3675 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
3677 err
= mDNS_Register_internal(m
, &info
->AutoTunnelDeviceInfo
);
3678 if (err
) LogMsg("RegisterAutoTunnelDevInfoRecord error %d registering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
3679 else LogInfo("RegisterAutoTunnelDevInfoRecord registering AutoTunnelDeviceInfo %##s", info
->AutoTunnelDeviceInfo
.namestorage
.c
);
3683 #ifndef NO_SECURITYFRAMEWORK
3684 mDNSlocal
void DeregisterAutoTunnelDevInfoRecord(mDNS
*m
, DomainAuthInfo
*info
)
3686 LogInfo("DeregisterAutoTunnelDevInfoRecord %##s", info
->domain
.c
);
3688 if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
3690 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelDeviceInfo
);
3693 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
3694 LogMsg("DeregisterAutoTunnelDevInfoRecord error %d deregistering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
3696 else LogInfo("DeregisterAutoTunnelDevInfoRecord: Deregistered AutoTunnel Device Info");
3698 else LogInfo("DeregisterAutoTunnelDevInfoRecord: Not deregistering DeviceInfo Record state:%d", info
->AutoTunnelDeviceInfo
.resrec
.RecordType
);
3703 // Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
3704 // sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
3705 // not e.g., AutoTunnelHostNameChanged
3706 mDNSlocal
void RegisterAutoTunnel6Record(mDNS
*m
, DomainAuthInfo
*info
)
3710 if (!m
->mDNS_busy
) LogMsg("RegisterAutoTunnel6Record: ERROR!! Lock not held");
3712 // We deregister the AutoTunnel6Record during sleep and come back here (AutoTunnelRecordCallback) to
3713 // register the address if needed. During that time, we might get a network change event which finds
3714 // that the utun interface exists and tries to register the AutoTunnel6Record which should be stopped.
3715 // Also the RelayAddress is reinitialized during that process which in turn causes the AutoTunnelRecordCallback
3716 // to re-register again. To stop these, we check for the SleepState and register only if we are awake.
3717 if (m
->SleepState
!= SleepState_Awake
)
3719 LogInfo("RegisterAutoTunnel6Record: Not in awake state, SleepState %d", m
->SleepState
);
3723 // if disabled administratively, don't register
3724 if (!m
->RegisterAutoTunnel6
|| DisableInboundRelayConnection
)
3726 LogInfo("RegisterAutoTunnel6Record: registration Disabled RegisterAutoTunnel6 %d, DisableInbound %d",
3727 m
->RegisterAutoTunnel6
, DisableInboundRelayConnection
);
3731 // If we have a valid Relay address, we need to register it now. When we got a valid address, we may not
3732 // have registered it because it was waiting for at least one service to become active in the BTMM domain.
3733 // During network change event, we might be called multiple times while the "Connectivity" key did not
3734 // change, so check to see if the value has changed. This can also be zero when we are deregistering and
3735 // getting called from the AutoTunnelRecordCallback
3737 if (mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddrIn
))
3739 LogInfo("RegisterAutoTunnel6Record: Relay address is zero, not registering");
3743 if ((info
->AutoTunnel6Record
.resrec
.RecordType
> kDNSRecordTypeDeregistering
) &&
3744 (mDNSSameIPv6Address(info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
, m
->AutoTunnelRelayAddrIn
)))
3746 LogInfo("RegisterAutoTunnel6Record: Relay address %.16a same, not registering", &m
->AutoTunnelRelayAddrIn
);
3751 // a. We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
3752 // called at least once with some Services/Records in the domain and hence it is safe to register
3753 // records when this function is called.
3755 // b. We use zero Requested port to infer that we should not be calling Register anymore as it might
3756 // be shutdown or the DomainAuthInfo is going away.
3758 // We can use a different set of state variables to track the above as the records registered in
3759 // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
3760 // reuse the NAT variables.
3762 if (info
->AutoTunnelNAT
.clientContext
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.RequestedPort
) &&
3763 info
->AutoTunnel6Record
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3765 AssignDomainName (&info
->AutoTunnel6Record
.namestorage
, (const domainname
*) "\x0C" "_autotunnel6");
3766 AppendDomainLabel(&info
->AutoTunnel6Record
.namestorage
, &m
->hostlabel
);
3767 AppendDomainName (&info
->AutoTunnel6Record
.namestorage
, &info
->domain
);
3768 info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
= m
->AutoTunnelRelayAddrIn
;
3769 info
->AutoTunnel6Record
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
3771 err
= mDNS_Register_internal(m
, &info
->AutoTunnel6Record
);
3772 if (err
) LogMsg("RegisterAutoTunnel6Record error %d registering AutoTunnel6 Record %##s", err
, info
->AutoTunnel6Record
.namestorage
.c
);
3773 else LogInfo("RegisterAutoTunnel6Record registering AutoTunnel6 Record %##s", info
->AutoTunnel6Record
.namestorage
.c
);
3775 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
3776 info
->AutoTunnel6Record
.namestorage
.c
, &m
->AutoTunnelRelayAddrIn
,
3777 info
->AutoTunnelHostRecord
.namestorage
.c
, &m
->AutoTunnelHostAddr
);
3779 } 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
);}
3781 RegisterAutoTunnelHostRecord(m
, info
);
3782 // When the AutoTunnel6 record comes up, we need to kick racoon and update the status.
3783 // If we had a port mapping, we would have done it in RegisterAutoTunnelServiceRecords.
3784 // If we don't have a port mapping, we need to do it here.
3785 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
3786 UpdateAutoTunnelDomainStatus(m
, info
);
3789 mDNSlocal
void DeregisterAutoTunnel6Record(mDNS
*m
, DomainAuthInfo
*info
)
3791 LogInfo("DeregisterAutoTunnel6Record %##s", info
->domain
.c
);
3793 if (info
->AutoTunnel6Record
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
3795 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnel6Record
);
3798 info
->AutoTunnel6Record
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
3799 info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
= zerov6Addr
;
3800 LogMsg("DeregisterAutoTunnel6Record error %d deregistering AutoTunnel6Record %##s", err
, info
->AutoTunnel6Record
.namestorage
.c
);
3802 else LogInfo("DeregisterAutoTunnel6Record: Deregistered AutoTunnel6 Record");
3804 else LogInfo("DeregisterAutoTunnel6Record: Not deregistering AuoTunnel6 record state:%d", info
->AutoTunnel6Record
.resrec
.RecordType
);
3806 DeregisterAutoTunnelHostRecord(m
, info
);
3807 // UpdateAutoTunnelDomainStatus is careful enough not to turn it on if we don't have
3808 // a external port mapping. Otherwise, it will be turned off.
3810 UpdateAutoTunnelDomainStatus(m
, info
);
3814 mDNSlocal
void AutoTunnelRecordCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
3816 DomainAuthInfo
*info
= (DomainAuthInfo
*)rr
->RecordContext
;
3817 if (result
== mStatus_MemFree
)
3819 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m
, rr
));
3820 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
3821 if (rr
== &info
->AutoTunnelHostRecord
)
3823 rr
->namestorage
.c
[0] = 0;
3824 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
3825 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m
->NextSRVUpdate
- m
->timenow
, m
->timenow
);
3827 if (m
->ShutdownTime
) {LogInfo("AutoTunnelRecordCallback: Shutdown, returning");return;}
3828 if (rr
== &info
->AutoTunnelHostRecord
)
3830 LogInfo("AutoTunnelRecordCallback: calling RegisterAutoTunnelHostRecord");
3831 RegisterAutoTunnelHostRecord(m
,info
);
3833 else if (rr
== &info
->AutoTunnelDeviceInfo
)
3835 LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnelDevInfoRecord");
3836 RegisterAutoTunnelDevInfoRecord(m
,info
);
3838 else if (rr
== &info
->AutoTunnelService
|| rr
== &info
->AutoTunnelTarget
)
3840 LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnelServiceRecords");
3841 RegisterAutoTunnelServiceRecords(m
,info
);
3843 else if (rr
== &info
->AutoTunnel6Record
)
3845 LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnel6Record");
3846 info
->AutoTunnel6Record
.resrec
.rdata
->u
.ipv6
= zerov6Addr
;
3847 RegisterAutoTunnel6Record(m
,info
);
3852 #ifndef NO_SECURITYFRAMEWORK
3853 mDNSlocal
void AutoTunnelDeleteAuthInfoState(mDNS
*m
, DomainAuthInfo
*info
)
3855 LogInfo("AutoTunnelDeleteAuthInfoState: Cleaning up state releated to Domain AuthInfo %##s", info
->domain
.c
);
3857 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
3858 DeregisterAutoTunnelDevInfoRecord(m
, info
);
3859 DeregisterAutoTunnelServiceRecords(m
, info
);
3860 DeregisterAutoTunnel6Record(m
, info
);
3861 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
3862 UpdateAutoTunnelDomainStatus(m
, info
);
3864 #endif // ndef NO_SECURITYFRAMEWORK
3866 mDNSlocal
void AutoTunnelNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
3868 DomainAuthInfo
*info
= (DomainAuthInfo
*)n
->clientContext
;
3869 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s",
3870 n
->Result
, &n
->ExternalAddress
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->ExternalPort
), m
->hostlabel
.c
, info
->domain
.c
);
3872 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
3873 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m
->NextSRVUpdate
- m
->timenow
, m
->timenow
);
3875 DeregisterAutoTunnelServiceRecords(m
, info
);
3876 RegisterAutoTunnelServiceRecords(m
, info
);
3878 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
3880 UpdateAutoTunnelDomainStatus(m
, (DomainAuthInfo
*)n
->clientContext
);
3883 mDNSlocal
void AbortDeregistration(mDNS
*const m
, AuthRecord
*rr
)
3885 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
3887 LogInfo("Aborting deregistration of %s", ARDisplayString(m
, rr
));
3888 CompleteDeregistration(m
, rr
);
3890 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnregistered
)
3891 LogMsg("AbortDeregistration ERROR RecordType %02X for %s", ARDisplayString(m
, rr
));
3894 mDNSlocal
void AutoTunnelHostNameChanged(mDNS
*m
, DomainAuthInfo
*info
)
3896 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m
->hostlabel
.c
, info
->domain
.c
);
3898 #ifndef NO_SECURITYFRAMEWORK
3899 DeregisterAutoTunnelDevInfoRecord(m
, info
);
3901 DeregisterAutoTunnelServiceRecords(m
, info
);
3902 DeregisterAutoTunnel6Record(m
, info
);
3903 RegisterAutoTunnelServiceRecords(m
, info
);
3906 RegisterAutoTunnelDevInfoRecord(m
, info
);
3907 RegisterAutoTunnel6Record(m
, info
);
3908 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
3912 mDNSlocal
void SetupLocalAutoTunnel6Records(mDNS
*const m
, DomainAuthInfo
*info
)
3914 AbortDeregistration(m
, &info
->AutoTunnelDeviceInfo
);
3915 AbortDeregistration(m
, &info
->AutoTunnel6Record
);
3917 // When the BTMM is turned on/off too quickly, following things happen.
3919 // 1. Turning off BTMM triggers deregistration of the DevInfo/AutoTunnel6 etc. records
3920 // 2. While (1) is in progress, the BTMM is turned on
3922 // At step (2), mDNS_SetSecretForDomain clears info->deltime indicating that the domain is valid
3923 // while we have not processed the turning off BTMM completely. Hence, we end up calling this
3924 // function to re-register the records. AbortDeregistration above aborts the Deregistration as the
3925 // records are still in Deregistering state and in AutoTunnelRecordCallback we end up registering
3926 // again. So, we have to be careful below to not call mDNS_SetupResourceRecord again which will
3927 // reset the state to Unregistered and registering again will lead to error as it is registered
3928 // and already in the list. Hence, register below only if needed.
3930 if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
||
3931 info
->AutoTunnel6Record
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
)
3933 LogInfo("SetupLocalAutoTunnel6Records: AutoTunnel Records not in Unregistered state: Device: %d, AutoTunnel6:%d",
3934 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
, info
->AutoTunnel6Record
.resrec
.RecordType
);
3937 if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3939 mDNS_SetupResourceRecord(&info
->AutoTunnelDeviceInfo
, mDNSNULL
, mDNSInterface_Any
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
3940 RegisterAutoTunnelDevInfoRecord(m
, info
);
3942 if (info
->AutoTunnel6Record
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
3944 mDNS_SetupResourceRecord(&info
->AutoTunnel6Record
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
3945 RegisterAutoTunnel6Record(m
, info
);
3948 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
3950 UpdateAutoTunnelDomainStatus(m
, info
);
3951 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
3954 // Before SetupLocalAutoTunnelInterface_internal is called,
3955 // m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
3956 // Must be called with the lock held
3957 mDNSexport
void SetupLocalAutoTunnelInterface_internal(mDNS
*const m
, mDNSBool servicesStarting
)
3959 // 1. Configure the local IPv6 ULA BTMM address
3960 if (!m
->AutoTunnelHostAddrActive
)
3962 m
->AutoTunnelHostAddrActive
= mDNStrue
;
3963 LogInfo("SetupLocalAutoTunnelInterface_internal: Setting up AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
3964 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp
, m
->AutoTunnelHostAddr
.b
);
3967 // 2. If we have at least one server (pending) listening, publish our records
3968 // The services may not be in the list when it is first trying to resolve the target of the SRV record.
3969 // servicesStarting is an indication of that. Use that instead of looking up in the list of Services/Records.
3970 if (servicesStarting
|| TunnelServers(m
))
3972 DomainAuthInfo
*info
;
3973 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
3975 if (info
->AutoTunnel
&& !info
->deltime
&& !info
->AutoTunnelNAT
.clientContext
)
3977 // If we just resurrected a DomainAuthInfo that is still deregistering, we need to abort the
3978 // deregistration process before re-using the AuthRecord memory
3980 // Note: We don't need the same caution as in SetupLocalAutoTunnel6Records (see the comments there)
3981 // as AutoTunnelRecordCallback (called as a result of AbortDeregistration) will not end up registering
3982 // the records because clientContext is still NULL
3984 AbortDeregistration(m
, &info
->AutoTunnelTarget
);
3985 AbortDeregistration(m
, &info
->AutoTunnelService
);
3986 AbortDeregistration(m
, &info
->AutoTunnelHostRecord
);
3988 mDNS_SetupResourceRecord(&info
->AutoTunnelTarget
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, kHostNameTTL
,
3989 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
3990 mDNS_SetupResourceRecord(&info
->AutoTunnelService
, mDNSNULL
, mDNSInterface_Any
, kDNSType_SRV
, kHostNameTTL
,
3991 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
3992 mDNS_SetupResourceRecord(&info
->AutoTunnelHostRecord
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
,
3993 kDNSRecordTypeUnregistered
, AuthRecordAny
, AutoTunnelRecordCallback
, info
);
3995 // Try to get a NAT port mapping for the AutoTunnelService
3996 info
->AutoTunnelNAT
.clientCallback
= AutoTunnelNATCallback
;
3997 info
->AutoTunnelNAT
.clientContext
= info
;
3998 info
->AutoTunnelNAT
.Protocol
= NATOp_MapUDP
;
3999 info
->AutoTunnelNAT
.IntPort
= IPSECPort
;
4000 info
->AutoTunnelNAT
.RequestedPort
= IPSECPort
;
4001 info
->AutoTunnelNAT
.NATLease
= 0;
4002 mStatus err
= mDNS_StartNATOperation_internal(m
, &info
->AutoTunnelNAT
);
4003 if (err
) LogMsg("SetupLocalAutoTunnelInterface_internal: error %d starting NAT mapping", err
);
4005 // Register the records that can be done without communicating with the NAT
4007 // Note: This should be done after we setup the AutoTunnelNAT information
4008 // as some of the fields in that structure are used to infer other information
4009 // e.g., is it okay to register now ?
4011 SetupLocalAutoTunnel6Records(m
, info
);
4018 mDNSlocal mStatus
AutoTunnelSetKeys(ClientTunnel
*tun
, mDNSBool AddNew
)
4020 mDNSv6Addr loc_outer6
;
4021 mDNSv6Addr rmt_outer6
;
4023 // When we are tunneling over IPv6 Relay address, the port number is zero
4024 if (mDNSIPPortIsZero(tun
->rmt_outer_port
))
4026 loc_outer6
= tun
->loc_outer6
;
4027 rmt_outer6
= tun
->rmt_outer6
;
4031 loc_outer6
= zerov6Addr
;
4032 loc_outer6
.b
[0] = tun
->loc_outer
.b
[0];
4033 loc_outer6
.b
[1] = tun
->loc_outer
.b
[1];
4034 loc_outer6
.b
[2] = tun
->loc_outer
.b
[2];
4035 loc_outer6
.b
[3] = tun
->loc_outer
.b
[3];
4037 rmt_outer6
= zerov6Addr
;
4038 rmt_outer6
.b
[0] = tun
->rmt_outer
.b
[0];
4039 rmt_outer6
.b
[1] = tun
->rmt_outer
.b
[1];
4040 rmt_outer6
.b
[2] = tun
->rmt_outer
.b
[2];
4041 rmt_outer6
.b
[3] = tun
->rmt_outer
.b
[3];
4044 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
), tun
->prefix
, SkipLeadingLabels(&tun
->dstname
, 1)));
4047 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
4048 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
4050 mDNSlocal
void ReissueBlockedQuestionWithType(mDNS
*const m
, domainname
*d
, mDNSBool success
, mDNSu16 qtype
)
4052 DNSQuestion
*q
= m
->Questions
;
4055 if (q
->NoAnswer
== NoAnswer_Suspended
&& q
->qtype
== qtype
&& q
->AuthInfo
&& q
->AuthInfo
->AutoTunnel
&& SameDomainName(&q
->qname
, d
))
4057 LogInfo("Restart %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4058 mDNSQuestionCallback
*tmp
= q
->QuestionCallback
;
4059 q
->QuestionCallback
= AutoTunnelCallback
; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
4060 mDNS_StopQuery(m
, q
);
4061 mDNS_StartQuery(m
, q
);
4062 q
->QuestionCallback
= tmp
; // Restore QuestionCallback back to the real value
4063 if (!success
) q
->NoAnswer
= NoAnswer_Fail
;
4064 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
4065 // In general we have to assume that the question list might have changed in arbitrary ways.
4066 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
4067 // already in use. The safest solution is just to go back to the start of the list and start again.
4068 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
4069 // just one suspended question, so it's really a 2n algorithm.
4077 mDNSlocal
void ReissueBlockedQuestions(mDNS
*const m
, domainname
*d
, mDNSBool success
)
4079 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
4080 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
4081 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
4082 // 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.
4083 // 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.
4084 ReissueBlockedQuestionWithType(m
, d
, success
, kDNSType_AAAA
);
4085 ReissueBlockedQuestionWithType(m
, d
, mDNStrue
, kDNSType_A
);
4088 mDNSlocal
void UnlinkAndReissueBlockedQuestions(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool success
)
4090 ClientTunnel
**p
= &m
->TunnelClients
;
4091 while (*p
!= tun
&& *p
) p
= &(*p
)->next
;
4092 if (*p
) *p
= tun
->next
;
4093 ReissueBlockedQuestions(m
, &tun
->dstname
, success
);
4094 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun
);
4095 freeL("ClientTunnel", tun
);
4098 mDNSlocal mDNSBool
TunnelClientDeleteMatching(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool v6Tunnel
)
4101 mDNSBool needSetKeys
= mDNStrue
;
4106 // Is this a tunnel to the same host that we are trying to setup now?
4107 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
4110 ClientTunnel
*old
= *p
;
4113 if (!mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue; }
4114 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4115 if (old
->q
.ThisQInterval
>= 0)
4117 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4118 mDNS_StopQuery(m
, &old
->q
);
4120 else if (!mDNSSameIPv6Address((*p
)->rmt_inner
, tun
->rmt_inner
) ||
4121 !mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
4122 !mDNSSameIPv6Address(old
->loc_outer6
, tun
->loc_outer6
) ||
4123 !mDNSSameIPv6Address(old
->rmt_outer6
, tun
->rmt_outer6
))
4125 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4126 // the other parameters of the tunnel are different
4127 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4128 AutoTunnelSetKeys(old
, mDNSfalse
);
4132 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4133 // as "tun" and "old" are identical
4134 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
,
4136 needSetKeys
= mDNSfalse
;
4141 if (mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue; }
4142 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4143 if (old
->q
.ThisQInterval
>= 0)
4145 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4146 mDNS_StopQuery(m
, &old
->q
);
4148 else if (!mDNSSameIPv6Address((*p
)->rmt_inner
, tun
->rmt_inner
) ||
4149 !mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
4150 !mDNSSameIPv4Address(old
->loc_outer
, tun
->loc_outer
) ||
4151 !mDNSSameIPv4Address(old
->rmt_outer
, tun
->rmt_outer
) ||
4152 !mDNSSameIPPort(old
->rmt_outer_port
, tun
->rmt_outer_port
))
4154 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4155 // the other parameters of the tunnel are different
4156 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4157 AutoTunnelSetKeys(old
, mDNSfalse
);
4161 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4162 // as "tun" and "old" are identical
4163 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
,
4165 needSetKeys
= mDNSfalse
;
4170 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old
);
4171 freeL("ClientTunnel", old
);
4177 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
4178 // tunnel will be deleted
4179 mDNSlocal
void TunnelClientDeleteAny(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool v6Tunnel
)
4186 // If there is more than one client tunnel to the same host, delete all of them.
4187 // We do this by just checking against the EUI64 rather than the full address
4188 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
4191 ClientTunnel
*old
= *p
;
4194 if (!mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue;}
4195 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4199 if (mDNSIPPortIsZero(old
->rmt_outer_port
)) { p
= &old
->next
; continue;}
4200 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4202 if (old
->q
.ThisQInterval
>= 0)
4204 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4205 mDNS_StopQuery(m
, &old
->q
);
4209 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old
->dstname
.c
, &old
->rmt_inner
);
4210 AutoTunnelSetKeys(old
, mDNSfalse
);
4213 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old
);
4214 freeL("ClientTunnel", old
);
4219 mDNSlocal
void TunnelClientFinish(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
)
4221 mDNSBool needSetKeys
= mDNStrue
;
4222 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
4223 mDNSBool v6Tunnel
= mDNSfalse
;
4225 // If the port is zero, then we have a relay address of the peer
4226 if (mDNSIPPortIsZero(tun
->rmt_outer_port
))
4227 v6Tunnel
= mDNStrue
;
4231 LogInfo("TunnelClientFinish: Relay address %.16a", &answer
->rdata
->u
.ipv6
);
4232 tun
->rmt_outer6
= answer
->rdata
->u
.ipv6
;
4233 tun
->loc_outer6
= m
->AutoTunnelRelayAddrOut
;
4237 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer
->rdata
->u
.ipv4
);
4238 tun
->rmt_outer
= answer
->rdata
->u
.ipv4
;
4239 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
4240 tmpDst
.ip
.v4
= tun
->rmt_outer
;
4241 mDNSAddr tmpSrc
= zeroAddr
;
4242 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
4243 if (tmpSrc
.type
== mDNSAddrType_IPv4
) tun
->loc_outer
= tmpSrc
.ip
.v4
;
4244 else tun
->loc_outer
= m
->AdvertisedV4
.ip
.v4
;
4247 question
->ThisQInterval
= -1; // So we know this tunnel setup has completed
4248 tun
->loc_inner
= m
->AutoTunnelHostAddr
;
4250 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
4251 // look for existing tunnels to see whether they have the same information for our peer.
4252 // If not, delete them and need to create a new tunnel. If they are same, just use the
4253 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
4254 TunnelClientDeleteAny(m
, tun
, !v6Tunnel
);
4255 needSetKeys
= TunnelClientDeleteMatching(m
, tun
, v6Tunnel
);
4257 if (needSetKeys
) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel
? "IPv6" : "IPv4"), tun
->dstname
.c
, &tun
->rmt_inner
);
4258 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel
? "IPv6" : "IPv4"), tun
->dstname
.c
, &tun
->rmt_inner
);
4260 if (m
->AutoTunnelHostAddr
.b
[0]) { mDNS_Lock(m
); SetupLocalAutoTunnelInterface_internal(m
, mDNSfalse
); mDNS_Unlock(m
); };
4262 mStatus result
= needSetKeys
? AutoTunnelSetKeys(tun
, mDNStrue
) : mStatus_NoError
;
4263 static char msgbuf
[32];
4264 mDNS_snprintf(msgbuf
, sizeof(msgbuf
), "Tunnel setup - %d", result
);
4265 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.config", result
? "failure" : "success", msgbuf
, "");
4266 // Kick off any questions that were held pending this tunnel setup
4267 ReissueBlockedQuestions(m
, &tun
->dstname
, (result
== mStatus_NoError
) ? mDNStrue
: mDNSfalse
);
4270 mDNSexport
void AutoTunnelCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
4272 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
4274 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun
, AddRecord
, answer
->rdlength
, question
->qtype
);
4276 if (!AddRecord
) return;
4277 mDNS_StopQuery(m
, question
);
4279 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
4280 // The code below will look for _autotunnel._udp SRV record followed by A record
4281 if (tun
->tc_state
!= TC_STATE_AAAA_PEER_RELAY
&& !answer
->rdlength
)
4283 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
4284 static char msgbuf
[16];
4285 mDNS_snprintf(msgbuf
, sizeof(msgbuf
), "%s lookup", DNSTypeName(question
->qtype
));
4286 mDNSASLLog((uuid_t
*)&m
->asl_uuid
, "autotunnel.config", "failure", msgbuf
, "");
4287 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNSfalse
);
4291 switch (tun
->tc_state
)
4293 case TC_STATE_AAAA_PEER
:
4294 if (question
->qtype
!= kDNSType_AAAA
)
4296 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question
->qtype
);
4298 if (mDNSSameIPv6Address(answer
->rdata
->u
.ipv6
, m
->AutoTunnelHostAddr
))
4300 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer
->rdata
->u
.ipv6
);
4301 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNStrue
);
4304 tun
->rmt_inner
= answer
->rdata
->u
.ipv6
;
4305 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun
->rmt_inner
);
4306 if (!mDNSIPv6AddressIsZero(m
->AutoTunnelRelayAddrOut
))
4308 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
4309 tun
->tc_state
= TC_STATE_AAAA_PEER_RELAY
;
4310 question
->qtype
= kDNSType_AAAA
;
4311 AssignDomainName(&question
->qname
, (const domainname
*) "\x0C" "_autotunnel6");
4315 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
4316 tun
->tc_state
= TC_STATE_SRV_PEER
;
4317 question
->qtype
= kDNSType_SRV
;
4318 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
4320 AppendDomainName(&question
->qname
, &tun
->dstname
);
4321 mDNS_StartQuery(m
, &tun
->q
);
4323 case TC_STATE_AAAA_PEER_RELAY
:
4324 if (question
->qtype
!= kDNSType_AAAA
)
4326 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question
->qtype
);
4328 // If it failed, look for the SRV record.
4329 if (!answer
->rdlength
)
4331 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
4332 tun
->tc_state
= TC_STATE_SRV_PEER
;
4333 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
4334 AppendDomainName(&question
->qname
, &tun
->dstname
);
4335 question
->qtype
= kDNSType_SRV
;
4336 mDNS_StartQuery(m
, &tun
->q
);
4339 TunnelClientFinish(m
, question
, answer
);
4341 case TC_STATE_SRV_PEER
:
4342 if (question
->qtype
!= kDNSType_SRV
)
4344 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question
->qtype
);
4346 LogInfo("AutoTunnelCallback: SRV target name %##s", answer
->rdata
->u
.srv
.target
.c
);
4347 tun
->tc_state
= TC_STATE_ADDR_PEER
;
4348 AssignDomainName(&tun
->q
.qname
, &answer
->rdata
->u
.srv
.target
);
4349 tun
->rmt_outer_port
= answer
->rdata
->u
.srv
.port
;
4350 question
->qtype
= kDNSType_A
;
4351 mDNS_StartQuery(m
, &tun
->q
);
4353 case TC_STATE_ADDR_PEER
:
4354 if (question
->qtype
!= kDNSType_A
)
4356 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question
->qtype
);
4358 TunnelClientFinish(m
, question
, answer
);
4361 LogMsg("AutoTunnelCallback: Unknown question %p", question
);
4365 // Must be called with the lock held
4366 mDNSexport
void AddNewClientTunnel(mDNS
*const m
, DNSQuestion
*const q
)
4368 ClientTunnel
*p
= mallocL("ClientTunnel", sizeof(ClientTunnel
));
4370 p
->prefix
= q
->AuthInfo
->AutoTunnel
;
4371 AssignDomainName(&p
->dstname
, &q
->qname
);
4372 p
->MarkedForDeletion
= mDNSfalse
;
4373 p
->loc_inner
= zerov6Addr
;
4374 p
->loc_outer
= zerov4Addr
;
4375 p
->loc_outer6
= zerov6Addr
;
4376 p
->rmt_inner
= zerov6Addr
;
4377 p
->rmt_outer
= zerov4Addr
;
4378 p
->rmt_outer6
= zerov6Addr
;
4379 p
->rmt_outer_port
= zeroIPPort
;
4380 p
->tc_state
= TC_STATE_AAAA_PEER
;
4381 p
->next
= m
->TunnelClients
;
4382 m
->TunnelClients
= p
; // We intentionally build list in reverse order
4384 p
->q
.InterfaceID
= mDNSInterface_Any
;
4385 p
->q
.Target
= zeroAddr
;
4386 AssignDomainName(&p
->q
.qname
, &q
->qname
);
4387 p
->q
.qtype
= kDNSType_AAAA
;
4388 p
->q
.qclass
= kDNSClass_IN
;
4389 p
->q
.LongLived
= mDNSfalse
;
4390 p
->q
.ExpectUnique
= mDNStrue
;
4391 p
->q
.ForceMCast
= mDNSfalse
;
4392 p
->q
.ReturnIntermed
= mDNStrue
;
4393 p
->q
.SuppressUnusable
= mDNSfalse
;
4394 p
->q
.SearchListIndex
= 0;
4395 p
->q
.AppendSearchDomains
= 0;
4396 p
->q
.RetryWithSearchDomains
= mDNSfalse
;
4397 p
->q
.TimeoutQuestion
= 0;
4398 p
->q
.WakeOnResolve
= 0;
4399 p
->q
.qnameOrig
= mDNSNULL
;
4400 p
->q
.QuestionCallback
= AutoTunnelCallback
;
4401 p
->q
.QuestionContext
= p
;
4403 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p
, &q
->qname
.c
, DNSTypeName(q
->qtype
), q
->LongLived
? " LongLived" : "");
4404 mDNS_StartQuery_internal(m
, &p
->q
);
4407 #endif // APPLE_OSX_mDNSResponder
4409 #if COMPILER_LIKES_PRAGMA_MARK
4411 #pragma mark - Power State & Configuration Change Management
4414 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
, mDNSs32 utc
)
4416 mDNSBool foundav4
= mDNSfalse
;
4417 mDNSBool foundav6
= mDNSfalse
;
4418 struct ifaddrs
*ifa
= myGetIfAddrs(1);
4419 struct ifaddrs
*v4Loopback
= NULL
;
4420 struct ifaddrs
*v6Loopback
= NULL
;
4421 char defaultname
[64];
4423 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
4424 if (InfoSocket
< 3 && errno
!= EAFNOSUPPORT
) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
4427 // During wakeup, we may get a network change notification e.g., new addresses, before we get
4428 // a wake notification. This means that we have not set AnnounceOwner. Registering interfaces with
4429 // core would cause us to probe again which will conflict with the sleep proxy server, if we had
4430 // registered with it when going to sleep. Hence, need to delay until we get the wake notification
4432 if (m
->SleepState
== SleepState_Sleeping
) ifa
= NULL
;
4436 #if LIST_ALL_INTERFACES
4437 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
4438 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
4439 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4440 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
4441 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
4442 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4443 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
4444 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
4445 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4446 if (!(ifa
->ifa_flags
& IFF_UP
))
4447 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
4448 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4449 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
4450 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
4451 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4452 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
4453 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
4454 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4455 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
4456 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
4457 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
4460 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
4462 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
4463 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(m
->PrimaryMAC
) && mDNSSameEthAddress(&m
->PrimaryMAC
, &zeroEthAddr
))
4464 mDNSPlatformMemCopy(m
->PrimaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6);
4467 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
)
4468 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
4470 if (!ifa
->ifa_netmask
)
4473 SetupAddr(&ip
, ifa
->ifa_addr
);
4474 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
4475 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
4477 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
4478 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4479 else if (ifa
->ifa_netmask
->sa_family
!= ifa
->ifa_addr
->sa_family
&& ifa
->ifa_netmask
->sa_family
!= 0)
4482 SetupAddr(&ip
, ifa
->ifa_addr
);
4483 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
4484 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
4486 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
4487 else if ((int)if_nametoindex(ifa
->ifa_name
) <= 0)
4489 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
));
4493 // Make sure ifa_netmask->sa_family is set correctly
4494 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4495 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
;
4496 int ifru_flags6
= 0;
4498 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
4499 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
4501 struct in6_ifreq ifr6
;
4502 mDNSPlatformMemZero((char *)&ifr6
, sizeof(ifr6
));
4503 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
4504 ifr6
.ifr_addr
= *sin6
;
4505 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
4506 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
4507 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
4510 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
4512 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
4514 if (ifa
->ifa_addr
->sa_family
== AF_INET
) v4Loopback
= ifa
;
4516 else if (sin6
->sin6_addr
.s6_addr
[0] != 0xFD) v6Loopback
= ifa
;
4521 NetworkInterfaceInfoOSX
*i
= AddInterfaceToList(m
, ifa
, utc
);
4522 if (i
&& MulticastInterface(i
) && i
->ifinfo
.Advertise
)
4524 if (ifa
->ifa_addr
->sa_family
== AF_INET
) foundav4
= mDNStrue
;
4525 else foundav6
= mDNStrue
;
4531 ifa
= ifa
->ifa_next
;
4534 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
4535 if (!foundav4
&& v4Loopback
) AddInterfaceToList(m
, v4Loopback
, utc
);
4536 if (!foundav6
&& v6Loopback
) AddInterfaceToList(m
, v6Loopback
, utc
);
4538 // Now the list is complete, set the McastTxRx setting for each interface.
4539 NetworkInterfaceInfoOSX
*i
;
4540 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
4543 mDNSBool txrx
= MulticastInterface(i
);
4544 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
4545 txrx
= txrx
&& ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
4547 if (i
->ifinfo
.McastTxRx
!= txrx
)
4549 i
->ifinfo
.McastTxRx
= txrx
;
4550 i
->Exists
= 2; // State change; need to deregister and reregister this interface
4555 if (InfoSocket
>= 0) close(InfoSocket
);
4558 // If we haven't set up AutoTunnelHostAddr yet, do it now
4559 if (!mDNSSameEthAddress(&m
->PrimaryMAC
, &zeroEthAddr
) && m
->AutoTunnelHostAddr
.b
[0] == 0)
4561 m
->AutoTunnelHostAddr
.b
[0x0] = 0xFD; // Required prefix for "locally assigned" ULA (See RFC 4193)
4562 m
->AutoTunnelHostAddr
.b
[0x1] = mDNSRandom(255);
4563 m
->AutoTunnelHostAddr
.b
[0x2] = mDNSRandom(255);
4564 m
->AutoTunnelHostAddr
.b
[0x3] = mDNSRandom(255);
4565 m
->AutoTunnelHostAddr
.b
[0x4] = mDNSRandom(255);
4566 m
->AutoTunnelHostAddr
.b
[0x5] = mDNSRandom(255);
4567 m
->AutoTunnelHostAddr
.b
[0x6] = mDNSRandom(255);
4568 m
->AutoTunnelHostAddr
.b
[0x7] = mDNSRandom(255);
4569 m
->AutoTunnelHostAddr
.b
[0x8] = m
->PrimaryMAC
.b
[0] ^ 0x02; // See RFC 3513, Appendix A for explanation
4570 m
->AutoTunnelHostAddr
.b
[0x9] = m
->PrimaryMAC
.b
[1];
4571 m
->AutoTunnelHostAddr
.b
[0xA] = m
->PrimaryMAC
.b
[2];
4572 m
->AutoTunnelHostAddr
.b
[0xB] = 0xFF;
4573 m
->AutoTunnelHostAddr
.b
[0xC] = 0xFE;
4574 m
->AutoTunnelHostAddr
.b
[0xD] = m
->PrimaryMAC
.b
[3];
4575 m
->AutoTunnelHostAddr
.b
[0xE] = m
->PrimaryMAC
.b
[4];
4576 m
->AutoTunnelHostAddr
.b
[0xF] = m
->PrimaryMAC
.b
[5];
4577 m
->AutoTunnelLabel
.c
[0] = mDNS_snprintf((char*)m
->AutoTunnelLabel
.c
+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
4578 m
->AutoTunnelHostAddr
.b
[0x8], m
->AutoTunnelHostAddr
.b
[0x9], m
->AutoTunnelHostAddr
.b
[0xA], m
->AutoTunnelHostAddr
.b
[0xB],
4579 m
->AutoTunnelHostAddr
.b
[0xC], m
->AutoTunnelHostAddr
.b
[0xD], m
->AutoTunnelHostAddr
.b
[0xE], m
->AutoTunnelHostAddr
.b
[0xF]);
4580 LogInfo("m->AutoTunnelLabel %#s", m
->AutoTunnelLabel
.c
);
4583 mDNS_snprintf(defaultname
, sizeof(defaultname
), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen
, HINFO_HWstring
,
4584 m
->PrimaryMAC
.b
[0], m
->PrimaryMAC
.b
[1], m
->PrimaryMAC
.b
[2], m
->PrimaryMAC
.b
[3], m
->PrimaryMAC
.b
[4], m
->PrimaryMAC
.b
[5]);
4586 // Set up the nice label
4587 domainlabel nicelabel
;
4589 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
4590 if (nicelabel
.c
[0] == 0)
4592 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname
);
4593 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
4596 // Set up the RFC 1034-compliant label
4597 domainlabel hostlabel
;
4599 GetUserSpecifiedLocalHostName(&hostlabel
);
4600 if (hostlabel
.c
[0] == 0)
4602 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname
);
4603 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
4606 mDNSBool namechange
= mDNSfalse
;
4608 // We use a case-sensitive comparison here because even though changing the capitalization
4609 // of the name alone is not significant to DNS, it's still a change from the user's point of view
4610 if (SameDomainLabelCS(m
->p
->usernicelabel
.c
, nicelabel
.c
))
4611 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
4614 if (m
->p
->usernicelabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
4615 LogMsg("User updated Computer Name from “%#s” to “%#s”", m
->p
->usernicelabel
.c
, nicelabel
.c
);
4616 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
4617 namechange
= mDNStrue
;
4620 if (SameDomainLabelCS(m
->p
->userhostlabel
.c
, hostlabel
.c
))
4621 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
4624 if (m
->p
->userhostlabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
4625 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m
->p
->userhostlabel
.c
, hostlabel
.c
);
4626 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
4628 namechange
= mDNStrue
;
4631 #if APPLE_OSX_mDNSResponder
4632 if (namechange
) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
4634 DomainAuthInfo
*info
;
4635 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
4636 if (info
->AutoTunnel
) AutoTunnelHostNameChanged(m
, info
);
4638 #endif // APPLE_OSX_mDNSResponder
4640 return(mStatus_NoError
);
4643 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
4644 // Returns -1 if all the one-bits are not contiguous
4645 mDNSlocal
int CountMaskBits(mDNSAddr
*mask
)
4647 int i
= 0, bits
= 0;
4648 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
4651 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
4652 while (b
& 0x80) { bits
++; b
<<= 1; }
4655 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
4659 // returns count of non-link local V4 addresses registered
4660 mDNSlocal
int SetupActiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
4662 NetworkInterfaceInfoOSX
*i
;
4664 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
4667 NetworkInterfaceInfo
*const n
= &i
->ifinfo
;
4668 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AAAA_OVER_V4
? AF_UNSPEC
: i
->sa_family
);
4669 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifinfo
.ifname
);
4671 if (i
->Registered
&& i
->Registered
!= primary
) // Sanity check
4673 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i
->Registered
, primary
);
4674 i
->Registered
= mDNSNULL
;
4679 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
4680 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
4681 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it
4684 i
->Registered
= primary
;
4686 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
4687 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
4688 // 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.
4689 i
->Occulting
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->LastSeen
> 0 && utc
- i
->LastSeen
< 60);
4691 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
4692 // everytime it creates a new interface. We think it is a duplicate and hence consider it
4693 // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
4694 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
4695 // logs a warning message to system.log noting frequent interface transitions.
4696 if (strncmp(i
->ifinfo
.ifname
, "p2p", 3) == 0)
4698 LogInfo("SetupActiveInterfaces: P2P %s interface registering %s %s", i
->ifinfo
.ifname
,
4699 i
->Flashing
? " (Flashing)" : "",
4700 i
->Occulting
? " (Occulting)" : "");
4701 mDNS_RegisterInterface(m
, n
, 0);
4705 mDNS_RegisterInterface(m
, n
, i
->Flashing
&& i
->Occulting
);
4708 if (!mDNSAddressIsLinkLocal(&n
->ip
)) count
++;
4709 LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
4710 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
, primary
, &n
->ip
, CountMaskBits(&n
->mask
),
4711 i
->Flashing
? " (Flashing)" : "",
4712 i
->Occulting
? " (Occulting)" : "",
4713 n
->InterfaceActive
? " (Primary)" : "");
4716 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
);
4719 if (i
->sa_family
== AF_INET
)
4722 primary
->ifa_v4addr
.s_addr
= n
->ip
.ip
.v4
.NotAnInteger
;
4723 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
4724 imr
.imr_interface
= primary
->ifa_v4addr
;
4726 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
4727 // before trying to join the group, to clear out stale kernel state which may be lingering.
4728 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
4729 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
4730 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
4731 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
4732 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
4733 // because by the time we get the configuration change notification, the interface is already gone,
4734 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
4735 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
4736 if (SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AF_INET
) == i
)
4738 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
);
4739 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, &imr
, sizeof(imr
));
4740 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
4741 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err
, errno
, strerror(errno
));
4744 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i
->ifinfo
.ifname
, i
->scope_id
, &imr
.imr_multiaddr
, &imr
.imr_interface
);
4745 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
4746 // Joining same group twice can give "Address already in use" error -- no need to report that
4747 if (err
< 0 && (errno
!= EADDRINUSE
))
4748 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err
, errno
, strerror(errno
), &imr
.imr_multiaddr
, &imr
.imr_interface
);
4751 if (i
->sa_family
== AF_INET6
)
4753 struct ipv6_mreq i6mr
;
4754 i6mr
.ipv6mr_interface
= primary
->scope_id
;
4755 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroup_v6
.ip
.v6
;
4757 if (SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AF_INET6
) == i
)
4759 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
);
4760 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
4761 if (err
< 0 && (errno
!= EADDRNOTAVAIL
))
4762 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
4765 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i
->ifinfo
.ifname
, i
->scope_id
, &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
4766 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
4767 // Joining same group twice can give "Address already in use" error -- no need to report that
4768 if (err
< 0 && (errno
!= EADDRINUSE
))
4769 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
4779 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
, mDNSs32 utc
)
4781 NetworkInterfaceInfoOSX
*i
;
4782 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
4784 if (i
->Exists
) i
->LastSeen
= utc
;
4785 i
->Exists
= mDNSfalse
;
4789 // returns count of non-link local V4 addresses deregistered
4790 mDNSlocal
int ClearInactiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
4793 // If an interface is going away, then deregister this from the mDNSCore.
4794 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
4795 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
4796 // it refers to has gone away we'll crash.
4797 NetworkInterfaceInfoOSX
*i
;
4799 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
4801 // If this interface is no longer active, or its InterfaceID is changing, deregister it
4802 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifinfo
.ifname
, AAAA_OVER_V4
? AF_UNSPEC
: i
->sa_family
);
4804 if (i
->Exists
== 0 || i
->Exists
== 2 || i
->Registered
!= primary
)
4806 i
->Flashing
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->AppearanceTime
< 60);
4807 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
4808 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
, primary
,
4809 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
),
4810 i
->Flashing
? " (Flashing)" : "",
4811 i
->Occulting
? " (Occulting)" : "",
4812 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
4814 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
4815 // everytime it creates a new interface. We think it is a duplicate and hence consider it
4816 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
4817 // stale data returned to the application even after the interface is removed. The application
4818 // then starts to send data but the new interface is not yet created.
4819 if (strncmp(i
->ifinfo
.ifname
, "p2p", 3) == 0)
4821 LogInfo("ClearInactiveInterfaces: P2P %s interface deregistering %s %s", i
->ifinfo
.ifname
,
4822 i
->Flashing
? " (Flashing)" : "",
4823 i
->Occulting
? " (Occulting)" : "");
4824 mDNS_DeregisterInterface(m
, &i
->ifinfo
, 0);
4828 mDNS_DeregisterInterface(m
, &i
->ifinfo
, i
->Flashing
&& i
->Occulting
);
4830 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
4831 i
->Registered
= mDNSNULL
;
4832 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
4833 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
4834 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
4836 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
4837 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
4842 // Now that everything that's going to deregister has done so, we can clean up and free the memory
4843 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
4847 // If no longer active, delete interface from list and free memory
4850 if (i
->LastSeen
== utc
) i
->LastSeen
= utc
- 1;
4851 mDNSBool
delete = (NumCacheRecordsForInterfaceID(m
, i
->ifinfo
.InterfaceID
) == 0) && (utc
- i
->LastSeen
>= 60);
4852 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
4853 i
->ifinfo
.ifname
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, i
,
4854 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), utc
- i
->LastSeen
,
4855 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
4856 #if APPLE_OSX_mDNSResponder
4857 if (i
->BPF_fd
>= 0) CloseBPF(i
);
4858 #endif // APPLE_OSX_mDNSResponder
4862 freeL("NetworkInterfaceInfoOSX", i
);
4863 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
4871 mDNSlocal
void AppendDNameListElem(DNameListElem
***List
, mDNSu32 uid
, domainname
*name
)
4873 DNameListElem
*dnle
= (DNameListElem
*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem
));
4874 if (!dnle
) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
4877 dnle
->next
= mDNSNULL
;
4879 AssignDomainName(&dnle
->name
, name
);
4881 *List
= &dnle
->next
;
4885 mDNSlocal
int compare_dns_configs(const void *aa
, const void *bb
)
4887 dns_resolver_t
*a
= *(dns_resolver_t
**)aa
;
4888 dns_resolver_t
*b
= *(dns_resolver_t
**)bb
;
4890 return (a
->search_order
< b
->search_order
) ? -1 : (a
->search_order
== b
->search_order
) ? 0 : 1;
4893 // ConfigResolvers is called twice - once to parse the "scoped_resolver" list and second time to parse the "resolver" list.
4894 // "scoped_resolver" has entries that should only be used for "scoped_questions" (for questions that specify an interface index
4895 // q->InterfaceID) and "resolver" entries should only be used for non-scoped questions. Entries in either of the list can specify
4896 // an ifindex. This means that the dns query should be scoped to that interface when sent out on the wire. The flag value
4897 // "DNS_RESOLVER_FLAGS_SCOPED" itself appears only in "scoped" list of resolvers.
4899 // Before "scoped_resolver" was introduced, the entries in "resolver" list can contain options like "interface=en0" which
4900 // was meant to scope the query (non-scoped queries) to a specific interface. We still support this option. On top of that,
4901 // we also support a new way of specifying the interface index as described above.
4902 mDNSlocal
void ConfigResolvers(mDNS
*const m
, dns_config_t
*config
, mDNSBool scope
, mDNSBool setsearch
, mDNSBool setservers
)
4906 #if DNSINFO_VERSION >= 20091104
4907 dns_resolver_t
**resolver
= scope
? config
->scoped_resolver
: config
->resolver
;
4908 int nresolvers
= scope
? config
->n_scoped_resolver
: config
->n_resolver
;
4910 (void) scope
; // unused
4911 dns_resolver_t
**resolver
= config
->resolver
;
4912 int nresolvers
= config
->n_resolver
;
4915 if (setsearch
&& !scope
&& nresolvers
)
4917 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
4918 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
4919 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
4920 // instead use the search domain list as the sole authority for what domains to search and in what order
4921 // (and the domain from the "domain" field will also appear somewhere in that list).
4922 // Also, all search domains get added to the search list for resolver[0], so the domains and/or
4923 // search lists for other resolvers in the list need to be ignored.
4925 // Note: Starting DNSINFO_VERSION 20091104, search list is present only in the first resolver (resolver 0).
4926 // i.e., n_search for the first resolver is always non-zero. We don't guard it with #ifs for better readability
4928 if (resolver
[0]->n_search
== 0)
4930 LogInfo("ConfigResolvers: (%s) configuring zeroth domain as search list %s", scope
? "Scoped" : "Non-scoped", resolver
[0]->domain
);
4931 mDNS_AddSearchDomain_CString(resolver
[0]->domain
, mDNSNULL
);
4935 for (i
= 0; i
< resolver
[0]->n_search
; i
++)
4937 LogInfo("ConfigResolvers: (%s) configuring search list %s", scope
? "Scoped" : "Non-scoped", resolver
[0]->search
[i
]);
4938 mDNS_AddSearchDomain_CString(resolver
[0]->search
[i
], mDNSNULL
);
4943 // scoped search domains are set below. If neither scoped nor setting servers, we have nothing to do
4944 if (!scope
&& !setservers
) return;
4946 // For the "default" resolver ("resolver #1") the "domain" value is bogus and we need to ignore it.
4947 // e.g. the default resolver's "domain" value might say "apple.com", which indicates that this resolver
4948 // is only for names that fall under "apple.com", but that's not correct. Actually the default resolver is
4949 // for all names not covered by a more specific resolver (i.e. its domain should be ".", the root domain).
4951 // Note: Starting DNSINFO_VERSION 20091104, domain value of this first resolver (resolver 0) is always NULL.
4952 // We don't guard it with #ifs for better readability
4954 if ((nresolvers
!= 0) && resolver
[0]->domain
)
4955 resolver
[0]->domain
[0] = 0; // don't stop pointing at the memory, just change the first byte
4957 qsort(resolver
, nresolvers
, sizeof(dns_resolver_t
*), compare_dns_configs
);
4959 for (i
= 0; i
< nresolvers
; i
++)
4962 dns_resolver_t
*r
= resolver
[i
];
4963 mDNSInterfaceID interface
= mDNSInterface_Any
;
4966 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scope
? "Scoped" : "", i
, r
->domain
, r
->n_nameserver
);
4968 // On Tiger, dnsinfo entries for mDNS domains have port 5353, the mDNS port. Ignore them.
4969 // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
4970 // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
4971 // We also don't need to do any more work if there are no nameserver addresses
4972 if (r
->port
== 5353 || r
->n_nameserver
== 0)
4974 char *opt
= r
->options
;
4975 if (opt
&& !strncmp(opt
, "mdns", strlen(opt
)))
4977 if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
))
4978 { LogMsg("ConfigResolvers: config->resolver[%d] bad domain %s", i
, r
->domain
); continue; }
4979 mDNS_AddMcastResolver(m
, &d
, interface
, r
->timeout
);
4985 if (!r
->domain
|| !*r
->domain
) d
.c
[0] = 0;
4986 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
))
4987 { LogMsg("ConfigResolvers: config->resolver[%d] bad domain %s", i
, r
->domain
); continue; }
4989 // DNS server option parsing
4990 if (r
->options
!= NULL
)
4992 char *nextOption
= r
->options
;
4993 char *currentOption
= NULL
;
4994 while ((currentOption
= strsep(&nextOption
, " ")) != NULL
&& currentOption
[0] != 0)
4996 // The option may be in the form of interface=xxx where xxx is an interface name.
4997 if (strncmp(currentOption
, kInterfaceSpecificOption
, sizeof(kInterfaceSpecificOption
) - 1) == 0)
4999 NetworkInterfaceInfoOSX
*ni
;
5000 char ifname
[IF_NAMESIZE
+1];
5001 mDNSu32 ifindex
= 0;
5002 // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
5003 // This allows us to block these special queries from going out on the wire.
5004 strlcpy(ifname
, currentOption
+ sizeof(kInterfaceSpecificOption
)-1, sizeof(ifname
));
5005 ifindex
= if_nametoindex(ifname
);
5006 if (ifindex
== 0) { disabled
= 1; LogMsg("ConfigResolvers: RegisterSplitDNS interface specific - interface %s not found", ifname
); continue; }
5007 LogInfo("ConfigResolvers: interface specific entry: %s on %s (%d)", r
->domain
, ifname
, ifindex
);
5008 // Find the interface. Can't use mDNSPlatformInterfaceIDFromInterfaceIndex
5009 // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
5010 for (ni
= m
->p
->InterfaceList
; ni
; ni
= ni
->next
)
5011 if (ni
->ifinfo
.InterfaceID
&& ni
->scope_id
== ifindex
) break;
5012 if (ni
!= NULL
) interface
= ni
->ifinfo
.InterfaceID
;
5013 if (interface
== mDNSNULL
)
5016 LogMsg("ConfigResolvers: RegisterSplitDNS interface specific - index %d (%s) not found", ifindex
, ifname
);
5023 // flags and if_index are defined only from this DNSINFO_VERSION onwards.
5024 // Parse the interface index if we have not already parsed one above.
5025 #if DNSINFO_VERSION >= 20091104
5026 if ((interface
== mDNSInterface_Any
) && (r
->if_index
!= 0))
5028 NetworkInterfaceInfoOSX
*ni
;
5029 interface
= mDNSNULL
;
5030 for (ni
= m
->p
->InterfaceList
; ni
; ni
= ni
->next
)
5031 if (ni
->ifinfo
.InterfaceID
&& ni
->scope_id
== r
->if_index
) break;
5032 if (ni
!= NULL
) interface
= ni
->ifinfo
.InterfaceID
;
5033 if (interface
== mDNSNULL
)
5036 LogMsg("ConfigResolvers: interface specific index %d not found", r
->if_index
);
5044 // For non-scoped resolvers unlike scoped resolvers, only zeroth resolver has search lists if any. For scoped
5045 // resolvers, we need to parse all the entries.
5048 for (j
= 0; j
< resolver
[i
]->n_search
; j
++)
5050 LogInfo("ConfigResolvers: (%s) configuring search list %s, Interface %p", scope
? "Scoped" : "Non-scoped", resolver
[i
]->search
[j
], interface
);
5051 mDNS_AddSearchDomain_CString(resolver
[i
]->search
[j
], interface
);
5053 // Parse other scoped resolvers for search lists
5054 if (!setservers
) continue;
5058 for (n
= 0; n
< r
->n_nameserver
; n
++)
5059 if (r
->nameserver
[n
]->sa_family
== AF_INET
|| r
->nameserver
[n
]->sa_family
== AF_INET6
)
5062 // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
5063 if (SetupAddr(&saddr
, r
->nameserver
[n
])) LogMsg("RegisterSplitDNS: bad IP address");
5066 mDNSBool scopedDNS
= mDNSfalse
;
5068 #if DNSINFO_VERSION >= 20091104
5069 // By setting scoped, this DNSServer can only be picked if the right interfaceID
5070 // is given in the question.
5071 if (scope
&& (r
->flags
& DNS_RESOLVER_FLAGS_SCOPED
) && (interface
== mDNSNULL
))
5072 LogMsg("ConfigResolvers: ERROR: scoped is set but if_index %d is invalid for DNSServer %#a:%d",
5073 r
->if_index
, &saddr
, mDNSVal16(r
->port
? mDNSOpaque16fromIntVal(r
->port
) : UnicastDNSPort
));
5075 scopedDNS
= (scope
&& (r
->flags
& DNS_RESOLVER_FLAGS_SCOPED
)) ? mDNStrue
: mDNSfalse
;
5077 // The timeout value is for all the DNS servers in a given resolver, hence we pass
5078 // the timeout value only for the first DNSServer. If we don't have a value in the
5079 // resolver, then use the core's default value
5081 // Note: this assumes that when the core picks a list of DNSServers for a question,
5082 // it takes the sum of all the timeout values for all DNS servers. By doing this, it
5083 // tries all the DNS servers in a specified timeout
5084 s
= mDNS_AddDNSServer(m
, &d
, interface
, &saddr
, r
->port
? mDNSOpaque16fromIntVal(r
->port
) : UnicastDNSPort
, scopedDNS
,
5085 (n
== 0 ? (r
->timeout
? r
->timeout
: DEFAULT_UDNS_TIMEOUT
) : 0));
5088 if (disabled
) s
->teststate
= DNSServer_Disabled
;
5089 LogInfo("ConfigResolvers: DNS server %#a:%d for domain %##s from slot %d, %d",
5090 &s
->addr
, mDNSVal16(s
->port
), d
.c
, i
, n
);
5097 mDNSexport
void mDNSPlatformSetDNSConfig(mDNS
*const m
, mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
, DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
)
5100 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
5103 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
5104 if (fqdn
) fqdn
->c
[0] = 0;
5105 if (RegDomains
) *RegDomains
= NULL
;
5106 if (BrowseDomains
) *BrowseDomains
= NULL
;
5108 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
5109 setservers
? " setservers" : "",
5110 setsearch
? " setsearch" : "",
5111 fqdn
? " fqdn" : "",
5112 RegDomains
? " RegDomains" : "",
5113 BrowseDomains
? " BrowseDomains" : "");
5115 // Add the inferred address-based configuration discovery domains
5116 // (should really be in core code I think, not platform-specific)
5119 struct ifaddrs
*ifa
= mDNSNULL
;
5120 struct sockaddr_in saddr
;
5121 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
5122 saddr
.sin_len
= sizeof(saddr
);
5123 saddr
.sin_family
= AF_INET
;
5125 saddr
.sin_addr
.s_addr
= *(in_addr_t
*)&m
->Router
.ip
.v4
;
5127 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
5128 if (!AddrRequiresPPPConnection((struct sockaddr
*)&saddr
)) ifa
= myGetIfAddrs(1);
5133 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
5135 !(ifa
->ifa_flags
& IFF_LOOPBACK
) &&
5136 !SetupAddr(&a
, ifa
->ifa_addr
) &&
5137 !mDNSv4AddressIsLinkLocal(&a
.ip
.v4
) )
5139 // 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
5140 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5141 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
; // Make sure ifa_netmask->sa_family is set correctly
5142 SetupAddr(&n
, ifa
->ifa_netmask
);
5143 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
5144 mDNS_snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d.in-addr.arpa.", a
.ip
.v4
.b
[3] & n
.ip
.v4
.b
[3],
5145 a
.ip
.v4
.b
[2] & n
.ip
.v4
.b
[2],
5146 a
.ip
.v4
.b
[1] & n
.ip
.v4
.b
[1],
5147 a
.ip
.v4
.b
[0] & n
.ip
.v4
.b
[0]);
5148 mDNS_AddSearchDomain_CString(buf
, mDNSNULL
);
5150 ifa
= ifa
->ifa_next
;
5154 #ifndef MDNS_NO_DNSINFO
5155 if (setservers
|| setsearch
)
5157 dns_config_t
*config
= dns_configuration_copy();
5160 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
5161 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
5162 // Apparently this is expected behaviour -- "not a bug".
5163 // Accordingly, we suppress syslog messages for the first three minutes after boot.
5164 // If we are still getting failures after three minutes, then we log them.
5165 if ((mDNSu32
)mDNSPlatformRawTime() > (mDNSu32
)(mDNSPlatformOneSecond
* 180))
5166 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
5170 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config
->n_resolver
);
5172 #if APPLE_OSX_mDNSResponder
5173 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
5174 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
5175 if (config
->n_resolver
&& config
->resolver
[0]->domain
&& config
->resolver
[0]->n_nameserver
&& config
->resolver
[0]->nameserver
[0])
5176 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain
, config
->resolver
[0]->domain
);
5177 else ActiveDirectoryPrimaryDomain
.c
[0] = 0;
5178 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
5179 ActiveDirectoryPrimaryDomainLabelCount
= CountLabels(&ActiveDirectoryPrimaryDomain
);
5180 if (config
->n_resolver
&& config
->resolver
[0]->n_nameserver
&& SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain
, ActiveDirectoryPrimaryDomainLabelCount
- 1), &localdomain
))
5181 SetupAddr(&ActiveDirectoryPrimaryDomainServer
, config
->resolver
[0]->nameserver
[0]);
5184 AssignDomainName(&ActiveDirectoryPrimaryDomain
, (const domainname
*)"");
5185 ActiveDirectoryPrimaryDomainLabelCount
= 0;
5186 ActiveDirectoryPrimaryDomainServer
= zeroAddr
;
5190 ConfigResolvers(m
, config
, mDNSfalse
, setsearch
, setservers
);
5191 #if DNSINFO_VERSION >= 20091104
5192 ConfigResolvers(m
, config
, mDNStrue
, setsearch
, setservers
);
5194 dns_configuration_free(config
);
5195 if (setsearch
) RetrySearchDomainQuestions(m
);
5196 setservers
= mDNSfalse
; // Done these now -- no need to fetch the same data from SCDynamicStore
5197 setsearch
= mDNSfalse
;
5200 #endif // MDNS_NO_DNSINFO
5202 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL
, NULL
);
5204 LogMsg("mDNSPlatformSetDNSConfig: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5207 CFDictionaryRef ddnsdict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_DynamicDNS
);
5212 CFArrayRef fqdnArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("HostNames"));
5213 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
5215 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
5216 CFDictionaryRef fqdnDict
= CFArrayGetValueAtIndex(fqdnArray
, 0);
5217 if (fqdnDict
&& DictionaryIsEnabled(fqdnDict
))
5219 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
5222 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5223 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
5224 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
5225 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
5233 CFArrayRef regArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("RegistrationDomains"));
5234 if (regArray
&& CFArrayGetCount(regArray
) > 0)
5236 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
5237 if (regDict
&& DictionaryIsEnabled(regDict
))
5239 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
5242 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5243 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
5244 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
5247 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf
);
5248 AppendDNameListElem(&RegDomains
, 0, &d
);
5257 CFArrayRef browseArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("BrowseDomains"));
5260 for (i
= 0; i
< CFArrayGetCount(browseArray
); i
++)
5262 CFDictionaryRef browseDict
= CFArrayGetValueAtIndex(browseArray
, i
);
5263 if (browseDict
&& DictionaryIsEnabled(browseDict
))
5265 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
5268 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
5269 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
5270 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf
[0] ? buf
: "(unknown)");
5273 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf
);
5274 AppendDNameListElem(&BrowseDomains
, 0, &d
);
5281 CFRelease(ddnsdict
);
5286 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BackToMyMac
);
5289 CFIndex size
= CFDictionaryGetCount(btmm
);
5290 const void *key
[size
];
5291 const void *val
[size
];
5292 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
5293 for (i
= 0; i
< size
; i
++)
5295 LogInfo("BackToMyMac %d", i
);
5296 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5297 LogMsg("Can't read BackToMyMac %d key %s", i
, buf
);
5300 mDNSu32 uid
= atoi(buf
);
5301 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5302 LogMsg("Can't read BackToMyMac %d val %s", i
, buf
);
5303 else if (MakeDomainNameFromDNSNameString(&d
, buf
) && d
.c
[0])
5305 LogInfo("BackToMyMac %d %d %##s", i
, uid
, d
.c
);
5306 AppendDNameListElem(&RegDomains
, uid
, &d
);
5314 if (setservers
|| setsearch
)
5316 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_DNS
);
5321 CFArrayRef values
= CFDictionaryGetValue(dict
, kSCPropNetDNSServerAddresses
);
5324 LogInfo("DNS Server Address values: %d", (int)CFArrayGetCount(values
));
5325 for (i
= 0; i
< CFArrayGetCount(values
); i
++)
5327 CFStringRef s
= CFArrayGetValueAtIndex(values
, i
);
5328 mDNSAddr addr
= { mDNSAddrType_IPv4
, { { { 0 } } } };
5329 if (s
&& CFStringGetCString(s
, buf
, 256, kCFStringEncodingUTF8
) &&
5330 inet_aton(buf
, (struct in_addr
*) &addr
.ip
.v4
))
5332 LogInfo("Adding DNS server from dict: %s", buf
);
5333 mDNS_AddDNSServer(m
, mDNSNULL
, mDNSInterface_Any
, &addr
, UnicastDNSPort
, mDNSfalse
, 0);
5337 else LogInfo("No DNS Server Address values");
5341 // Add the manual and/or DHCP-dicovered search domains
5342 CFArrayRef searchDomains
= CFDictionaryGetValue(dict
, kSCPropNetDNSSearchDomains
);
5345 for (i
= 0; i
< CFArrayGetCount(searchDomains
); i
++)
5347 CFStringRef s
= CFArrayGetValueAtIndex(searchDomains
, i
);
5348 if (s
&& CFStringGetCString(s
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5349 mDNS_AddSearchDomain_CString(buf
, mDNSNULL
);
5352 else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
5354 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
5355 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
5356 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
5357 // instead use the search domain list as the sole authority for what domains to search and in what order
5358 // (and the domain from the "domain" field will also appear somewhere in that list).
5359 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetDNSDomainName
);
5360 if (string
&& CFStringGetCString(string
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5361 mDNS_AddSearchDomain_CString(buf
, mDNSNULL
);
5363 RetrySearchDomainQuestions(m
);
5372 mDNSexport mStatus
mDNSPlatformGetPrimaryInterface(mDNS
*const m
, mDNSAddr
*v4
, mDNSAddr
*v6
, mDNSAddr
*r
)
5377 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL
, NULL
);
5379 LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5382 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_IPv4
);
5385 r
->type
= mDNSAddrType_IPv4
;
5386 r
->ip
.v4
= zerov4Addr
;
5387 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
5390 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
5391 LogMsg("Could not convert router to CString");
5394 struct sockaddr_in saddr
;
5395 saddr
.sin_len
= sizeof(saddr
);
5396 saddr
.sin_family
= AF_INET
;
5398 inet_aton(buf
, &saddr
.sin_addr
);
5400 *(in_addr_t
*)&r
->ip
.v4
= saddr
.sin_addr
.s_addr
;
5404 string
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
5407 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
5408 struct ifaddrs
*ifa
= myGetIfAddrs(1);
5410 *v4
= *v6
= zeroAddr
;
5412 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
)) { LogMsg("Could not convert router to CString"); goto exit
; }
5414 // find primary interface in list
5415 while (ifa
&& (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
) || !HavePrimaryGlobalv6
))
5417 mDNSAddr tmp6
= zeroAddr
;
5418 if (!strcmp(buf
, ifa
->ifa_name
))
5420 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
5422 if (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
)) SetupAddr(v4
, ifa
->ifa_addr
);
5424 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
5426 SetupAddr(&tmp6
, ifa
->ifa_addr
);
5427 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
5428 { HavePrimaryGlobalv6
= mDNStrue
; *v6
= tmp6
; }
5433 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
5434 if (!HavePrimaryGlobalv6
&& ifa
->ifa_addr
->sa_family
== AF_INET6
&& !v6
->ip
.v6
.b
[0])
5436 SetupAddr(&tmp6
, ifa
->ifa_addr
);
5437 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) *v6
= tmp6
;
5440 ifa
= ifa
->ifa_next
;
5443 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
5444 // V4 to communicate w/ our DNS server
5452 return mStatus_NoError
;
5455 mDNSexport
void mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
5457 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status
, dname
->c
);
5458 char uname
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
5459 ConvertDomainNameToCString(dname
, uname
);
5465 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
5469 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
5470 // That single entity is a CFDictionary with name "HostNames".
5471 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
5472 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
5473 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
5474 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
5475 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
5477 const CFStringRef StateKeys
[1] = { CFSTR("HostNames") };
5478 const CFStringRef HostKeys
[1] = { CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
) };
5479 const CFStringRef StatusKeys
[1] = { CFSTR("Status") };
5480 if (!HostKeys
[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname
);
5483 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
5484 if (!StatusVals
[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status
);
5487 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
5490 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
) };
5493 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
5496 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig
, mDNSNULL
, StateDict
);
5497 CFRelease(StateDict
);
5499 CFRelease(StateVals
[0]);
5501 CFRelease(HostVals
[0]);
5503 CFRelease(StatusVals
[0]);
5505 CFRelease(HostKeys
[0]);
5509 #if APPLE_OSX_mDNSResponder
5512 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
5513 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
5515 mDNSlocal mDNSBool
IsBTMMDomain(domainname
*d
)
5517 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:IsBTMMDomain"), NULL
, NULL
);
5520 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5523 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BackToMyMac
);
5526 CFIndex size
= CFDictionaryGetCount(btmm
);
5527 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
5528 const void *key
[size
];
5529 const void *val
[size
];
5532 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
5533 for (i
= 0; i
< size
; i
++)
5535 LogInfo("BackToMyMac %d", i
);
5536 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5537 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i
, buf
);
5540 mDNSu32 uid
= atoi(buf
);
5541 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
5542 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i
, buf
);
5543 else if (MakeDomainNameFromDNSNameString(&dom
, buf
) && dom
.c
[0])
5545 if (SameDomainName(&dom
, d
))
5547 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d
->c
, uid
);
5558 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d
->c
);
5562 // Appends data to the buffer
5563 mDNSlocal
int AddOneItem(char *buf
, int bufsz
, char *data
, int *currlen
)
5567 len
= strlcpy(buf
+ *currlen
, data
, bufsz
- *currlen
);
5568 if (len
>= (bufsz
- *currlen
))
5570 // if we have exceeded the space in buf, it has already been NULL terminated
5571 // and we have nothing more to do. Set currlen to the last byte so that the caller
5572 // knows to do the right thing
5573 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen
, len
);
5574 *currlen
= bufsz
- 1;
5577 else { (*currlen
) += len
; }
5579 buf
[*currlen
] = ',';
5580 if (*currlen
>= bufsz
)
5582 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen
);
5583 *currlen
= bufsz
- 1;
5587 // if we have filled up the buffer exactly, then there is no more work to do
5588 if (*currlen
== bufsz
- 1) { buf
[*currlen
] = 0; return -1; }
5593 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
5594 // BTMM domains, then bring down the connection to the relay.
5595 mDNSlocal
void UpdateBTMMRelayConnection(mDNS
*const m
)
5597 DomainAuthInfo
*BTMMDomain
= mDNSNULL
;
5598 DomainAuthInfo
*FoundInList
;
5599 static mDNSBool AWACSDConnected
= mDNSfalse
;
5600 char AllUsers
[1024]; // maximum size of mach message
5601 char AllPass
[1024]; // maximum size of mach message
5602 char username
[MAX_DOMAIN_LABEL
+ 1];
5606 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
5607 // we may not be able to send the dns queries over the relay connection which may be needed
5608 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
5609 // need to make sure that we send the disconnect before attempting the next connect as the
5610 // awacs connections are redirected based on usernames.
5612 // For now we send a disconnect immediately. When we start sending dns queries over the relay
5613 // connection, we will need to fix this.
5615 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
5616 if (!FoundInList
->deltime
&& FoundInList
->AutoTunnel
&& IsBTMMDomain(&FoundInList
->domain
))
5618 // We need the passwd from the first domain.
5619 BTMMDomain
= FoundInList
;
5620 ConvertDomainLabelToCString_unescaped((domainlabel
*)BTMMDomain
->domain
.c
, username
);
5621 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username
, BTMMDomain
->domain
.c
);
5622 if (AddOneItem(AllUsers
, sizeof(AllUsers
), username
, &currulen
) == -1) break;
5623 if (AddOneItem(AllPass
, sizeof(AllPass
), BTMMDomain
->b64keydata
, &currplen
) == -1) break;
5628 // In the normal case (where we neither exceed the buffer size nor write bytes that
5629 // fit exactly into the buffer), currulen/currplen should be a different size than
5630 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
5632 if (currulen
!= (int)(sizeof(AllUsers
) - 1)) AllUsers
[currulen
- 1] = 0;
5633 if (currplen
!= (int)(sizeof(AllPass
) - 1)) AllPass
[currplen
- 1] = 0;
5635 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers
);
5636 AWACS_Connect(AllUsers
, AllPass
, "hello.connectivity.me.com");
5637 AWACSDConnected
= mDNStrue
;
5641 // Disconnect only if we connected previously
5642 if (AWACSDConnected
)
5644 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
5646 AWACSDConnected
= mDNSfalse
;
5648 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
5652 mDNSlocal
void UpdateBTMMRelayConnection(mDNS
*const m
)
5655 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
5657 #endif // ! NO_AWACS
5658 #endif // APPLE_OSX_mDNSResponder
5660 // MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
5661 mDNSexport
void SetDomainSecrets(mDNS
*m
)
5663 #ifdef NO_SECURITYFRAMEWORK
5665 LogMsg("Note: SetDomainSecrets: no keychain support");
5667 mDNSBool haveAutoTunnels
= mDNSfalse
;
5669 LogInfo("SetDomainSecrets");
5671 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
5672 // In the case where the user simultaneously removes their DDNS host name and the key
5673 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
5674 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
5675 // address records behind that we no longer have permission to delete.
5676 DomainAuthInfo
*ptr
;
5677 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
5678 ptr
->deltime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
*10);
5680 #if APPLE_OSX_mDNSResponder
5682 // Mark all TunnelClients for deletion
5683 ClientTunnel
*client
;
5684 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
5686 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client
->dstname
.c
);
5687 client
->MarkedForDeletion
= mDNStrue
;
5690 #endif // APPLE_OSX_mDNSResponder
5692 // String Array used to write list of private domains to Dynamic Store
5693 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
5694 if (!sa
) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
5696 CFDataRef data
= NULL
;
5697 const int itemsPerEntry
= 4; // domain name, key name, key value, Name value
5698 CFArrayRef secrets
= NULL
;
5699 int err
= mDNSKeychainGetSecrets(&secrets
);
5700 if (err
|| !secrets
)
5701 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err
, secrets
);
5704 CFIndex ArrayCount
= CFArrayGetCount(secrets
);
5705 // Iterate through the secrets
5706 for (i
= 0; i
< ArrayCount
; ++i
)
5708 mDNSBool AutoTunnel
;
5710 CFArrayRef entry
= CFArrayGetValueAtIndex(secrets
, i
);
5711 if (CFArrayGetTypeID() != CFGetTypeID(entry
) || itemsPerEntry
!= CFArrayGetCount(entry
))
5712 { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i
, itemsPerEntry
); continue; }
5713 for (j
= 0; j
< CFArrayGetCount(entry
); ++j
)
5714 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry
, j
)))
5715 { LogMsg("SetDomainSecrets: malformed entry item %d", j
); continue; }
5717 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
5719 // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
5720 // Get DNS domain this key is for (kmDNSKcWhere)
5721 char stringbuf
[MAX_ESCAPED_DOMAIN_NAME
+ sizeof(btmmprefix
)];
5722 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcWhere
);
5723 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
5724 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data
)); continue; }
5725 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
5726 stringbuf
[CFDataGetLength(data
)] = '\0';
5728 AutoTunnel
= mDNSfalse
;
5730 if (!strncmp(stringbuf
, dnsprefix
, strlen(dnsprefix
)))
5731 offset
= strlen(dnsprefix
);
5732 else if (!strncmp(stringbuf
, btmmprefix
, strlen(btmmprefix
)))
5734 AutoTunnel
= mDNStrue
;
5735 offset
= strlen(btmmprefix
);
5738 if (!MakeDomainNameFromDNSNameString(&domain
, stringbuf
+ offset
)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf
); continue; }
5740 // Get key name (kmDNSKcAccount)
5741 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcAccount
);
5742 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
5743 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data
)); continue; }
5744 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)stringbuf
);
5745 stringbuf
[CFDataGetLength(data
)] = '\0';
5748 if (!MakeDomainNameFromDNSNameString(&keyname
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf
); continue; }
5750 // Get key data (kmDNSKcKey)
5751 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcKey
);
5752 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
5753 { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data
)); continue; }
5754 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
5755 stringbuf
[CFDataGetLength(data
)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
5757 // Get the Name of the keychain entry (kmDNSKcName) host or host:port
5758 // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
5759 char hostbuf
[MAX_ESCAPED_DOMAIN_NAME
+ 6]; // Max legal domainname as C-string, including terminating NUL
5760 data
= CFArrayGetValueAtIndex(entry
, kmDNSKcName
);
5761 if (CFDataGetLength(data
) >= (int)sizeof(hostbuf
))
5762 { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data
)); continue; }
5763 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)hostbuf
);
5764 hostbuf
[CFDataGetLength(data
)] = '\0';
5766 domainname hostname
;
5769 hptr
= strchr(hostbuf
, ':');
5771 port
.NotAnInteger
= 0;
5778 while(hptr
&& *hptr
!= 0)
5780 if (*hptr
< '0' || *hptr
> '9')
5781 { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr
, val
); val
= 0; break;}
5782 val
= val
* 10 + *hptr
- '0';
5787 port
.NotAnInteger
= p
[0] << 8 | p
[1];
5789 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
5790 hptr
= strchr(hostbuf
, '@');
5795 if (!MakeDomainNameFromDNSNameString(&hostname
, hptr
)) { LogMsg("SetDomainSecrets: bad host name %s", hptr
); continue; }
5797 DomainAuthInfo
*FoundInList
;
5798 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
5799 if (SameDomainName(&FoundInList
->domain
, &domain
)) break;
5801 #if APPLE_OSX_mDNSResponder
5804 // If any client tunnel destination is in this domain, set deletion flag to false
5805 ClientTunnel
*client
;
5806 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
5807 if (FoundInList
== GetAuthInfoForName_internal(m
, &client
->dstname
))
5809 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client
->dstname
.c
);
5810 client
->MarkedForDeletion
= mDNSfalse
;
5814 #endif // APPLE_OSX_mDNSResponder
5816 // Uncomment the line below to view the keys as they're read out of the system keychain
5817 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
5818 //LogInfo("SetDomainSecrets: domain %##s keyname %##s key %s hostname %##s port %d", &domain.c, &keyname.c, stringbuf, hostname.c, (port.b[0] << 8 | port.b[1]));
5819 LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain
.c
, &keyname
.c
, hostname
.c
, (port
.b
[0] << 8 | port
.b
[1]));
5821 // If didn't find desired domain in the list, make a new entry
5823 if (FoundInList
&& FoundInList
->AutoTunnel
&& haveAutoTunnels
== mDNSfalse
) haveAutoTunnels
= mDNStrue
;
5826 ptr
= (DomainAuthInfo
*)mallocL("DomainAuthInfo", sizeof(*ptr
));
5827 if (!ptr
) { LogMsg("SetDomainSecrets: No memory"); continue; }
5830 //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
5832 // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
5833 if (mDNS_SetSecretForDomain(m
, ptr
, &domain
, &keyname
, stringbuf
, &hostname
, &port
, (AutoTunnel
? btmmprefix
: (IsTunnelModeDomain(&domain
) ? dnsprefix
: NULL
))) == mStatus_BadParamErr
)
5835 if (!FoundInList
) mDNSPlatformMemFree(ptr
); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
5839 #if APPLE_OSX_mDNSResponder
5840 if (ptr
->AutoTunnel
) UpdateAutoTunnelDomainStatus(m
, ptr
);
5841 #endif // APPLE_OSX_mDNSResponder
5843 ConvertDomainNameToCString(&domain
, stringbuf
);
5844 CFStringRef cfs
= CFStringCreateWithCString(NULL
, stringbuf
, kCFStringEncodingUTF8
);
5845 if (cfs
) { CFArrayAppendValue(sa
, cfs
); CFRelease(cfs
); }
5849 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, mDNSNULL
, sa
);
5852 #if APPLE_OSX_mDNSResponder
5854 // clean up ClientTunnels
5855 ClientTunnel
**pp
= &m
->TunnelClients
;
5858 if ((*pp
)->MarkedForDeletion
)
5860 ClientTunnel
*cur
= *pp
;
5861 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur
, cur
->dstname
.c
);
5862 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
5863 AutoTunnelSetKeys(cur
, mDNSfalse
);
5865 freeL("ClientTunnel", cur
);
5871 DomainAuthInfo
*info
= m
->AuthInfoList
;
5874 if (info
->AutoTunnel
&& info
->deltime
)
5876 if (info
->AutoTunnelNAT
.clientContext
)
5878 // stop the NAT operation
5879 mDNS_StopNATOperation_internal(m
, &info
->AutoTunnelNAT
);
5880 if (info
->AutoTunnelNAT
.clientCallback
)
5882 // Reset port and cleanup the state
5883 info
->AutoTunnelNAT
.ExternalAddress
= m
->ExternalAddress
;
5884 info
->AutoTunnelNAT
.ExternalPort
= zeroIPPort
;
5885 info
->AutoTunnelNAT
.RequestedPort
= zeroIPPort
;
5886 info
->AutoTunnelNAT
.Lifetime
= 0;
5887 info
->AutoTunnelNAT
.Result
= mStatus_NoError
;
5888 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
5889 AutoTunnelDeleteAuthInfoState(m
, info
);
5890 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
5892 info
->AutoTunnelNAT
.clientContext
= mDNSNULL
;
5894 RemoveAutoTunnelDomainStatus(m
, info
);
5899 if (!haveAutoTunnels
&& !m
->TunnelClients
&& m
->AutoTunnelHostAddrActive
)
5901 // remove interface if no autotunnel servers and no more client tunnels
5902 LogInfo("SetDomainSecrets: Bringing tunnel interface DOWN");
5903 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
5904 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
5905 mDNSPlatformMemZero(m
->AutoTunnelHostAddr
.b
, sizeof(m
->AutoTunnelHostAddr
.b
));
5908 if (m
->AutoTunnelHostAddr
.b
[0])
5909 if (TunnelClients(m
) || TunnelServers(m
))
5910 SetupLocalAutoTunnelInterface_internal(m
, mDNSfalse
);
5912 UpdateAnonymousRacoonConfig(m
); // Determine whether we need racoon to accept incoming connections
5913 UpdateBTMMRelayConnection(m
);
5915 #endif // APPLE_OSX_mDNSResponder
5917 CheckSuppressUnusableQuestions(m
);
5919 #endif /* NO_SECURITYFRAMEWORK */
5922 mDNSlocal
void SetLocalDomains(void)
5924 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
5925 if (!sa
) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
5927 CFArrayAppendValue(sa
, CFSTR("local"));
5928 CFArrayAppendValue(sa
, CFSTR("254.169.in-addr.arpa"));
5929 CFArrayAppendValue(sa
, CFSTR("8.e.f.ip6.arpa"));
5930 CFArrayAppendValue(sa
, CFSTR("9.e.f.ip6.arpa"));
5931 CFArrayAppendValue(sa
, CFSTR("a.e.f.ip6.arpa"));
5932 CFArrayAppendValue(sa
, CFSTR("b.e.f.ip6.arpa"));
5934 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig
, mDNSNULL
, sa
);
5938 mDNSlocal
void GetCurrentPMSetting(const CFStringRef name
, mDNSs32
*val
)
5940 #if USE_IOPMCOPYACTIVEPMPREFERENCES
5941 CFTypeRef blob
= NULL
;
5942 CFStringRef str
= NULL
;
5943 CFDictionaryRef odict
= NULL
;
5944 CFDictionaryRef idict
= NULL
;
5945 CFNumberRef number
= NULL
;
5947 blob
= IOPSCopyPowerSourcesInfo();
5948 if (!blob
) { LogMsg("GetCurrentPMSetting: IOPSCopyPowerSourcesInfo failed!"); goto end
; }
5950 odict
= IOPMCopyActivePMPreferences();
5951 if (!odict
) { LogMsg("GetCurrentPMSetting: IOPMCopyActivePMPreferences failed!"); goto end
; }
5953 str
= IOPSGetProvidingPowerSourceType(blob
);
5954 if (!str
) { LogMsg("GetCurrentPMSetting: IOPSGetProvidingPowerSourceType failed!"); goto end
; }
5956 idict
= CFDictionaryGetValue(odict
, str
);
5960 if (!CFStringGetCString(str
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
5961 LogMsg("GetCurrentPMSetting: CFDictionaryGetValue (%s) failed!", buf
);
5965 number
= CFDictionaryGetValue(idict
, name
);
5966 if (!number
|| CFGetTypeID(number
) != CFNumberGetTypeID() || !CFNumberGetValue(number
, kCFNumberSInt32Type
, val
))
5969 if (blob
) CFRelease(blob
);
5970 if (odict
) CFRelease(odict
);
5974 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetCurrentPMSetting"), NULL
, NULL
);
5975 if (!store
) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5978 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_PowerSettings
);
5979 if (!dict
) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
5982 CFNumberRef number
= CFDictionaryGetValue(dict
, name
);
5983 if (!number
|| CFGetTypeID(number
) != CFNumberGetTypeID() || !CFNumberGetValue(number
, kCFNumberSInt32Type
, val
))
5993 #if APPLE_OSX_mDNSResponder
5995 static CFMutableDictionaryRef spsStatusDict
= NULL
;
5996 static const CFStringRef kMetricRef
= CFSTR("Metric");
5998 mDNSlocal
void SPSStatusPutNumber(CFMutableDictionaryRef dict
, const mDNSu8
* const ptr
, CFStringRef key
)
6000 mDNSu8 tmp
= (ptr
[0] - '0') * 10 + ptr
[1] - '0';
6001 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt8Type
, &tmp
);
6003 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
6006 CFDictionarySetValue(dict
, key
, num
);
6011 mDNSlocal CFMutableDictionaryRef
SPSCreateDict(const mDNSu8
* const ptr
)
6013 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
6014 if (!dict
) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict
; }
6017 buffer
[mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", ptr
) - 1] = 0;
6018 CFStringRef spsname
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
6019 if (!spsname
) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict
); return NULL
; }
6020 CFDictionarySetValue(dict
, CFSTR("FullName"), spsname
);
6023 if (ptr
[0] >= 2) SPSStatusPutNumber(dict
, ptr
+ 1, CFSTR("Type"));
6024 if (ptr
[0] >= 5) SPSStatusPutNumber(dict
, ptr
+ 4, CFSTR("Portability"));
6025 if (ptr
[0] >= 8) SPSStatusPutNumber(dict
, ptr
+ 7, CFSTR("MarginalPower"));
6026 if (ptr
[0] >= 11) SPSStatusPutNumber(dict
, ptr
+10, CFSTR("TotalPower"));
6028 mDNSu32 tmp
= SPSMetric(ptr
);
6029 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tmp
);
6031 LogMsg("SPSCreateDict: Could not create CFNumber");
6034 CFDictionarySetValue(dict
, kMetricRef
, num
);
6040 memcpy(buffer
, ptr
+ 13, ptr
[0] - 12);
6041 buffer
[ptr
[0] - 12] = 0;
6042 spsname
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
6043 if (!spsname
) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict
); return NULL
; }
6046 CFDictionarySetValue(dict
, CFSTR("PrettyName"), spsname
);
6054 mDNSlocal CFComparisonResult
CompareSPSEntries(const void *val1
, const void *val2
, void *context
)
6057 return CFNumberCompare((CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val1
, kMetricRef
),
6058 (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)val2
, kMetricRef
),
6062 mDNSlocal
void UpdateSPSStatus(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
6064 NetworkInterfaceInfo
* info
= (NetworkInterfaceInfo
*)question
->QuestionContext
;
6065 debugf("UpdateSPSStatus: %s %##s %s %s", info
->ifname
, question
->qname
.c
, AddRecord
? "Add" : "Rmv", answer
? RRDisplayString(m
, answer
) : "<null>");
6068 mDNS_UpdateAllowSleep(m
);
6071 if (answer
&& SPSMetric(answer
->rdata
->u
.name
.c
) > 999999) return; // Ignore instances with invalid names
6075 spsStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
6076 if (!spsStatusDict
) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
6079 CFStringRef ifname
= CFStringCreateWithCString(NULL
, info
->ifname
, kCFStringEncodingUTF8
);
6080 if (!ifname
) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
6082 CFMutableArrayRef array
= NULL
;
6084 if (!CFDictionaryGetValueIfPresent(spsStatusDict
, ifname
, (const void**) &array
))
6086 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6087 if (!array
) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname
); return; }
6088 CFDictionarySetValue(spsStatusDict
, ifname
, array
);
6089 CFRelease(array
); // let go of our reference, now that the dict has one
6092 if (!array
) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info
->ifname
); CFRelease(ifname
); return; }
6094 if (!answer
) // special call that means the question has been stopped (because the interface is going away)
6095 CFArrayRemoveAllValues(array
);
6098 CFMutableDictionaryRef dict
= SPSCreateDict(answer
->rdata
->u
.name
.c
);
6099 if (!dict
) { CFRelease(ifname
); return; }
6103 if (!CFArrayContainsValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), dict
))
6106 for (i
=0; i
<CFArrayGetCount(array
); i
++)
6107 if (CompareSPSEntries(CFArrayGetValueAtIndex(array
, i
), dict
, NULL
) != kCFCompareLessThan
)
6109 CFArrayInsertValueAtIndex(array
, i
, dict
);
6111 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info
->ifname
, answer
->rdata
->u
.name
.c
);
6115 CFIndex i
= CFArrayGetFirstIndexOfValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), dict
);
6116 if (i
!= -1) CFArrayRemoveValueAtIndex(array
, i
);
6117 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info
->ifname
, answer
->rdata
->u
.name
.c
);
6123 if (!m
->ShutdownTime
) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState
, info
->ifname
, array
);
6128 mDNSlocal mDNSs32
GetSystemSleepTimerSetting(void)
6131 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL
, NULL
);
6133 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6136 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_PowerSettings
);
6139 CFNumberRef number
= CFDictionaryGetValue(dict
, CFSTR("System Sleep Timer"));
6140 if (number
) CFNumberGetValue(number
, kCFNumberSInt32Type
, &val
);
6148 mDNSlocal
void SetSPS(mDNS
*const m
)
6150 SCPreferencesSynchronize(m
->p
->SCPrefs
);
6151 CFDictionaryRef dict
= SCPreferencesGetValue(m
->p
->SCPrefs
, CFSTR("NAT"));
6152 mDNSBool natenabled
= (dict
&& (CFGetTypeID(dict
) == CFDictionaryGetTypeID()) && DictionaryIsEnabled(dict
));
6153 mDNSu8 sps
= natenabled
? mDNSSleepProxyMetric_PrimarySoftware
:
6154 (OfferSleepProxyService
&& GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware
: 0;
6156 // For devices that are not running NAT, but are set to never sleep, we may choose to act
6157 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
6158 //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
6160 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
6162 // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
6163 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
6164 // We rate such a device as metric 70 ("Incidentally Available Hardware")
6165 if (SPMetricMarginalPower
<= 60 && !sps
) sps
= mDNSSleepProxyMetric_IncidentalHardware
;
6167 // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
6168 // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
6169 if (sps
&& OfferSleepProxyService
&& OfferSleepProxyService
< 100) sps
= OfferSleepProxyService
;
6171 mDNSCoreBeSleepProxyServer(m
, sps
, SPMetricPortability
, SPMetricMarginalPower
, SPMetricTotalPower
);
6174 mDNSlocal
void InternetSharingChanged(SCPreferencesRef prefs
, SCPreferencesNotification notificationType
, void *context
)
6176 (void)prefs
; // Parameter not used
6177 (void)notificationType
; // Parameter not used
6178 mDNS
*const m
= (mDNS
*const)context
;
6182 // Tell platform layer to open or close its BPF fds
6183 if (!m
->p
->NetworkChanged
||
6184 m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2) < 0)
6186 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2);
6187 LogInfo("InternetSharingChanged: Set NetworkChanged to %d (%d)", m
->p
->NetworkChanged
- m
->timenow
, m
->p
->NetworkChanged
);
6191 KQueueUnlock(m
, "InternetSharingChanged");
6194 mDNSlocal mStatus
WatchForInternetSharingChanges(mDNS
*const m
)
6196 SCPreferencesRef SCPrefs
= SCPreferencesCreate(NULL
, CFSTR("mDNSResponder:WatchForInternetSharingChanges"), CFSTR("com.apple.nat.plist"));
6197 if (!SCPrefs
) { LogMsg("SCPreferencesCreate failed: %s", SCErrorString(SCError())); return(mStatus_NoMemoryErr
); }
6199 SCPreferencesContext context
= { 0, m
, NULL
, NULL
, NULL
};
6200 if (!SCPreferencesSetCallback(SCPrefs
, InternetSharingChanged
, &context
))
6201 { LogMsg("SCPreferencesSetCallback failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs
); return(mStatus_NoMemoryErr
); }
6203 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
6204 if (!SCPreferencesSetDispatchQueue( SCPrefs
, dispatch_get_main_queue()))
6205 { LogMsg("SCPreferencesSetDispatchQueue failed: %s", SCErrorString(SCError())); return(mStatus_NoMemoryErr
); }
6207 if (!SCPreferencesScheduleWithRunLoop(SCPrefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
))
6208 { LogMsg("SCPreferencesScheduleWithRunLoop failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs
); return(mStatus_NoMemoryErr
); }
6211 m
->p
->SCPrefs
= SCPrefs
;
6212 return(mStatus_NoError
);
6215 // The definitions below should eventually come from some externally-supplied header file.
6216 // However, since these definitions can't really be changed without breaking binary compatibility,
6217 // they should never change, so in practice it should not be a big problem to have them defined here.
6219 #define mDNS_IOREG_KEY "mDNS_KEY"
6220 #define mDNS_IOREG_VALUE "2009-07-30"
6221 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
6224 { // commands from the daemon to the driver
6225 cmd_mDNSOffloadRR
= 21, // give the mdns update buffer to the driver
6228 typedef union { void *ptr
; mDNSOpaque64 sixtyfourbits
; } FatPtr
;
6231 { // cmd_mDNSOffloadRR structure
6232 uint32_t command
; // set to OffloadRR
6233 uint32_t rrBufferSize
; // number of bytes of RR records
6234 uint32_t numUDPPorts
; // number of SRV UDP ports
6235 uint32_t numTCPPorts
; // number of SRV TCP ports
6236 uint32_t numRRRecords
; // number of RR records
6237 uint32_t compression
; // rrRecords - compression is base for compressed strings
6238 FatPtr rrRecords
; // address of array of pointers to the rr records
6239 FatPtr udpPorts
; // address of udp port list (SRV)
6240 FatPtr tcpPorts
; // address of tcp port list (SRV)
6243 #include <IOKit/IOKitLib.h>
6244 #include <dns_util.h>
6246 mDNSlocal mDNSu16
GetPortArray(mDNS
*const m
, int trans
, mDNSIPPort
*portarray
)
6248 const domainlabel
*const tp
= (trans
== mDNSTransport_UDP
) ? (const domainlabel
*)"\x4_udp" : (const domainlabel
*)"\x4_tcp";
6251 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6252 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& SameDomainLabel(ThirdLabel(rr
->resrec
.name
)->c
, tp
->c
))
6254 if (portarray
) portarray
[count
] = rr
->resrec
.rdata
->u
.srv
.port
;
6258 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
6259 if (trans
== mDNSTransport_UDP
&& TunnelServers(m
))
6261 LogSPS("GetPortArray Back to My Mac at %d", count
);
6262 if (portarray
) portarray
[count
] = IPSECPort
;
6268 #define TfrRecordToNIC(RR) \
6269 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
6271 mDNSlocal mDNSu32
CountProxyRecords(mDNS
*const m
, uint32_t *const numbytes
)
6276 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6277 if (rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
6278 if (TfrRecordToNIC(rr
))
6280 *numbytes
+= DomainNameLength(rr
->resrec
.name
) + 10 + rr
->resrec
.rdestimate
;
6281 LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
6282 count
, DomainNameLength(rr
->resrec
.name
) + 10 + rr
->resrec
.rdestimate
, *numbytes
, ARDisplayString(m
,rr
));
6288 mDNSlocal
void GetProxyRecords(mDNS
*const m
, DNSMessage
*const msg
, uint32_t *const numbytes
, FatPtr
*const records
)
6290 mDNSu8
*p
= msg
->data
;
6291 const mDNSu8
*const limit
= p
+ *numbytes
;
6292 InitializeDNSMessage(&msg
->h
, zeroID
, zeroID
);
6296 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6297 if (rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
6298 if (TfrRecordToNIC(rr
))
6300 records
[count
].sixtyfourbits
= zeroOpaque64
;
6301 records
[count
].ptr
= p
;
6302 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
6303 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the 'unique' bit so PutResourceRecord will set it
6304 p
= PutResourceRecordTTLWithLimit(msg
, p
, &msg
->h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
, limit
);
6305 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear 'unique' bit back to normal state
6306 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
6307 count
, records
[count
].ptr
, p
, p
- (mDNSu8
*)records
[count
].ptr
, p
- msg
->data
, ARDisplayString(m
,rr
));
6310 *numbytes
= p
- msg
->data
;
6313 // If compiling with old headers and libraries (pre 10.5) that don't include IOConnectCallStructMethod
6314 // then we declare a dummy version here so that the code at least compiles
6315 #ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
6316 static kern_return_t
6317 IOConnectCallStructMethod(
6318 mach_port_t connection
, // In
6319 uint32_t selector
, // In
6320 const void *inputStruct
, // In
6321 size_t inputStructCnt
, // In
6322 void *outputStruct
, // Out
6323 size_t *outputStructCnt
) // In/Out
6328 (void)inputStructCnt
;
6330 (void)outputStructCnt
;
6331 LogMsg("Compiled without IOConnectCallStructMethod");
6332 return(KERN_FAILURE
);
6336 mDNSexport mStatus
ActivateLocalProxy(mDNS
*const m
, char *ifname
) // Called with the lock held
6338 mStatus result
= mStatus_UnknownErr
;
6339 io_service_t service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOBSDNameMatching(kIOMasterPortDefault
, 0, ifname
));
6340 if (!service
) { LogMsg("ActivateLocalProxy: No service for interface %s", ifname
); return(mStatus_UnknownErr
); }
6343 IOObjectGetClass(service
, n1
);
6345 kern_return_t kr
= IORegistryEntryGetParentEntry(service
, kIOServicePlane
, &parent
);
6346 if (kr
!= KERN_SUCCESS
) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", ifname
, n1
, kr
);
6349 IOObjectGetClass(parent
, n2
);
6350 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", ifname
, n1
, n2
);
6351 const CFTypeRef ref
= IORegistryEntryCreateCFProperty(parent
, CFSTR(mDNS_IOREG_KEY
), kCFAllocatorDefault
, mDNSNULL
);
6352 if (!ref
) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", ifname
, n1
, n2
);
6355 if (CFGetTypeID(ref
) != CFStringGetTypeID() || !CFEqual(ref
, CFSTR(mDNS_IOREG_VALUE
)))
6356 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
6357 ifname
, n1
, n2
, CFStringGetCStringPtr(ref
, mDNSNULL
), mDNS_IOREG_VALUE
);
6358 else if (!UseInternalSleepProxy
)
6359 LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", ifname
);
6362 io_connect_t conObj
;
6363 kr
= IOServiceOpen(parent
, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE
, &conObj
);
6364 if (kr
!= KERN_SUCCESS
) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", ifname
, n1
, n2
, kr
);
6368 mDNSPlatformMemZero(&cmd
, sizeof(cmd
)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
6369 cmd
.command
= cmd_mDNSOffloadRR
;
6370 cmd
.numUDPPorts
= GetPortArray(m
, mDNSTransport_UDP
, mDNSNULL
);
6371 cmd
.numTCPPorts
= GetPortArray(m
, mDNSTransport_TCP
, mDNSNULL
);
6372 cmd
.numRRRecords
= CountProxyRecords(m
, &cmd
.rrBufferSize
);
6373 cmd
.compression
= sizeof(DNSMessageHeader
);
6375 DNSMessage
*msg
= (DNSMessage
*)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader
) + cmd
.rrBufferSize
);
6376 cmd
.rrRecords
.ptr
= mallocL("mDNSOffloadCmd rrRecords", cmd
.numRRRecords
* sizeof(FatPtr
));
6377 cmd
.udpPorts
.ptr
= mallocL("mDNSOffloadCmd udpPorts", cmd
.numUDPPorts
* sizeof(mDNSIPPort
));
6378 cmd
.tcpPorts
.ptr
= mallocL("mDNSOffloadCmd tcpPorts", cmd
.numTCPPorts
* sizeof(mDNSIPPort
));
6380 LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
6381 msg
, cmd
.rrBufferSize
,
6382 cmd
.rrRecords
.ptr
, cmd
.numRRRecords
,
6383 cmd
.udpPorts
.ptr
, cmd
.numUDPPorts
,
6384 cmd
.tcpPorts
.ptr
, cmd
.numTCPPorts
);
6386 if (!msg
|| !cmd
.rrRecords
.ptr
|| !cmd
.udpPorts
.ptr
|| !cmd
.tcpPorts
.ptr
)
6387 LogMsg("ActivateLocalProxy: Failed to allocate memory: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
6388 msg
, cmd
.rrBufferSize
,
6389 cmd
.rrRecords
.ptr
, cmd
.numRRRecords
,
6390 cmd
.udpPorts
.ptr
, cmd
.numUDPPorts
,
6391 cmd
.tcpPorts
.ptr
, cmd
.numTCPPorts
);
6394 GetProxyRecords(m
, msg
, &cmd
.rrBufferSize
, cmd
.rrRecords
.ptr
);
6395 GetPortArray(m
, mDNSTransport_UDP
, cmd
.udpPorts
.ptr
);
6396 GetPortArray(m
, mDNSTransport_TCP
, cmd
.tcpPorts
.ptr
);
6398 size_t outputDataSize
= sizeof(outputData
);
6399 kr
= IOConnectCallStructMethod(conObj
, 0, &cmd
, sizeof(cmd
), outputData
, &outputDataSize
);
6400 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", ifname
, n1
, n2
, kr
);
6401 if (kr
== KERN_SUCCESS
) result
= mStatus_NoError
;
6404 if (cmd
.tcpPorts
. ptr
) freeL("mDNSOffloadCmd udpPorts", cmd
.tcpPorts
.ptr
);
6405 if (cmd
.udpPorts
. ptr
) freeL("mDNSOffloadCmd tcpPorts", cmd
.udpPorts
.ptr
);
6406 if (cmd
.rrRecords
.ptr
) freeL("mDNSOffloadCmd rrRecords", cmd
.rrRecords
.ptr
);
6407 if (msg
) freeL("mDNSOffloadCmd msg", msg
);
6408 IOServiceClose(conObj
);
6413 IOObjectRelease(parent
);
6415 IOObjectRelease(service
);
6419 #endif // APPLE_OSX_mDNSResponder
6421 static io_service_t g_rootdomain
= MACH_PORT_NULL
;
6423 mDNSlocal mDNSBool
SystemWakeForNetworkAccess(void)
6426 CFBooleanRef clamshellStop
= NULL
;
6427 mDNSBool retnow
= mDNSfalse
;
6429 if (DisableSleepProxyClient
) { LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option"); return mDNSfalse
; }
6431 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val
);
6432 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", val
);
6433 if (!val
) return mDNSfalse
;
6435 if (!g_rootdomain
) g_rootdomain
= IORegistryEntryFromPath(MACH_PORT_NULL
, kIOPowerPlane
":/IOPowerConnection/IOPMrootDomain");
6436 if (!g_rootdomain
) { LogMsg("SystemWakeForNetworkAccess: IORegistryEntryFromPath failed; assuming no clamshell so can WOMP"); return mDNStrue
; }
6438 clamshellStop
= (CFBooleanRef
)IORegistryEntryCreateCFProperty(g_rootdomain
, CFSTR(kAppleClamshellStateKey
), kCFAllocatorDefault
, 0);
6439 if (!clamshellStop
) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue
; }
6440 retnow
= clamshellStop
== kCFBooleanFalse
;
6441 CFRelease(clamshellStop
);
6442 if (retnow
) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey is false; clamshell is open so can WOMP"); return mDNStrue
; }
6444 clamshellStop
= (CFBooleanRef
)IORegistryEntryCreateCFProperty(g_rootdomain
, CFSTR(kAppleClamshellCausesSleepKey
), kCFAllocatorDefault
, 0);
6445 if (!clamshellStop
) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue
; }
6446 retnow
= (clamshellStop
== kCFBooleanFalse
);
6447 CFRelease(clamshellStop
);
6448 if (retnow
) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey is false; clamshell is closed but can WOMP"); return mDNStrue
; }
6450 LogSPS("SystemWakeForNetworkAccess: clamshell is closed and can't WOMP");
6454 mDNSlocal mDNSBool
SystemSleepOnlyIfWakeOnLAN(void)
6457 GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val
);
6458 return val
!= 0 ? mDNStrue
: mDNSfalse
;
6461 #if APPLE_OSX_mDNSResponder
6462 // If the _autotunnel6 record is still there in the list, we are waiting for the ack from
6465 // If we are behind a double-NAT or NAT with no NAT-PMP support, we should make sure that all our
6466 // BTMM records are deregistered so that it does not appear on the Finder sidebar of our peers
6467 // when we go to sleep. First _autotunnel6 and the host record gets deregistered, then SRV
6468 // (UpdateAllSrvRecords) and then PTR and TXT
6470 // Note: We wait up to a maximum of 10 seconds before we ack the sleep. So, returning "false"
6471 // here does not necessarily mean that it will be honored.
6472 mDNSexport mDNSBool
RecordReadyForSleep(mDNS
*const m
, AuthRecord
*rr
)
6474 if (!AuthRecord_uDNS(rr
)) return mDNStrue
;
6476 if (SameDomainLabel(rr
->namestorage
.c
, (const mDNSu8
*)"\x0c_autotunnel6"))
6478 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m
, rr
));
6481 // Just check for the SRV record alone as the PTR and TXT records are dependent on SRV
6482 // and will get deregistered together in a single update. We also don't check for TXT
6483 // records as _kerberos TXT record is always there even when there are no services
6484 // and we don't want to delay the sleep in that case.
6485 if (mDNSIPPortIsZero(m
->LLQNAT
.ExternalPort
) || m
->LLQNAT
.Result
)
6487 if ((rr
->resrec
.rrtype
== kDNSType_SRV
) && rr
->state
!= regState_NoTarget
&& rr
->zone
)
6489 DomainAuthInfo
*info
= GetAuthInfoForName_internal(m
, rr
->zone
);
6490 if (info
&& info
->AutoTunnel
)
6492 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m
, rr
));
6500 // Note: BTMMDict needs to be retained by the caller if needed
6501 mDNSlocal CFDictionaryRef
ParseBackToMyMacKey(CFDictionaryRef connd
)
6503 CFDictionaryRef BTMMDict
= CFDictionaryGetValue(connd
, CFSTR("BackToMyMac"));
6506 LogInfo("ParseBackToMyMacKey: CFDictionaryGetValue No value for BackToMyMac");
6510 // Non-dictionary is treated as non-existent dictionary
6511 if (CFGetTypeID(BTMMDict
) != CFDictionaryGetTypeID())
6512 {LogMsg("ERROR: ParseBackToMyMacKey: CFDictionaryGetValue BackToMyMac not a dictionary"); CFRelease(BTMMDict
); return NULL
;}
6517 mDNSlocal
void ParseBTMMInterfaceKey(CFDictionaryRef BTMMDict
, char *buf
, int buflen
)
6522 ifExists
= CFDictionaryGetValueIfPresent(BTMMDict
, CFSTR("Interface"), &string
);
6525 if (!CFStringGetCString(string
, buf
, buflen
, kCFStringEncodingUTF8
))
6527 LogMsg("ERROR: ParseBTMMInterfaceKey: Could not convert Interface to CString");
6528 if (buflen
) buf
[0] = 0;
6532 debugf("ParseBTMMInterfaceKey: Interface Key exists %s", buf
);
6536 if (buflen
) buf
[0] = 0;
6537 debugf("ParseBTMMInterfaceKey: Interface Key does not exist");
6541 mDNSexport
void RemoveAutoTunnel6Record(mDNS
*const m
)
6543 DomainAuthInfo
*info
;
6546 // Did we parse a non-empty dictionary before ?
6547 if (!m
->p
->ConndBTMMDict
|| (CFDictionaryGetCount(m
->p
->ConndBTMMDict
) == 0))
6549 LogInfo("RemoveAutoTunnel6Record: Never registered any records before, not deregistering %p", m
->p
->ConndBTMMDict
);
6553 // Did we have a non-NULL Interface name before ?
6554 ParseBTMMInterfaceKey(m
->p
->ConndBTMMDict
, buf
, sizeof(buf
));
6557 LogInfo("RemoveAutoTunnel6Record: Interface name already NULL, not deregistering");
6561 // Set the address to zero before calling DeregisterAutoTunnel6Record. If we call
6562 // Deregister too quickly before the previous Register completed (just scheduled
6563 // to be sent out) and when DeregisterAutoTunnel6Record calls mDNS_Register_internal,
6564 // it invokes the AutoTunnelRecordCallback immediately and AutoTunnelRelayAddrIn should
6565 // be zero so that we don't register again.
6566 m
->AutoTunnelRelayAddrIn
= zerov6Addr
;
6567 if (!m
->AuthInfoList
) LogInfo("RemoveAutoTunnel6Record: No Domain AuthInfo");
6568 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
6570 if (!info
->AutoTunnel
) { LogInfo("RemoveAutoTunnel6Record: Domain %##s not an AutoTunnel", info
->domain
.c
); continue;}
6572 if (info
->deltime
) {LogInfo("RemoveAutoTunnel6Record: Domain %##s about to be deleted", info
->domain
.c
); continue;}
6574 LogInfo("RemoveAutoTunnel6Record: Deregistering records for domain %##s", info
->domain
.c
);
6575 DeregisterAutoTunnel6Record(m
, info
);
6577 CFRelease(m
->p
->ConndBTMMDict
);
6578 m
->p
->ConndBTMMDict
= NULL
;
6581 // Returns zero on success
6582 mDNSlocal
int GetIPv6AddressForIfname(char *ifname
, mDNSv6Addr
*ipv6Addr
)
6584 struct ifaddrs
*ifa
;
6585 struct ifaddrs
*ifaddrs
;
6588 if (if_nametoindex(ifname
) == 0) {LogInfo("GetIPv6AddressForIfname: Invalid name %s", ifname
); return (-1);}
6590 if (getifaddrs(&ifaddrs
) < 0) {LogInfo("GetIPv6AddressForIfname: getifaddrs failed"); return (-1);}
6593 * Find the ifaddr entry corresponding to the interface name,
6594 * and return the first matching non-linklocal IPv6 address.
6596 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
6598 if (strncmp(ifa
->ifa_name
, ifname
, IFNAMSIZ
) != 0)
6600 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
&& ifa
->ifa_addr
->sa_family
== AF_INET6
)
6602 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
6603 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
))
6605 if (SetupAddr(&addr
, ifa
->ifa_addr
) != mStatus_NoError
)
6607 LogInfo("GetIPv6AddressForIfname: SetupAddr error, continuing to the next address");
6612 *ipv6Addr
= *(mDNSv6Addr
*)&addr
.ip
.v6
;
6613 LogInfo("GetIPv6AddressForIfname: Returning IPv6 address %.16a", ipv6Addr
);
6614 freeifaddrs(ifaddrs
);
6619 LogInfo("GetIPv6AddressForIfname: No Valid IPv6 address");
6620 freeifaddrs(ifaddrs
);
6624 mDNSlocal
void AddAutoTunnel6Record(mDNS
*const m
, char *ifname
, CFDictionaryRef BTMMDict
)
6627 DomainAuthInfo
*info
;
6629 if (GetIPv6AddressForIfname(ifname
, &v6addr
) != 0)
6631 LogInfo("AddAutoTunnel6Record: No Valid IPv6 addresses found for %s", ifname
);
6632 // If the interface does not exist but the dictionary has the value, we treat
6633 // this case as though the dictionary does not have the value
6634 RemoveAutoTunnel6Record(m
);
6635 // If awacsd crashes or exits for some reason, restart the relay connection
6636 UpdateBTMMRelayConnection(m
);
6640 m
->AutoTunnelRelayAddrOut
= v6addr
;
6642 // if disabled administratively, don't bother to register. RegisterAutoTunnel6Record makes these same
6643 // checks, but we do it here not just as an optimization but mainly to keep AutoTunnelRelayAddrIn zero
6644 // as a non-zero AutoTunnelRelayAddrIn indicates that we have registered _autotunnel6 record and hence
6645 // other hosts can connect to this host through the relay
6646 if (!m
->RegisterAutoTunnel6
|| DisableInboundRelayConnection
)
6648 LogInfo("RegisterAutoTunnel6Record: registration Disabled RegisterAutoTunnel6 %d, DisableInbound %d",
6649 m
->RegisterAutoTunnel6
, DisableInboundRelayConnection
);
6652 m
->AutoTunnelRelayAddrIn
= v6addr
;
6654 if (!m
->AuthInfoList
) LogInfo("AddAutoTunnel6Record: No Domain AuthInfo");
6655 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
6657 // clientContext for a domain tells us that we are listening for at least one Service/Record
6658 // in a domain and SetLocalAutoTunnelInterface_internal was called
6659 if (!info
->AutoTunnel
) { LogInfo("AddAutoTunnel6Record: Domain %##s not an AutoTunnel", info
->domain
.c
); continue;}
6661 if (!info
->AutoTunnelNAT
.clientContext
) {LogInfo("AddAutoTunnel6Record: Domain %##s has no services", info
->domain
.c
); continue;}
6663 if (info
->deltime
) {LogInfo("AddAutoTunnel6Record: Domain %##s about to be deleted", info
->domain
.c
); continue;}
6665 LogInfo("AddAutoTunnel6Record: Registering records for domain %##s", info
->domain
.c
);
6667 RegisterAutoTunnel6Record(m
, info
);
6670 if (m
->p
->ConndBTMMDict
) CFRelease(m
->p
->ConndBTMMDict
);
6671 m
->p
->ConndBTMMDict
= CFRetain(BTMMDict
);
6674 mDNSlocal
void ParseBackToMyMac(mDNS
*const m
, CFDictionaryRef connd
)
6676 CFDictionaryRef BTMMDict
;
6679 BTMMDict
= ParseBackToMyMacKey(connd
);
6682 LogInfo("ParseBackToMyMac: CFDictionaryGetValue No value for BackToMyMac, Removing autotunnel6");
6683 RemoveAutoTunnel6Record(m
);
6684 // Note: AutoTunnelRelayAddrIn is zeroed out in RemoveAutoTunnel6Record as it is called
6685 // from other places.
6686 m
->AutoTunnelRelayAddrOut
= zerov6Addr
;
6688 UpdateAutoTunnelDomainStatuses(m
);
6693 ParseBTMMInterfaceKey(BTMMDict
, buf
, sizeof(buf
));
6696 LogInfo("ParseBackToMyMac: NULL value for Interface, Removing autotunnel6");
6697 RemoveAutoTunnel6Record(m
);
6698 m
->AutoTunnelRelayAddrOut
= zerov6Addr
;
6699 // We don't have a utun interface, start the relay connection if possible
6700 UpdateBTMMRelayConnection(m
);
6704 LogInfo("ParseBackToMyMac: non-NULL value for Interface, Adding autotunnel6");
6705 AddAutoTunnel6Record(m
, buf
, BTMMDict
);
6709 UpdateAutoTunnelDomainStatuses(m
);
6713 mDNSlocal
void SetupConndConfigChanges(mDNS
*const m
)
6715 CFDictionaryRef connd
;
6716 SCDynamicStoreRef store
;
6718 store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:SetupConndConfigChanges"), NULL
, NULL
);
6719 if (!store
) {LogMsg("SetupConndConfigChanges: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); return;}
6721 connd
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BTMMConnectivity
);
6723 {LogInfo("SetupConndConfigChanges: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError())); CFRelease(store
); return;}
6726 ParseBackToMyMac(m
, connd
);
6731 #endif /* APPLE_OSX_mDNSResponder */
6734 mDNSexport
void mDNSMacOSXNetworkChanged(mDNS
*const m
)
6736 LogInfo("*** Network Configuration Change *** (%d)%s",
6737 m
->p
->NetworkChanged
? mDNS_TimeNow(m
) - m
->p
->NetworkChanged
: 0,
6738 m
->p
->NetworkChanged
? "" : " (no scheduled configuration change)");
6739 m
->p
->NetworkChanged
= 0; // If we received a network change event and deferred processing, we're now dealing with it
6740 mDNSs32 utc
= mDNSPlatformUTC();
6741 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
6742 m
->SystemSleepOnlyIfWakeOnLAN
= SystemSleepOnlyIfWakeOnLAN();
6743 MarkAllInterfacesInactive(m
, utc
);
6744 UpdateInterfaceList(m
, utc
);
6745 ClearInactiveInterfaces(m
, utc
);
6746 SetupActiveInterfaces(m
, utc
);
6748 #if APPLE_OSX_mDNSResponder
6750 SetupConndConfigChanges(m
);
6752 if (m
->AutoTunnelHostAddr
.b
[0])
6755 if (TunnelClients(m
) || TunnelServers(m
))
6756 SetupLocalAutoTunnelInterface_internal(m
, mDNSfalse
);
6760 // Scan to find client tunnels whose questions have completed,
6761 // but whose local inner/outer addresses have changed since the tunnel was set up
6763 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
6764 if (p
->q
.ThisQInterval
< 0)
6766 if (!mDNSIPPortIsZero(p
->rmt_outer_port
))
6768 mDNSAddr tmpSrc
= zeroAddr
;
6769 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
6770 tmpDst
.ip
.v4
= p
->rmt_outer
;
6771 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
6772 if (!mDNSSameIPv6Address(p
->loc_inner
, m
->AutoTunnelHostAddr
) ||
6773 !mDNSSameIPv4Address(p
->loc_outer
, tmpSrc
.ip
.v4
))
6775 AutoTunnelSetKeys(p
, mDNSfalse
);
6776 p
->loc_inner
= m
->AutoTunnelHostAddr
;
6777 p
->loc_outer
= tmpSrc
.ip
.v4
;
6778 AutoTunnelSetKeys(p
, mDNStrue
);
6783 if (!mDNSSameIPv6Address(p
->loc_inner
, m
->AutoTunnelHostAddr
) ||
6784 !mDNSSameIPv6Address(p
->loc_outer6
, m
->AutoTunnelRelayAddrOut
))
6786 AutoTunnelSetKeys(p
, mDNSfalse
);
6787 p
->loc_inner
= m
->AutoTunnelHostAddr
;
6788 p
->loc_outer6
= m
->AutoTunnelRelayAddrOut
;
6789 AutoTunnelSetKeys(p
, mDNStrue
);
6797 NetworkInterfaceInfoOSX
*i
;
6798 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
6800 if (!m
->SPSSocket
) // Not being Sleep Proxy Server; close any open BPF fds
6802 if (i
->BPF_fd
>= 0 && CountProxyTargets(m
, i
, mDNSNULL
, mDNSNULL
) == 0) CloseBPF(i
);
6804 else // else, we're Sleep Proxy Server; open BPF fds
6806 if (i
->Exists
&& i
->Registered
== i
&& i
->ifinfo
.McastTxRx
&& !(i
->ifa_flags
& IFF_LOOPBACK
) && i
->BPF_fd
== -1)
6807 { LogSPS("%s requesting BPF", i
->ifinfo
.ifname
); i
->BPF_fd
= -2; mDNSRequestBPF(); }
6811 #endif // APPLE_OSX_mDNSResponder
6813 uDNS_SetupDNSConfig(m
);
6814 mDNS_ConfigChanged(m
);
6817 // Called with KQueueLock & mDNS lock
6818 mDNSlocal
void SetNetworkChanged(mDNS
*const m
, mDNSs32 delay
)
6820 if (!m
->p
->NetworkChanged
|| m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) < 0)
6822 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
6823 LogInfo("SetNetworkChanged: setting network changed to %d (%d)", delay
, m
->p
->NetworkChanged
);
6827 // Called with KQueueLock & mDNS lock
6828 mDNSlocal
void SetKeyChainTimer(mDNS
*const m
, mDNSs32 delay
)
6830 // If it's not set or it needs to happen sooner than when it's currently set
6831 if (!m
->p
->KeyChainTimer
|| m
->p
->KeyChainTimer
- NonZeroTime(m
->timenow
+ delay
) > 0)
6833 m
->p
->KeyChainTimer
= NonZeroTime(m
->timenow
+ delay
);
6834 LogInfo("SetKeyChainTimer: %d", delay
);
6838 // Copy the fourth slash-delimited element from either:
6839 // State:/Network/Interface/<bsdname>/IPv4
6841 // Setup:/Network/Service/<servicename>/Interface
6842 mDNSlocal CFStringRef
CopyNameFromKey(CFStringRef key
)
6845 CFStringRef name
= NULL
;
6847 a
= CFStringCreateArrayBySeparatingStrings(NULL
, key
, CFSTR("/"));
6848 if (a
&& CFArrayGetCount(a
) == 5) name
= CFRetain(CFArrayGetValueAtIndex(a
, 3));
6849 if (a
!= NULL
) CFRelease(a
);
6854 // Whether a key from a network change notification corresponds to
6855 // an IP service that is explicitly configured for IPv4 Link Local
6856 mDNSlocal mDNSBool
ChangedKeysHaveIPv4LL(CFArrayRef inkeys
)
6858 SCDynamicStoreRef store
= NULL
;
6859 CFDictionaryRef dict
= NULL
;
6860 CFMutableArrayRef a
;
6861 const void **keys
= NULL
, **vals
= NULL
;
6862 CFStringRef pattern
= NULL
;
6864 mDNSBool found
= mDNSfalse
;
6866 jc
= CFArrayGetCount(inkeys
);
6869 store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:ChangedKeysHaveIPv4LL"), NULL
, NULL
);
6870 if (store
== NULL
) goto done
;
6872 a
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
6873 if (a
== NULL
) goto done
;
6875 // Setup:/Network/Service/[^/]+/Interface
6876 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetInterface
);
6877 if (pattern
== NULL
) goto done
;
6878 CFArrayAppendValue(a
, pattern
);
6881 // Setup:/Network/Service/[^/]+/IPv4
6882 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCCompAnyRegex
, kSCEntNetIPv4
);
6883 if (pattern
== NULL
) goto done
;
6884 CFArrayAppendValue(a
, pattern
);
6887 dict
= SCDynamicStoreCopyMultiple(store
, NULL
, a
);
6892 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
6896 ic
= CFDictionaryGetCount(dict
);
6897 vals
= mDNSPlatformMemAllocate(sizeof (void *) * ic
);
6898 keys
= mDNSPlatformMemAllocate(sizeof (void *) * ic
);
6899 CFDictionaryGetKeysAndValues(dict
, keys
, vals
);
6901 for (j
= 0; j
< jc
&& !found
; j
++)
6903 CFStringRef key
= CFArrayGetValueAtIndex(inkeys
, j
);
6904 CFStringRef ifname
= NULL
;
6908 // It would be nice to use a regex here
6909 if (!CFStringHasPrefix(key
, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key
, kSCEntNetIPv4
)) continue;
6911 if ((ifname
= CopyNameFromKey(key
)) == NULL
) continue;
6912 if (mDNS_LoggingEnabled
)
6914 if (!CFStringGetCString(ifname
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
6915 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf
);
6918 for (i
= 0; i
< ic
; i
++)
6920 CFDictionaryRef ipv4dict
;
6922 CFStringRef serviceid
;
6923 CFStringRef configmethod
;
6925 if (!CFStringHasSuffix(keys
[i
], kSCEntNetInterface
)) continue;
6927 if (CFDictionaryGetTypeID() != CFGetTypeID(vals
[i
])) continue;
6929 if ((name
= CFDictionaryGetValue(vals
[i
], kSCPropNetInterfaceDeviceName
)) == NULL
) continue;
6931 if (!CFEqual(ifname
, name
)) continue;
6933 if ((serviceid
= CopyNameFromKey(keys
[i
])) == NULL
) continue;
6934 if (mDNS_LoggingEnabled
)
6936 if (!CFStringGetCString(serviceid
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
6937 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf
);
6940 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceid
, kSCEntNetIPv4
);
6941 CFRelease(serviceid
);
6942 if (pattern
== NULL
) continue;
6944 ipv4dict
= CFDictionaryGetValue(dict
, pattern
);
6946 if (!ipv4dict
|| CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict
)) continue;
6948 configmethod
= CFDictionaryGetValue(ipv4dict
, kSCPropNetIPv4ConfigMethod
);
6949 if (!configmethod
) continue;
6951 if (mDNS_LoggingEnabled
)
6953 if (!CFStringGetCString(configmethod
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
6954 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf
);
6957 if (CFEqual(configmethod
, kSCValNetIPv4ConfigMethodLinkLocal
)) { found
= mDNStrue
; break; }
6964 if (vals
!= NULL
) mDNSPlatformMemFree(vals
);
6965 if (keys
!= NULL
) mDNSPlatformMemFree(keys
);
6966 if (dict
!= NULL
) CFRelease(dict
);
6967 if (store
!= NULL
) CFRelease(store
);
6972 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
6974 (void)store
; // Parameter not used
6975 mDNSBool changeNow
= mDNSfalse
;
6976 mDNS
*const m
= (mDNS
*const)context
;
6980 mDNSs32 delay
= mDNSPlatformOneSecond
* 2; // Start off assuming a two-second delay
6982 int c
= CFArrayGetCount(changedKeys
); // Count changes
6983 CFRange range
= { 0, c
};
6984 int c1
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Hostnames
) != 0);
6985 int c2
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Computername
) != 0);
6986 int c3
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DynamicDNS
) != 0);
6987 int c4
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DNS
) != 0);
6988 if (c
&& c
- c1
- c2
- c3
- c4
== 0) delay
= mDNSPlatformOneSecond
/10; // If these were the only changes, shorten delay
6995 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys
, i
), buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
6998 if (strstr(buf
, "p2p"))
7000 LogInfo("NetworkChanged SC key: %s, not delaying network change", buf
);
7001 changeNow
= mDNStrue
;
7008 if (mDNS_LoggingEnabled
)
7014 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys
, i
), buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7015 LogInfo("*** NetworkChanged SC key: %s", buf
);
7017 LogInfo("*** NetworkChanged *** %d change%s %s%s%s%sdelay %d",
7019 c1
? "(Local Hostname) " : "",
7020 c2
? "(Computer Name) " : "",
7021 c3
? "(DynamicDNS) " : "",
7026 mDNSBool btmmChanged
= CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_BackToMyMac
);
7027 if (btmmChanged
) delay
= 0;
7029 SetNetworkChanged(m
, delay
);
7031 // Other software might pick up these changes to register or browse in WAB or BTMM domains,
7032 // so in order for secure updates to be made to the server, make sure to read the keychain and
7033 // setup the DomainAuthInfo before handing the network change.
7034 // If we don't, then we will first try to register services in the clear, then later setup the
7035 // DomainAuthInfo, which is incorrect.
7036 if (c3
|| btmmChanged
)
7037 SetKeyChainTimer(m
, delay
);
7041 // If DNS settings changed, immediately force a reconfig (esp. cache flush)
7042 // Similarly, if an interface changed that is explicitly IPv4 link local, immediately force a reconfig
7043 if (c4
|| ChangedKeysHaveIPv4LL(changedKeys
) || changeNow
) mDNSMacOSXNetworkChanged(m
);
7045 KQueueUnlock(m
, "NetworkChanged");
7048 #if APPLE_OSX_mDNSResponder
7049 mDNSlocal
void RefreshSPSStatus(const void *key
, const void *value
, void *context
)
7054 CFStringRef ifnameStr
= (CFStringRef
)key
;
7055 CFArrayRef array
= (CFArrayRef
)value
;
7056 if (!CFStringGetCString(ifnameStr
, buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
7058 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf
, CFArrayGetCount(array
));
7059 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState
, buf
, value
);
7063 mDNSlocal
void DynamicStoreReconnected(SCDynamicStoreRef store
, void *info
)
7065 mDNS
*const m
= (mDNS
*const)info
;
7068 LogInfo("DynamicStoreReconnected: Reconnected");
7070 // State:/Network/MulticastDNS
7073 // State:/Network/DynamicDNS
7075 mDNSPlatformDynDNSHostNameStatusChanged(&m
->FQDN
, 1);
7077 // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
7078 // as we receive network change notifications and thus not necessary. But we leave it here
7079 // so that if things are done differently in the future, this code still works.
7081 // State:/Network/PrivateDNS
7082 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
7084 LogMsg("DynamicStoreReconnected:PrivateDNS: CFArrayCreateMutable failed");
7087 DomainAuthInfo
*FoundInList
;
7088 char stringbuf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal domainname as C-string, including terminating NUL
7089 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
7091 ConvertDomainNameToCString(&FoundInList
->domain
, stringbuf
);
7092 CFStringRef cfs
= CFStringCreateWithCString(NULL
, stringbuf
, kCFStringEncodingUTF8
);
7093 if (cfs
) { CFArrayAppendValue(sa
, cfs
); CFRelease(cfs
); }
7095 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, mDNSNULL
, sa
);
7099 // State:/Network/BackToMyMac
7100 #if APPLE_OSX_mDNSResponder
7102 UpdateAutoTunnelDomainStatuses(m
);
7105 // State:/Network/Interface/en0/SleepProxyServers
7106 if (spsStatusDict
) CFDictionaryApplyFunction(spsStatusDict
, RefreshSPSStatus
, NULL
);
7110 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
7113 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
7114 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
7115 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
7116 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
7117 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
7118 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
7120 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
7121 if (!keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
7123 CFArrayAppendValue(keys
, NetworkChangedKey_IPv4
);
7124 CFArrayAppendValue(keys
, NetworkChangedKey_IPv6
);
7125 CFArrayAppendValue(keys
, NetworkChangedKey_Hostnames
);
7126 CFArrayAppendValue(keys
, NetworkChangedKey_Computername
);
7127 CFArrayAppendValue(keys
, NetworkChangedKey_DNS
);
7128 CFArrayAppendValue(keys
, NetworkChangedKey_DynamicDNS
);
7129 CFArrayAppendValue(keys
, NetworkChangedKey_BackToMyMac
);
7130 CFArrayAppendValue(keys
, NetworkChangedKey_PowerSettings
); // should remove as part of <rdar://problem/6751656>
7131 CFArrayAppendValue(keys
, NetworkChangedKey_BTMMConnectivity
);
7132 CFArrayAppendValue(patterns
, pattern1
);
7133 CFArrayAppendValue(patterns
, pattern2
);
7134 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
7135 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
7136 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
7138 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
7139 if (!SCDynamicStoreSetDispatchQueue(store
, dispatch_get_main_queue()))
7140 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
7142 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
7143 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
7144 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
7146 SCDynamicStoreSetDisconnectCallBack(store
, DynamicStoreReconnected
);
7147 m
->p
->Store
= store
;
7152 if (store
) CFRelease(store
);
7155 if (patterns
) CFRelease(patterns
);
7156 if (pattern2
) CFRelease(pattern2
);
7157 if (pattern1
) CFRelease(pattern1
);
7158 if (keys
) CFRelease(keys
);
7163 #if 0 // <rdar://problem/6751656>
7164 mDNSlocal
void PMChanged(void *context
)
7166 mDNS
*const m
= (mDNS
*const)context
;
7171 LogSPS("PMChanged");
7173 SetNetworkChanged(m
, mDNSPlatformOneSecond
* 2);
7176 KQueueUnlock(m
, "PMChanged");
7179 mDNSlocal mStatus
WatchForPMChanges(mDNS
*const m
)
7181 m
->p
->PMRLS
= IOPMPrefsNotificationCreateRunLoopSource(PMChanged
, m
);
7182 if (!m
->p
->PMRLS
) { LogMsg("IOPMPrefsNotificationCreateRunLoopSource failed!"); return mStatus_UnknownErr
; }
7184 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PMRLS
, kCFRunLoopDefaultMode
);
7186 return mStatus_NoError
;
7190 #ifndef KEV_DL_WAKEFLAGS_CHANGED
7191 #define KEV_DL_WAKEFLAGS_CHANGED 17
7194 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
7196 mDNSlocal
void mDNSSetPacketFilterRules(mDNS
*const m
, char * ifname
)
7201 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
7203 if ((rr
->resrec
.rrtype
== kDNSServiceType_SRV
) && (rr
->ARType
== AuthRecordAnyIncludeP2P
))
7205 uint16_t port
= rr
->resrec
.rdata
->u
.srv
.port
.NotAnInteger
;
7209 LogInfo("mDNSSetPacketFilterRules: found %s", ARDisplayString(m
, rr
));
7211 // Note presence of more than one p2p service in list
7212 // since code is currently opening only one port in the packet filter.
7216 LogMsg("mDNSSetPacketFilterRules: found service #%d %s", found
, ARDisplayString(m
, rr
));
7219 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
7220 p
= rr
->resrec
.name
->c
;
7222 // Skip to App Protocol
7223 if (p
[0]) p
+= 1 + p
[0];
7224 // Skip to Transport Protocol
7225 if (p
[0]) p
+= 1 + p
[0];
7227 if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_tcp")) protocol
= IPPROTO_TCP
;
7228 else if (SameDomainLabel(p
, (mDNSu8
*)"\x4" "_udp")) protocol
= IPPROTO_UDP
;
7231 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
7232 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m
, rr
));
7236 LogInfo("mDNSSetPacketFilterRules: ifname %s, port(in NBO)0x%X, protocol %d",
7237 ifname
, port
, protocol
);
7238 mDNSPacketFilterControl(PF_SET_RULES
, ifname
, port
, protocol
);
7242 #endif // !TARGET_OS_EMBEDDED
7245 #if APPLE_OSX_mDNSResponder
7247 #if !TARGET_OS_EMBEDDED
7248 // If the p2p interface already exists, set the Bonjour packet filter rules for it.
7249 mDNSexport
void mDNSInitPacketFilter(void)
7251 mDNS
*const m
= & mDNSStorage
;
7253 NetworkInterfaceInfo
*intf
= GetFirstActiveInterface(m
->HostInterfaces
);
7256 if (strncmp(intf
->ifname
, "p2p", 3) == 0)
7258 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf
->ifname
);
7259 mDNSSetPacketFilterRules(m
, intf
->ifname
);
7262 intf
= GetFirstActiveInterface(intf
->next
);
7266 #else // !TARGET_OS_EMBEDDED
7268 // Currently no packet filter setup required embedded on platforms.
7269 mDNSexport
void mDNSInitPacketFilter()
7273 #endif // !TARGET_OS_EMBEDDED
7274 #endif // APPLE_OSX_mDNSResponder
7276 mDNSlocal
void SysEventCallBack(int s1
, short __unused filter
, void *context
)
7278 mDNS
*const m
= (mDNS
*const)context
;
7282 struct { struct kern_event_msg k
; char extra
[256]; } msg
;
7283 int bytes
= recv(s1
, &msg
, sizeof(msg
), 0);
7285 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes
, errno
, strerror(errno
));
7288 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
7289 bytes
, msg
.k
.total_size
,
7290 msg
.k
.vendor_code
, msg
.k
.vendor_code
== KEV_VENDOR_APPLE
? "KEV_VENDOR_APPLE" : "?",
7291 msg
.k
.kev_class
, msg
.k
.kev_class
== KEV_NETWORK_CLASS
? "KEV_NETWORK_CLASS" : "?",
7292 msg
.k
.kev_subclass
, msg
.k
.kev_subclass
== KEV_DL_SUBCLASS
? "KEV_DL_SUBCLASS" : "?",
7293 msg
.k
.id
, msg
.k
.event_code
,
7294 msg
.k
.event_code
== KEV_DL_SIFFLAGS
? "KEV_DL_SIFFLAGS" :
7295 msg
.k
.event_code
== KEV_DL_SIFMETRICS
? "KEV_DL_SIFMETRICS" :
7296 msg
.k
.event_code
== KEV_DL_SIFMTU
? "KEV_DL_SIFMTU" :
7297 msg
.k
.event_code
== KEV_DL_SIFPHYS
? "KEV_DL_SIFPHYS" :
7298 msg
.k
.event_code
== KEV_DL_SIFMEDIA
? "KEV_DL_SIFMEDIA" :
7299 msg
.k
.event_code
== KEV_DL_SIFGENERIC
? "KEV_DL_SIFGENERIC" :
7300 msg
.k
.event_code
== KEV_DL_ADDMULTI
? "KEV_DL_ADDMULTI" :
7301 msg
.k
.event_code
== KEV_DL_DELMULTI
? "KEV_DL_DELMULTI" :
7302 msg
.k
.event_code
== KEV_DL_IF_ATTACHED
? "KEV_DL_IF_ATTACHED" :
7303 msg
.k
.event_code
== KEV_DL_IF_DETACHING
? "KEV_DL_IF_DETACHING" :
7304 msg
.k
.event_code
== KEV_DL_IF_DETACHED
? "KEV_DL_IF_DETACHED" :
7305 msg
.k
.event_code
== KEV_DL_LINK_OFF
? "KEV_DL_LINK_OFF" :
7306 msg
.k
.event_code
== KEV_DL_LINK_ON
? "KEV_DL_LINK_ON" :
7307 msg
.k
.event_code
== KEV_DL_PROTO_ATTACHED
? "KEV_DL_PROTO_ATTACHED" :
7308 msg
.k
.event_code
== KEV_DL_PROTO_DETACHED
? "KEV_DL_PROTO_DETACHED" :
7309 msg
.k
.event_code
== KEV_DL_LINK_ADDRESS_CHANGED
? "KEV_DL_LINK_ADDRESS_CHANGED" :
7310 msg
.k
.event_code
== KEV_DL_WAKEFLAGS_CHANGED
? "KEV_DL_WAKEFLAGS_CHANGED" : "?");
7312 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
7313 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
7314 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
7315 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
7316 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
7318 if (msg
.k
.event_code
== KEV_DL_WAKEFLAGS_CHANGED
|| msg
.k
.event_code
== KEV_DL_LINK_ON
)
7319 SetNetworkChanged(m
, mDNSPlatformOneSecond
* 2);
7321 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
7323 // For p2p interfaces, need to open the advertised service port in the firewall.
7324 if (msg
.k
.event_code
== KEV_DL_IF_ATTACHED
)
7326 struct net_event_data
* p
;
7327 p
= (struct net_event_data
*) & msg
.k
.event_data
;
7329 if (strncmp(p
->if_name
, "p2p", 3) == 0)
7331 char ifname
[IFNAMSIZ
];
7332 snprintf(ifname
, IFNAMSIZ
, "%s%d", p
->if_name
, p
->if_unit
);
7334 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p
->if_family
, p
->if_unit
, p
->if_name
);
7336 mDNSSetPacketFilterRules(m
, ifname
);
7340 // For p2p interfaces, need to clear the firewall rules on interface detach
7341 if (msg
.k
.event_code
== KEV_DL_IF_DETACHED
)
7343 struct net_event_data
* p
;
7344 p
= (struct net_event_data
*) & msg
.k
.event_data
;
7346 if (strncmp(p
->if_name
, "p2p", 3) == 0)
7348 char ifname
[IFNAMSIZ
];
7349 snprintf(ifname
, IFNAMSIZ
, "%s%d", p
->if_name
, p
->if_unit
);
7351 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p
->if_family
, p
->if_unit
, p
->if_name
);
7353 mDNSPacketFilterControl(PF_CLEAR_RULES
, ifname
, 0, 0);
7356 #endif // !TARGET_OS_EMBEDDED
7363 mDNSlocal mStatus
WatchForSysEvents(mDNS
*const m
)
7365 m
->p
->SysEventNotifier
= socket(PF_SYSTEM
, SOCK_RAW
, SYSPROTO_EVENT
);
7366 if (m
->p
->SysEventNotifier
< 0)
7367 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m
->p
->SysEventNotifier
, errno
, strerror(errno
)); return(mStatus_NoMemoryErr
); }
7369 struct kev_request kev_req
= { KEV_VENDOR_APPLE
, KEV_NETWORK_CLASS
, KEV_DL_SUBCLASS
};
7370 int err
= ioctl(m
->p
->SysEventNotifier
, SIOCSKEVFILT
, &kev_req
);
7373 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err
, errno
, strerror(errno
));
7374 close(m
->p
->SysEventNotifier
);
7375 m
->p
->SysEventNotifier
= -1;
7376 return(mStatus_UnknownErr
);
7379 m
->p
->SysEventKQueue
.KQcallback
= SysEventCallBack
;
7380 m
->p
->SysEventKQueue
.KQcontext
= m
;
7381 m
->p
->SysEventKQueue
.KQtask
= "System Event Notifier";
7382 KQueueSet(m
->p
->SysEventNotifier
, EV_ADD
, EVFILT_READ
, &m
->p
->SysEventKQueue
);
7384 return(mStatus_NoError
);
7387 #ifndef NO_SECURITYFRAMEWORK
7388 mDNSlocal OSStatus
KeychainChanged(SecKeychainEvent keychainEvent
, SecKeychainCallbackInfo
*info
, void *context
)
7390 LogInfo("*** Keychain Changed ***");
7391 mDNS
*const m
= (mDNS
*const)context
;
7393 OSStatus err
= SecKeychainCopyDefault(&skc
);
7396 if (info
->keychain
== skc
)
7398 // 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
7399 mDNSBool relevant
= (keychainEvent
== kSecDeleteEvent
);
7402 UInt32 tags
[3] = { kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
};
7403 SecKeychainAttributeInfo attrInfo
= { 3, tags
, NULL
}; // Count, array of tags, array of formats
7404 SecKeychainAttributeList
*a
= NULL
;
7405 err
= SecKeychainItemCopyAttributesAndData(info
->item
, &attrInfo
, NULL
, &a
, NULL
, NULL
);
7408 relevant
= ((a
->attr
[0].length
== 4 && (!strncasecmp(a
->attr
[0].data
, "ddns", 4) || !strncasecmp(a
->attr
[0].data
, "sndd", 4))) ||
7409 (a
->attr
[1].length
>= mDNSPlatformStrLen(dnsprefix
) && (!strncasecmp(a
->attr
[1].data
, dnsprefix
, mDNSPlatformStrLen(dnsprefix
)))) ||
7410 (a
->attr
[1].length
>= mDNSPlatformStrLen(btmmprefix
) && (!strncasecmp(a
->attr
[1].data
, btmmprefix
, mDNSPlatformStrLen(btmmprefix
)))));
7411 SecKeychainItemFreeAttributesAndData(a
, NULL
);
7416 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
7418 keychainEvent
== kSecAddEvent
? "kSecAddEvent" :
7419 keychainEvent
== kSecDeleteEvent
? "kSecDeleteEvent" :
7420 keychainEvent
== kSecUpdateEvent
? "kSecUpdateEvent" : "<Unknown>");
7421 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
7425 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
7426 // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
7427 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
7429 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
7430 // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
7431 // a one second delay is ok, as we'll still converge to correctness, and there's no race
7432 // condition between the RegistrationDomain and the DomainAuthInfo.
7434 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
7435 // the timer here, as it will not get set by NetworkChanged().
7436 SetKeyChainTimer(m
, mDNSPlatformOneSecond
);
7439 KQueueUnlock(m
, "KeychainChanged");
7449 mDNSlocal
void PowerOn(mDNS
*const m
)
7451 mDNSCoreMachineSleep(m
, false); // Will set m->SleepState = SleepState_Awake;
7452 if (m
->p
->WakeAtUTC
)
7454 long utc
= mDNSPlatformUTC();
7455 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
7456 if (m
->p
->WakeAtUTC
- utc
> 30) LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m
->p
->WakeAtUTC
- utc
);
7457 else if (utc
- m
->p
->WakeAtUTC
> 30) LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc
- m
->p
->WakeAtUTC
);
7458 else if (!strncasecmp(HINFO_HWstring
, "K66AP", 5)) LogSPS("PowerChanged PowerOn %d seconds late, device is K66AP so not re-sleeping", utc
- m
->p
->WakeAtUTC
);
7461 LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m
->p
->WakeAtUTC
- utc
);
7462 m
->p
->RequestReSleep
= mDNS_TimeNow(m
) + 20 * mDNSPlatformOneSecond
;
7467 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
7469 mDNS
*const m
= (mDNS
*const)refcon
;
7471 (void)service
; // Parameter not used
7472 debugf("PowerChanged %X %lX", messageType
, messageArgument
);
7474 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
7475 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
7479 case kIOMessageCanSystemPowerOff
: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
7480 case kIOMessageSystemWillPowerOff
: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
7481 mDNSCoreMachineSleep(m
, true);
7482 if (m
->SleepState
== SleepState_Sleeping
) mDNSMacOSXNetworkChanged(m
);
7484 case kIOMessageSystemWillNotPowerOff
: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
7485 case kIOMessageCanSystemSleep
: LogSPS("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
7486 case kIOMessageSystemWillSleep
: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
7487 mDNSCoreMachineSleep(m
, true);
7489 case kIOMessageSystemWillNotSleep
: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
7490 case kIOMessageSystemHasPoweredOn
: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
7491 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
7494 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m
->SleepState
);
7497 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
7498 // the System Configuration Framework "network changed" event that we expect
7499 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
7501 if (!m
->p
->NetworkChanged
||
7502 m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2) < 0)
7503 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2);
7507 case kIOMessageSystemWillRestart
: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
7508 case kIOMessageSystemWillPowerOn
: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
7510 // On Leopard and earlier, on wake from sleep, instead of reporting link state down, Apple
7511 // Ethernet drivers report "hardware incapable of detecting link state", which the kernel
7512 // interprets as "should assume we have networking", which results in the first 4-5 seconds
7513 // of packets vanishing into a black hole. To work around this, on wake from sleep,
7514 // we block for five seconds to let Ethernet come up, and then resume normal operation.
7515 if (OSXVers
&& OSXVers
< OSXVers_10_6_SnowLeopard
)
7518 LogMsg("Running on Mac OS X version 10.%d earlier than 10.6; "
7519 "PowerChanged did sleep(5) to wait for Ethernet hardware", OSXVers
- OSXVers_Base
);
7522 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
7523 if (m
->SleepState
!= SleepState_Sleeping
)
7525 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m
->SleepState
);
7526 m
->SleepState
= SleepState_Sleeping
;
7527 mDNSMacOSXNetworkChanged(m
);
7531 default: LogSPS("PowerChanged unknown message %X", messageType
); break;
7534 if (messageType
== kIOMessageSystemWillSleep
) m
->p
->SleepCookie
= (long)messageArgument
;
7535 else IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
7537 KQueueUnlock(m
, "PowerChanged Sleep/Wake");
7540 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
7541 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
7542 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
7543 mDNSlocal
void SnowLeopardPowerChanged(void *refcon
, IOPMConnection connection
, IOPMConnectionMessageToken token
, IOPMSystemPowerStateCapabilities eventDescriptor
)
7545 mDNS
*const m
= (mDNS
*const)refcon
;
7547 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
7548 connection
, token
, eventDescriptor
,
7549 eventDescriptor
& kIOPMSystemPowerStateCapabilityCPU
? " CPU" : "",
7550 eventDescriptor
& kIOPMSystemPowerStateCapabilityVideo
? " Video" : "",
7551 eventDescriptor
& kIOPMSystemPowerStateCapabilityAudio
? " Audio" : "",
7552 eventDescriptor
& kIOPMSystemPowerStateCapabilityNetwork
? " Network" : "",
7553 eventDescriptor
& kIOPMSystemPowerStateCapabilityDisk
? " Disk" : "");
7555 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
7556 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
7558 if (eventDescriptor
& kIOPMSystemPowerStateCapabilityCPU
)
7560 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
7561 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
7562 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
7563 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
7566 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m
->SleepLimit
, m
->SleepState
);
7567 IOPMConnectionAcknowledgeEvent(connection
, m
->p
->SleepCookie
);
7570 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m
->SleepLimit
, m
->SleepState
);
7571 // If the network notifications have already come before we got the wakeup, we ignored them and
7572 // in case we get no more, we need to trigger one.
7574 SetNetworkChanged(m
, 2 * mDNSPlatformOneSecond
);
7576 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
7577 if (m
->SleepState
!= SleepState_Awake
) PowerOn(m
);
7578 IOPMConnectionAcknowledgeEvent(connection
, token
);
7582 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
7583 // we should hear nothing more until we're told that the CPU has started executing again.
7584 if (m
->SleepState
) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor
, m
->SleepState
);
7586 //mDNSMacOSXNetworkChanged(m);
7587 mDNSCoreMachineSleep(m
, true);
7588 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
7589 m
->p
->SleepCookie
= token
;
7592 KQueueUnlock(m
, "SnowLeopardPowerChanged Sleep/Wake");
7596 #if COMPILER_LIKES_PRAGMA_MARK
7598 #pragma mark - /etc/hosts support
7601 // Implementation Notes
7603 // As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
7604 // 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
7605 // them into a hash table. The implementation need to be able to do the following things efficiently
7607 // 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
7608 // 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
7609 // 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
7610 // need to be able set the RRSet of a resource record to the first one in the list and also update when
7611 // one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
7613 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
7615 // CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
7616 // "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
7617 // of the core layer which does all of the above very efficiently
7619 #define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
7621 mDNSexport
void FreeEtcHosts(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
7626 if (result
== mStatus_MemFree
)
7628 LogInfo("FreeEtcHosts: %s", ARDisplayString(m
, rr
));
7629 freeL("etchosts", rr
);
7633 // Returns true on success and false on failure
7634 mDNSlocal mDNSBool
mDNSMacOSXCreateEtcHostsEntry(mDNS
*const m
, const domainname
*domain
, const struct sockaddr
*sa
, const domainname
*cname
, char *ifname
, AuthHash
*auth
)
7640 mDNSInterfaceID InterfaceID
= mDNSInterface_LocalOnly
;
7645 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
7650 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
7654 if (sa
&& sa
->sa_family
!= AF_INET
&& sa
->sa_family
!= AF_INET6
)
7656 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa
->sa_family
);
7663 mDNSu32 ifindex
= if_nametoindex(ifname
);
7666 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain
->c
, ifname
);
7669 InterfaceID
= (mDNSInterfaceID
)(uintptr_t)ifindex
;
7673 rrtype
= (sa
->sa_family
== AF_INET
? kDNSType_A
: kDNSType_AAAA
);
7675 rrtype
= kDNSType_CNAME
;
7677 // Check for duplicates. See whether we parsed an entry before like this ?
7678 slot
= AuthHashSlot(domain
);
7679 namehash
= DomainNameHashValue(domain
);
7680 ag
= AuthGroupForName(auth
, slot
, namehash
, domain
);
7686 if (rr
->resrec
.rrtype
== rrtype
)
7688 if (rrtype
== kDNSType_A
)
7691 ip
.NotAnInteger
= ((struct sockaddr_in
*)sa
)->sin_addr
.s_addr
;
7692 if (mDNSSameIPv4Address(rr
->resrec
.rdata
->u
.ipv4
, ip
))
7694 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain
->c
);
7698 else if (rrtype
== kDNSType_AAAA
)
7701 ip6
.l
[0] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[0];
7702 ip6
.l
[1] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[1];
7703 ip6
.l
[2] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[2];
7704 ip6
.l
[3] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[3];
7705 if (mDNSSameIPv6Address(rr
->resrec
.rdata
->u
.ipv6
, ip6
))
7707 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain
->c
);
7711 else if (rrtype
== kDNSType_CNAME
)
7713 if (SameDomainName(&rr
->resrec
.rdata
->u
.name
, cname
))
7715 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname
->c
, domain
->c
);
7723 rr
= mallocL("etchosts", sizeof(*rr
));
7724 if (rr
== NULL
) return mDNSfalse
;
7725 mDNSPlatformMemZero(rr
, sizeof(*rr
));
7726 mDNS_SetupResourceRecord(rr
, NULL
, InterfaceID
, rrtype
, 1, kDNSRecordTypeKnownUnique
, AuthRecordLocalOnly
, FreeEtcHosts
, NULL
);
7727 AssignDomainName(&rr
->namestorage
, domain
);
7731 rr
->resrec
.rdlength
= sa
->sa_family
== AF_INET
? sizeof(mDNSv4Addr
) : sizeof(mDNSv6Addr
);
7732 if (sa
->sa_family
== AF_INET
)
7733 rr
->resrec
.rdata
->u
.ipv4
.NotAnInteger
= ((struct sockaddr_in
*)sa
)->sin_addr
.s_addr
;
7736 rr
->resrec
.rdata
->u
.ipv6
.l
[0] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[0];
7737 rr
->resrec
.rdata
->u
.ipv6
.l
[1] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[1];
7738 rr
->resrec
.rdata
->u
.ipv6
.l
[2] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[2];
7739 rr
->resrec
.rdata
->u
.ipv6
.l
[3] = ((struct sockaddr_in6
*)sa
)->sin6_addr
.__u6_addr
.__u6_addr32
[3];
7744 rr
->resrec
.rdlength
= DomainNameLength(cname
);
7745 rr
->resrec
.rdata
->u
.name
.c
[0] = 0;
7746 AssignDomainName(&rr
->resrec
.rdata
->u
.name
, cname
);
7748 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
7749 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
7750 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(m
, rr
));
7751 InsertAuthRecord(m
, auth
, rr
);
7755 mDNSlocal
int EtcHostsParseOneName(int start
, int length
, char *buffer
, char **name
)
7760 for (i
= start
; i
< length
; i
++)
7762 if (buffer
[i
] == '#')
7764 if (buffer
[i
] != ' ' && buffer
[i
] != ',' && buffer
[i
] != '\t')
7768 // Found the start of a name, find the end and null terminate
7769 for (i
++; i
< length
; i
++)
7771 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t')
7783 mDNSlocal
void mDNSMacOSXParseEtcHostsLine(mDNS
*const m
, char *buffer
, ssize_t length
, AuthHash
*auth
)
7787 char *ifname
= NULL
;
7794 // Find the end of the address string
7795 for (i
= 0; i
< length
; i
++)
7797 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t' || buffer
[i
] == '%')
7799 if (buffer
[i
] == '%')
7806 // Convert the address string to an address
7807 struct addrinfo hints
;
7808 bzero(&hints
, sizeof(hints
));
7809 hints
.ai_flags
= AI_NUMERICHOST
;
7810 struct addrinfo
*gairesults
= NULL
;
7811 if (getaddrinfo(buffer
, NULL
, &hints
, &gairesults
) != 0)
7813 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
7819 // Parse the interface
7820 ifname
= &buffer
[ifStart
];
7821 for (i
= ifStart
+ 1; i
< length
; i
++)
7823 if (buffer
[i
] == ' ' || buffer
[i
] == ',' || buffer
[i
] == '\t')
7831 i
= EtcHostsParseOneName(i
+ 1, length
, buffer
, &name1
);
7834 // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
7835 if (!MakeDomainNameFromDNSNameString(&name1d
, name1
))
7837 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1
);
7838 freeaddrinfo(gairesults
);
7841 mDNSMacOSXCreateEtcHostsEntry(m
, &name1d
, gairesults
->ai_addr
, mDNSNULL
, ifname
, auth
);
7846 // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
7847 // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
7848 // doing the right thing.
7849 if (!MakeDomainNameFromDNSNameString(&first
, name1
))
7851 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1
);
7852 freeaddrinfo(gairesults
);
7855 // If the /etc/hosts has an entry like this
7857 // 1.2.3.4 sun star bright
7859 // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
7860 // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
7862 // To achieve this, we need to add the entry like this:
7864 // star CNAME bright
7868 // We store the first name we parsed in "first". Then we parse additional names adding CNAME records
7869 // till we reach the end. When we reach the end, we wrap around and add one final CNAME with the last
7870 // entry and the first entry. Finally, we add the Address (A/AAAA) record.
7874 // Parse a name. If there are no names, we need to know whether we
7875 // parsed CNAMEs before or not. If we parsed CNAMEs before, then we
7876 // add a CNAME with the last name and the first name. Otherwise, this
7877 // is same as the common case above where the line has just one name
7878 // but with trailing white spaces.
7879 i
= EtcHostsParseOneName(i
+ 1, length
, buffer
, &name2
);
7882 if (!MakeDomainNameFromDNSNameString(&name2d
, name2
))
7884 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2
);
7885 freeaddrinfo(gairesults
);
7890 else if (!aliasIndex
)
7892 // We have never parsed any aliases. This case happens if there
7893 // is just one name and some extra white spaces at the end.
7894 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first
.c
);
7899 // We have parsed at least one alias before and we reached the end of the line.
7900 // Setup a CNAME for the last name with "first" name as its RDATA
7902 AssignDomainName(&name2d
, &first
);
7905 // Don't add a CNAME for the first alias we parse (see the example above).
7906 // As we parse more, we might discover that there are no more aliases, in
7907 // which case we would have set "name2d" to "first" above. We need to add
7908 // the CNAME in that case.
7910 if (aliasIndex
> 1 || SameDomainName(&name2d
, &first
))
7912 // Ignore if it points to itself
7913 if (!SameDomainName(&name1d
, &name2d
))
7915 if (!mDNSMacOSXCreateEtcHostsEntry(m
, &name1d
, mDNSNULL
, &name2d
, ifname
, auth
))
7917 freeaddrinfo(gairesults
);
7922 LogMsg("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names name1 %##s, name2 %##s", name1d
.c
, name2d
.c
);
7925 // If we have already wrapped around, we just need to add the A/AAAA record alone
7926 // which is done below
7927 if (SameDomainName(&name2d
, &first
)) break;
7929 // Remember the current name so that we can set the CNAME record if we parse one
7932 AssignDomainName(&name1d
, &name2d
);
7934 // Added all the CNAMEs if any, add the "A/AAAA" record
7935 mDNSMacOSXCreateEtcHostsEntry(m
, &first
, gairesults
->ai_addr
, mDNSNULL
, ifname
, auth
);
7937 freeaddrinfo(gairesults
);
7940 mDNSlocal
void mDNSMacOSXParseEtcHosts(mDNS
*const m
, int fd
, AuthHash
*auth
)
7943 char buf
[ETCHOSTS_BUFSIZE
];
7947 if (fd
== -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
7949 fp
= fopen("/etc/hosts", "r");
7950 if (!fp
) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
7954 good
= (fgets(buf
, ETCHOSTS_BUFSIZE
, fp
) != NULL
);
7957 // skip comment and empty lines
7958 if (buf
[0] == '#' || buf
[0] == '\r' || buf
[0] == '\n')
7962 if (!len
) break; // sanity check
7964 if (buf
[len
- 1] == '\r' || buf
[len
- 1] == '\n')
7965 buf
[len
- 1] = '\0';
7967 // fgets always null terminates and hence even if we have no
7968 // newline at the end, it is null terminated. The callee expects
7969 // the length to be such that buf[length] to be zero and hence
7971 mDNSMacOSXParseEtcHostsLine(m
, buf
, len
- 1, auth
);
7976 mDNSlocal
void mDNSMacOSXUpdateEtcHosts(mDNS
*const m
);
7978 mDNSlocal
int mDNSMacOSXGetEtcHostsFD(mDNS
*const m
)
7980 #ifdef __DISPATCH_GROUP__
7981 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
7982 static dispatch_queue_t etcq
= 0;
7983 static dispatch_source_t etcsrc
= 0;
7984 static dispatch_source_t hostssrc
= 0;
7986 // First time through? just schedule ourselves on the main queue and we'll do the work later
7989 etcq
= dispatch_get_main_queue();
7992 // Do this work on the queue, not here - solves potential synchronization issues
7993 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
7998 if (hostssrc
) return dispatch_source_get_handle(hostssrc
);
8001 int fd
= open("/etc/hosts", O_RDONLY
);
8003 #ifdef __DISPATCH_GROUP__
8004 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
8007 // If the open failed and we're already watching /etc, we're done
8008 if (etcsrc
) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd
; }
8010 // we aren't watching /etc, we should be
8011 fd
= open("/etc", O_RDONLY
);
8012 if (fd
== -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
8013 etcsrc
= dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE
, fd
, DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_WRITE
| DISPATCH_VNODE_RENAME
, etcq
);
8019 dispatch_source_set_event_handler(etcsrc
,
8021 u_int32_t flags
= dispatch_source_get_data(etcsrc
);
8022 LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags
);
8023 if ((flags
& (DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_RENAME
)) != 0)
8025 dispatch_source_cancel(etcsrc
);
8026 dispatch_release(etcsrc
);
8028 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
8031 if ((flags
& DISPATCH_VNODE_WRITE
) != 0 && hostssrc
== NULL
)
8033 mDNSMacOSXUpdateEtcHosts(m
);
8036 dispatch_source_set_cancel_handler(etcsrc
, ^{close(fd
);});
8037 dispatch_resume(etcsrc
);
8039 // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
8040 fd
= open("/etc/hosts", O_RDONLY
| O_EVTONLY
);
8041 if (fd
== -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
8044 // create a dispatch source to watch for changes to hosts file
8045 hostssrc
= dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE
, fd
,
8046 (DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_WRITE
| DISPATCH_VNODE_RENAME
|
8047 DISPATCH_VNODE_ATTRIB
| DISPATCH_VNODE_EXTEND
| DISPATCH_VNODE_LINK
| DISPATCH_VNODE_REVOKE
), etcq
);
8048 if (hostssrc
== NULL
)
8053 dispatch_source_set_event_handler(hostssrc
,
8055 u_int32_t flags
= dispatch_source_get_data(hostssrc
);
8056 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags
);
8057 if ((flags
& (DISPATCH_VNODE_DELETE
| DISPATCH_VNODE_RENAME
)) != 0)
8059 dispatch_source_cancel(hostssrc
);
8060 dispatch_release(hostssrc
);
8062 // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
8063 // the block immediately, we try to open the file and the file may not exist and may
8064 // fail to get a notification in the future. When the file does not exist and
8065 // we start to monitor the directory, on "dispatch_resume" of that source, there
8066 // is no guarantee that the file creation will be notified always because when
8067 // the dispatch_resume returns, the kevent manager may not have registered the
8068 // kevent yet but the file may have been created
8070 dispatch_async(etcq
, ^{mDNSMacOSXUpdateEtcHosts(m
);});
8073 if ((flags
& DISPATCH_VNODE_WRITE
) != 0)
8075 mDNSMacOSXUpdateEtcHosts(m
);
8078 dispatch_source_set_cancel_handler(hostssrc
, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd
); close(fd
);});
8079 dispatch_resume(hostssrc
);
8081 // Cleanup /etc source, no need to watch it if we already have /etc/hosts
8084 dispatch_source_cancel(etcsrc
);
8085 dispatch_release(etcsrc
);
8089 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
8090 return hostssrc
? (int)dispatch_source_get_handle(hostssrc
) : -1;
8097 // When /etc/hosts is modified, flush all the cache records as there may be local
8098 // authoritative answers now
8099 mDNSlocal
void FlushAllCacheRecords(mDNS
*const m
)
8105 FORALL_CACHERECORDS(slot
, cg
, cr
)
8108 if (cr
->resrec
.InterfaceID
) continue;
8110 // If a resource record can answer A or AAAA, they need to be flushed so that we will
8111 // never used to deliver an ADD or RMV
8112 if (RRTypeAnswersQuestionType(&cr
->resrec
, kDNSType_A
) ||
8113 RRTypeAnswersQuestionType(&cr
->resrec
, kDNSType_AAAA
))
8115 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m
, cr
));
8116 mDNS_PurgeCacheResourceRecord(m
, cr
);
8121 // Add new entries to the core. If justCheck is set, this function does not add, just returns true
8122 mDNSlocal mDNSBool
EtcHostsAddNewEntries(mDNS
*const m
, AuthHash
*newhosts
, mDNSBool justCheck
)
8126 AuthRecord
*rr
, *primary
, *rrnext
;
8127 for (slot
= 0; slot
< AUTH_HASH_SLOTS
; slot
++)
8128 for (ag
= newhosts
->rrauth_hash
[slot
]; ag
; ag
= ag
->next
)
8131 for (rr
= ag
->members
; rr
; rr
= rrnext
)
8136 mDNSBool found
= mDNSfalse
;
8137 ag1
= AuthGroupForRecord(&m
->rrauth
, slot
, &rr
->resrec
);
8138 if (ag1
&& ag1
->members
)
8140 if (!primary
) primary
= ag1
->members
;
8144 // We are not using InterfaceID in checking for duplicates. This means,
8145 // if there are two addresses for a given name e.g., fe80::1%en0 and
8146 // fe80::1%en1, we only add the first one. It is not clear whether
8147 // this is a common case. To fix this, we also need to modify
8148 // mDNS_Register_internal in how it handles duplicates. If it becomes a
8149 // common case, we will fix it then.
8150 if (IdenticalResourceRecord(&rr1
->resrec
, &rr
->resrec
))
8152 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m
, rr1
));
8163 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m
, rr
));
8166 RemoveAuthRecord(m
, newhosts
, rr
);
8167 // if there is no primary, point to self
8168 rr
->RRSet
= (primary
? primary
: rr
);
8170 LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m
, rr
));
8171 if (mDNS_Register_internal(m
, rr
) != mStatus_NoError
)
8172 LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m
, rr
));
8179 // Delete entries from the core that are no longer needed. If justCheck is set, this function
8180 // does not delete, just returns true
8181 mDNSlocal mDNSBool
EtcHostsDeleteOldEntries(mDNS
*const m
, AuthHash
*newhosts
, mDNSBool justCheck
)
8185 AuthRecord
*rr
, *primary
, *rrnext
;
8186 for (slot
= 0; slot
< AUTH_HASH_SLOTS
; slot
++)
8187 for (ag
= m
->rrauth
.rrauth_hash
[slot
]; ag
; ag
= ag
->next
)
8188 for (rr
= ag
->members
; rr
; rr
= rrnext
)
8190 mDNSBool found
= mDNSfalse
;
8194 if (rr
->RecordCallback
!= FreeEtcHosts
) continue;
8195 ag1
= AuthGroupForRecord(newhosts
, slot
, &rr
->resrec
);
8198 primary
= rr1
= ag1
->members
;
8201 if (IdenticalResourceRecord(&rr1
->resrec
, &rr
->resrec
))
8203 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m
, rr
));
8210 // there is no corresponding record in newhosts for the same name. This means
8211 // we should delete this from the core.
8216 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m
, rr
));
8219 // if primary is going away, make sure that the rest of the records
8220 // point to the new primary
8221 if (rr
== ag
->members
)
8223 AuthRecord
*new_primary
= rr
->next
;
8224 AuthRecord
*r
= new_primary
;
8229 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m
, r
));
8230 r
->RRSet
= new_primary
;
8232 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m
, r
), r
->resrec
.name
);
8236 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m
, rr
));
8237 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
8243 mDNSlocal
void UpdateEtcHosts(mDNS
*const m
, void *context
)
8245 AuthHash
*newhosts
= (AuthHash
*)context
;
8247 if (!m
->mDNS_busy
) LogMsg("UpdateEtcHosts: ERROR!! Lock not held");
8249 //Delete old entries from the core if they are not present in the newhosts
8250 EtcHostsDeleteOldEntries(m
, newhosts
, mDNSfalse
);
8251 // Add the new entries to the core if not already present in the core
8252 EtcHostsAddNewEntries(m
, newhosts
, mDNSfalse
);
8255 mDNSlocal
void FreeNewHosts(AuthHash
*newhosts
)
8258 AuthGroup
*ag
, *agnext
;
8259 AuthRecord
*rr
, *rrnext
;
8261 for (slot
= 0; slot
< AUTH_HASH_SLOTS
; slot
++)
8262 for (ag
= newhosts
->rrauth_hash
[slot
]; ag
; ag
= agnext
)
8265 for (rr
= ag
->members
; rr
; rr
= rrnext
)
8268 freeL("etchosts", rr
);
8270 freeL("AuthGroups", ag
);
8274 mDNSlocal
void mDNSMacOSXUpdateEtcHosts(mDNS
*const m
)
8278 // As we will be modifying the core, we can only have one thread running at
8279 // any point in time.
8282 mDNSPlatformMemZero(&newhosts
, sizeof(AuthHash
));
8284 // Get the file desecriptor (will trigger us to start watching for changes)
8285 int fd
= mDNSMacOSXGetEtcHostsFD(m
);
8288 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd
);
8289 mDNSMacOSXParseEtcHosts(m
, fd
, &newhosts
);
8291 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
8293 // Optimization: Detect whether /etc/hosts changed or not.
8295 // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
8296 // newhosts is already registered with core. If we find at least one entry that is not
8297 // registered with core, then it means we have work to do.
8299 // 2. Next, we check to see if any of the entries that are registered with core is not present
8300 // in newhosts. If we find at least one entry that is not present, it means we have work to
8303 // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
8304 // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
8305 // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
8306 // in the future and this code does not have to change.
8308 // Add the new entries to the core if not already present in the core
8309 if (!EtcHostsAddNewEntries(m
, &newhosts
, mDNStrue
))
8311 // No new entries to add, check to see if we need to delete any old entries from the
8312 // core if they are not present in the newhosts
8313 if (!EtcHostsDeleteOldEntries(m
, &newhosts
, mDNStrue
))
8315 LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
8317 KQueueUnlock(m
, "/etc/hosts changed");
8318 FreeNewHosts(&newhosts
);
8323 // This will flush the cache, stop and start the query so that the queries
8324 // can look at the /etc/hosts again
8328 // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
8329 // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
8330 // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
8331 // delivers these events in the right order and then calls us back to delete them.
8333 // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
8334 // is a common function that looks at all local auth records and delivers a RMV including
8335 // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
8336 // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
8337 // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
8338 // is called back where we do the Registration of the record. This results in RMV followed by ADD which
8340 mDNSCoreRestartAddressQueries(m
, mDNSfalse
, FlushAllCacheRecords
, UpdateEtcHosts
, &newhosts
);
8343 KQueueUnlock(m
, "/etc/hosts changed");
8344 FreeNewHosts(&newhosts
);
8347 #if COMPILER_LIKES_PRAGMA_MARK
8349 #pragma mark - Initialization & Teardown
8352 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
8353 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
8354 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
8355 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
8357 // Major version 6 is 10.2.x (Jaguar)
8358 // Major version 7 is 10.3.x (Panther)
8359 // Major version 8 is 10.4.x (Tiger)
8360 // Major version 9 is 10.5.x (Leopard)
8361 // Major version 10 is 10.6.x (SnowLeopard)
8362 mDNSexport
void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
8364 int major
= 0, minor
= 0;
8365 char letter
= 0, prodname
[256]="<Unknown>", prodvers
[256]="<Unknown>", buildver
[256]="<Unknown>";
8366 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
8369 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
8370 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
8371 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
8372 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
8373 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
8374 if (cfbuildver
&& CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
))
8375 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
8378 if (!major
) { major
=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
8379 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, STRINGIFY(mDNSResponderVersion
));
8380 //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
8382 // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
8383 if ((prodname
[0] & 0xDF) == 'M') OSXVers
= major
; else iOSVers
= major
;
8386 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
8387 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
8388 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
8389 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
8392 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
8394 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
8397 struct sockaddr_in s5353
;
8398 s5353
.sin_family
= AF_INET
;
8399 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
8400 s5353
.sin_addr
.s_addr
= 0;
8401 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
8405 if (err
) LogMsg("No unicast UDP responses");
8406 else debugf("Unicast UDP responses okay");
8410 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
8411 // 1) query for b._dns-sd._udp.local on LocalOnly interface
8412 // (.local manually generated via explicit callback)
8413 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
8414 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
8415 // 4) result above should generate a callback from question in (1). result added to global list
8416 // 5) global list delivered to client via GetSearchDomainList()
8417 // 6) client calls to enumerate domains now go over LocalOnly interface
8418 // (!!!KRS may add outgoing interface in addition)
8420 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
8423 m
->p
->CFRunLoop
= CFRunLoopGetCurrent();
8425 char HINFO_SWstring
[256] = "";
8426 mDNSMacOSXSystemBuildNumber(HINFO_SWstring
);
8428 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
8429 // 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.
8431 for (i
=0; i
<100; i
++)
8433 domainlabel testlabel
;
8435 GetUserSpecifiedLocalHostName(&testlabel
);
8436 if (testlabel
.c
[0]) break;
8440 m
->hostlabel
.c
[0] = 0;
8442 int get_model
[2] = { CTL_HW
, HW_MODEL
};
8443 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
8445 // Normal Apple model names are of the form "iPhone2,1", and
8446 // internal code names are strings containing no commas, e.g. "N88AP".
8447 // We used to ignore internal code names, but Apple now uses these internal code names
8448 // even in released shipping products, so we no longer ignore strings containing no commas.
8449 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
8450 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
8451 HINFO_HWstring
= HINFO_HWstring_buffer
;
8453 // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
8454 // For names of the form "N88AP" containg no comma, we use the entire string.
8455 HINFO_HWstring_prefixlen
= strchr(HINFO_HWstring_buffer
, ',') ? strcspn(HINFO_HWstring
, "0123456789") : strlen(HINFO_HWstring
);
8457 if (OSXVers
&& OSXVers
<= OSXVers_10_6_SnowLeopard
) m
->KnownBugs
|= mDNS_KnownBug_LimitedIPv6
;
8458 if (OSXVers
&& OSXVers
>= OSXVers_10_6_SnowLeopard
) m
->KnownBugs
|= mDNS_KnownBug_LossySyslog
;
8459 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
8461 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
8462 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
8463 if (hlen
+ slen
< 254)
8465 m
->HIHardware
.c
[0] = hlen
;
8466 m
->HISoftware
.c
[0] = slen
;
8467 mDNSPlatformMemCopy(&m
->HIHardware
.c
[1], HINFO_HWstring
, hlen
);
8468 mDNSPlatformMemCopy(&m
->HISoftware
.c
[1], HINFO_SWstring
, slen
);
8471 m
->p
->permanentsockets
.port
= MulticastDNSPort
;
8472 m
->p
->permanentsockets
.m
= m
;
8473 m
->p
->permanentsockets
.sktv4
= -1;
8474 m
->p
->permanentsockets
.kqsv4
.KQcallback
= myKQSocketCallBack
;
8475 m
->p
->permanentsockets
.kqsv4
.KQcontext
= &m
->p
->permanentsockets
;
8476 m
->p
->permanentsockets
.kqsv4
.KQtask
= "UDP packet reception";
8478 m
->p
->permanentsockets
.sktv6
= -1;
8479 m
->p
->permanentsockets
.kqsv6
.KQcallback
= myKQSocketCallBack
;
8480 m
->p
->permanentsockets
.kqsv6
.KQcontext
= &m
->p
->permanentsockets
;
8481 m
->p
->permanentsockets
.kqsv6
.KQtask
= "UDP packet reception";
8484 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET
, mDNSNULL
);
8486 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET6
, mDNSNULL
);
8489 struct sockaddr_in s4
;
8490 socklen_t n4
= sizeof(s4
);
8491 if (getsockname(m
->p
->permanentsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0) LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
8492 else m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
8494 if (m
->p
->permanentsockets
.sktv6
>= 0)
8496 struct sockaddr_in6 s6
;
8497 socklen_t n6
= sizeof(s6
);
8498 if (getsockname(m
->p
->permanentsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
8499 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
8503 m
->p
->InterfaceList
= mDNSNULL
;
8504 m
->p
->userhostlabel
.c
[0] = 0;
8505 m
->p
->usernicelabel
.c
[0] = 0;
8506 m
->p
->prevoldnicelabel
.c
[0] = 0;
8507 m
->p
->prevnewnicelabel
.c
[0] = 0;
8508 m
->p
->prevoldhostlabel
.c
[0] = 0;
8509 m
->p
->prevnewhostlabel
.c
[0] = 0;
8510 m
->p
->NotifyUser
= 0;
8511 m
->p
->KeyChainTimer
= 0;
8512 m
->p
->WakeAtUTC
= 0;
8513 m
->p
->RequestReSleep
= 0;
8515 #if APPLE_OSX_mDNSResponder
8516 uuid_generate(m
->asl_uuid
);
8519 m
->AutoTunnelHostAddr
.b
[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
8520 m
->AutoTunnelRelayAddrIn
= zerov6Addr
;
8521 m
->AutoTunnelRelayAddrOut
= zerov6Addr
;
8523 NetworkChangedKey_IPv4
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
8524 NetworkChangedKey_IPv6
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
8525 NetworkChangedKey_Hostnames
= SCDynamicStoreKeyCreateHostNames(NULL
);
8526 NetworkChangedKey_Computername
= SCDynamicStoreKeyCreateComputerName(NULL
);
8527 NetworkChangedKey_DNS
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
8528 if (!NetworkChangedKey_IPv4
|| !NetworkChangedKey_IPv6
|| !NetworkChangedKey_Hostnames
|| !NetworkChangedKey_Computername
|| !NetworkChangedKey_DNS
)
8529 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr
); }
8531 err
= WatchForNetworkChanges(m
);
8532 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err
); return(err
); }
8534 #if 0 // <rdar://problem/6751656>
8535 err
= WatchForPMChanges(m
);
8536 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForPMChanges failed %d", err
); return(err
); }
8539 err
= WatchForSysEvents(m
);
8540 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err
); return(err
); }
8542 mDNSs32 utc
= mDNSPlatformUTC();
8543 m
->SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess();
8544 UpdateInterfaceList(m
, utc
);
8545 SetupActiveInterfaces(m
, utc
);
8547 // Explicitly ensure that our Keychain operations utilize the system domain.
8548 #ifndef NO_SECURITYFRAMEWORK
8549 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
8553 SetDomainSecrets(m
);
8557 #ifndef NO_SECURITYFRAMEWORK
8558 err
= SecKeychainAddCallback(KeychainChanged
, kSecAddEventMask
|kSecDeleteEventMask
|kSecUpdateEventMask
, m
);
8559 if (err
) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err
); return(err
); }
8562 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
8563 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
8566 IOReturn iopmerr
= IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU
, &c
);
8567 if (iopmerr
) LogMsg("IOPMConnectionCreate failed %d", iopmerr
);
8570 iopmerr
= IOPMConnectionSetNotification(c
, m
, SnowLeopardPowerChanged
);
8571 if (iopmerr
) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr
);
8574 iopmerr
= IOPMConnectionScheduleWithRunLoop(c
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
);
8575 if (iopmerr
) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr
);
8578 m
->p
->IOPMConnection
= iopmerr
? mDNSNULL
: c
;
8579 if (iopmerr
) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
8580 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
8582 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &m
->p
->PowerPortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
8583 if (!m
->p
->PowerConnection
) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
8586 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8587 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, dispatch_get_main_queue());
8589 CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
8590 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
8594 #if APPLE_OSX_mDNSResponder
8595 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
8596 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
8597 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
8598 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
8599 if (!strncasecmp(HINFO_HWstring
, "Xserve", 6)) { SPMetricPortability
= 25 /* 30kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
8600 else if (!strncasecmp(HINFO_HWstring
, "RackMac", 7)) { SPMetricPortability
= 25 /* 30kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
8601 else if (!strncasecmp(HINFO_HWstring
, "MacPro", 6)) { SPMetricPortability
= 27 /* 20kg */; SPMetricMarginalPower
= 84 /* 250W */; SPMetricTotalPower
= 85 /* 300W */; }
8602 else if (!strncasecmp(HINFO_HWstring
, "PowerMac", 8)) { SPMetricPortability
= 27 /* 20kg */; SPMetricMarginalPower
= 82 /* 160W */; SPMetricTotalPower
= 83 /* 200W */; }
8603 else if (!strncasecmp(HINFO_HWstring
, "iMac", 4)) { SPMetricPortability
= 30 /* 10kg */; SPMetricMarginalPower
= 77 /* 50W */; SPMetricTotalPower
= 78 /* 60W */; }
8604 else if (!strncasecmp(HINFO_HWstring
, "Macmini", 7)) { SPMetricPortability
= 33 /* 5kg */; SPMetricMarginalPower
= 73 /* 20W */; SPMetricTotalPower
= 74 /* 25W */; }
8605 else if (!strncasecmp(HINFO_HWstring
, "TimeCapsule", 11)) { SPMetricPortability
= 34 /* 4kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 70 /* 13W */; }
8606 else if (!strncasecmp(HINFO_HWstring
, "AirPort", 7)) { SPMetricPortability
= 35 /* 3kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 70 /* 12W */; }
8607 else if (!strncasecmp(HINFO_HWstring
, "AppleTV", 7)) { SPMetricPortability
= 35 /* 3kg */; SPMetricMarginalPower
= 10 /* ~0W */; SPMetricTotalPower
= 73 /* 20W */; }
8608 else if (!strncasecmp(HINFO_HWstring
, "K66AP", 5)) { SPMetricPortability
= 35 /* 3kg */; SPMetricMarginalPower
= 60 /* 1W */; SPMetricTotalPower
= 63 /* 2W */; }
8609 else if (!strncasecmp(HINFO_HWstring
, "MacBook", 7)) { SPMetricPortability
= 37 /* 2kg */; SPMetricMarginalPower
= 71 /* 13W */; SPMetricTotalPower
= 72 /* 15W */; }
8610 else if (!strncasecmp(HINFO_HWstring
, "PowerBook", 9)) { SPMetricPortability
= 37 /* 2kg */; SPMetricMarginalPower
= 71 /* 13W */; SPMetricTotalPower
= 72 /* 15W */; }
8611 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d",
8612 HINFO_HWstring_prefixlen
, HINFO_HWstring
, HINFO_HWstring
, SPMetricPortability
, SPMetricMarginalPower
, SPMetricTotalPower
);
8614 err
= WatchForInternetSharingChanges(m
);
8615 if (err
) { LogMsg("WatchForInternetSharingChanges failed %d", err
); return(err
); }
8617 m
->p
->ConndBTMMDict
= mDNSNULL
;
8618 #endif // APPLE_OSX_mDNSResponder
8620 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8621 // Currently this is not defined. SSL code will eventually fix this. If it becomes
8622 // critical, we will define this to workaround the bug in SSL.
8623 #ifdef __SSL_NEEDS_SERIALIZATION__
8624 SSLqueue
= dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL
);
8626 SSLqueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
8628 if (SSLqueue
== mDNSNULL
) LogMsg("dispatch_queue_create: SSL queue NULL");
8630 mDNSMacOSXUpdateEtcHosts(m
);
8631 return(mStatus_NoError
);
8634 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
8637 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
8640 // Adding interfaces will use this flag, so set it now.
8641 m
->DivertMulticastAdvertisements
= !m
->AdvertiseLocalAddresses
;
8643 #if APPLE_OSX_mDNSResponder
8644 m
->SPSBrowseCallback
= UpdateSPSStatus
;
8645 #endif // APPLE_OSX_mDNSResponder
8647 mStatus result
= mDNSPlatformInit_setup(m
);
8649 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
8650 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
8651 if (result
== mStatus_NoError
)
8653 mDNSCoreInitComplete(m
, mStatus_NoError
);
8656 // We only initialize if mDNSCore successfully initialized.
8657 CHECK_D2D_FUNCTION(D2DInitialize
)
8659 D2DStatus ds
= D2DInitialize(m
->p
->CFRunLoop
, xD2DServiceCallback
, m
) ;
8660 if (ds
!= kD2DSuccess
)
8661 LogMsg("D2DInitialiize failed: %d", ds
);
8663 LogMsg("D2DInitialize succeeded");
8671 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
8673 if (m
->p
->PowerConnection
)
8675 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8676 IONotificationPortSetDispatchQueue(m
->p
->PowerPortRef
, NULL
);
8678 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
8680 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
8681 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
8682 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
8683 IOServiceClose ( m
->p
->PowerConnection
);
8684 IONotificationPortDestroy ( m
->p
->PowerPortRef
);
8685 m
->p
->PowerConnection
= 0;
8690 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8691 if (!SCDynamicStoreSetDispatchQueue(m
->p
->Store
, NULL
))
8692 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
8694 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
8695 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
8696 CFRelease(m
->p
->StoreRLS
);
8697 m
->p
->StoreRLS
= NULL
;
8699 CFRelease(m
->p
->Store
);
8705 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PMRLS
, kCFRunLoopDefaultMode
);
8706 CFRunLoopSourceInvalidate(m
->p
->PMRLS
);
8707 CFRelease(m
->p
->PMRLS
);
8711 if (m
->p
->SysEventNotifier
>= 0) { close(m
->p
->SysEventNotifier
); m
->p
->SysEventNotifier
= -1; }
8714 CHECK_D2D_FUNCTION(D2DTerminate
)
8716 D2DStatus ds
= D2DTerminate();
8717 if (ds
!= kD2DSuccess
)
8718 LogMsg("D2DTerminate failed: %d", ds
);
8720 LogMsg("D2DTerminate succeeded");
8724 mDNSs32 utc
= mDNSPlatformUTC();
8725 MarkAllInterfacesInactive(m
, utc
);
8726 ClearInactiveInterfaces(m
, utc
);
8727 CloseSocketSet(&m
->p
->permanentsockets
);
8729 #if APPLE_OSX_mDNSResponder
8731 while (m
->TunnelClients
)
8733 ClientTunnel
*cur
= m
->TunnelClients
;
8734 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur
, cur
->dstname
.c
);
8735 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
8736 AutoTunnelSetKeys(cur
, mDNSfalse
);
8737 m
->TunnelClients
= cur
->next
;
8738 freeL("ClientTunnel", cur
);
8741 if (AnonymousRacoonConfig
)
8743 AnonymousRacoonConfig
= mDNSNULL
;
8744 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel");
8745 (void)mDNSConfigureServer(kmDNSDown
, mDNSNULL
, mDNSNULL
);
8748 if (m
->AutoTunnelHostAddrActive
&& m
->AutoTunnelHostAddr
.b
[0])
8750 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
8751 LogInfo("mDNSPlatformClose: Removing AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
8752 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
8754 if (m
->p
->ConndBTMMDict
) CFRelease(m
->p
->ConndBTMMDict
);
8755 #endif // APPLE_OSX_mDNSResponder
8758 #if COMPILER_LIKES_PRAGMA_MARK
8760 #pragma mark - General Platform Support Layer functions
8763 mDNSexport mDNSu32
mDNSPlatformRandomNumber(void)
8765 return(arc4random());
8768 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
8769 mDNSexport mDNSu32 mDNSPlatformClockDivisor
= 0;
8771 mDNSexport mStatus
mDNSPlatformTimeInit(void)
8773 // Notes: Typical values for mach_timebase_info:
8774 // tbi.numer = 1000 million
8775 // tbi.denom = 33 million
8776 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
8777 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
8778 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
8779 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
8780 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
8782 // Arithmetic notes:
8783 // tbi.denom is at least 1, and not more than 2^32-1.
8784 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
8785 // tbi.denom is at least 1, and not more than 2^32-1.
8786 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
8787 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
8788 // which is unlikely on any current or future Macintosh.
8789 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
8790 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
8791 struct mach_timebase_info tbi
;
8792 kern_return_t result
= mach_timebase_info(&tbi
);
8793 if (result
== KERN_SUCCESS
) mDNSPlatformClockDivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
8797 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
8799 if (mDNSPlatformClockDivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
8801 static uint64_t last_mach_absolute_time
= 0;
8802 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
8803 uint64_t this_mach_absolute_time
= mach_absolute_time();
8804 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
8806 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
8807 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
8808 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
8809 last_mach_absolute_time
= this_mach_absolute_time
;
8810 // Note: This bug happens all the time on 10.3
8811 NotifyOfElusiveBug("mach_absolute_time went backwards!",
8812 "This error occurs from time to time, often on newly released hardware, "
8813 "and usually the exact cause is different in each instance.\r\r"
8814 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
8815 "and assign it to Radar Component “Kernel” Version “X”.");
8817 last_mach_absolute_time
= this_mach_absolute_time
;
8819 return((mDNSs32
)(this_mach_absolute_time
/ mDNSPlatformClockDivisor
));
8822 mDNSexport mDNSs32
mDNSPlatformUTC(void)
8827 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
8828 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
8829 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
8830 mDNSexport
void mDNSPlatformStrCopy( void *dst
, const void *src
) { strcpy((char *)dst
, (char *)src
); }
8831 mDNSexport mDNSu32
mDNSPlatformStrLen ( const void *src
) { return(strlen((char*)src
)); }
8832 mDNSexport
void mDNSPlatformMemCopy( void *dst
, const void *src
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
8833 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *dst
, const void *src
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
8834 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { memset(dst
, 0, len
); }
8835 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
8836 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
8838 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }
8840 mDNSexport
void mDNSPlatformSetAllowSleep(mDNS
*const m
, mDNSBool allowSleep
, const char *reason
)
8842 if (allowSleep
&& m
->p
->IOPMAssertion
)
8844 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__
);
8845 IOPMAssertionRelease(m
->p
->IOPMAssertion
);
8846 m
->p
->IOPMAssertion
= 0;
8848 else if (!allowSleep
&& m
->p
->IOPMAssertion
== 0)
8850 #ifdef kIOPMAssertionTypeNoIdleSleep
8851 CFStringRef assertionName
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s.%d %s"), getprogname(), getpid(), reason
? reason
: "");
8852 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep
, kIOPMAssertionLevelOn
, assertionName
? assertionName
: CFSTR("mDNSResponder"), &m
->p
->IOPMAssertion
);
8853 if (assertionName
) CFRelease(assertionName
);
8854 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__
);
8859 mDNSexport
void mDNSPlatformSendWakeupPacket(mDNS
*const m
, mDNSInterfaceID InterfaceID
, char *EthAddr
, char *IPAddr
, int iteration
)
8864 ifindex
= mDNSPlatformInterfaceIndexfromInterfaceID(m
, InterfaceID
, mDNStrue
);
8867 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex
);
8870 mDNSSendWakeupPacket(ifindex
, EthAddr
, IPAddr
, iteration
);
8873 // Called for rr->InterfaceID == mDNSInterface_Any.
8874 // If current interface is P2P, verify that record is marked to IncludeP2P.
8875 mDNSexport mDNSBool
mDNSPlatformValidRecordForInterface(AuthRecord
*rr
, const NetworkInterfaceInfo
*intf
)
8877 mDNSBool p2pInterface
= (strncmp(intf
->ifname
, "p2p", 3) == 0);
8879 if (!p2pInterface
|| (rr
->ARType
== AuthRecordAnyIncludeP2P
))