]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mDNSMacOSX.c
mDNSResponder-258.21.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / mDNSMacOSX.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 *
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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17
18 // ***************************************************************************
19 // mDNSMacOSX.c:
20 // Supporting routines to run mDNS on a CFRunLoop platform
21 // ***************************************************************************
22
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
26
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
31
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.
41
42 #define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
43
44 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
45 #include "DNSCommon.h"
46 #include "uDNS.h"
47 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
48 #include "dns_sd.h" // For mDNSInterface_LocalOnly etc.
49 #include "PlatformCommon.h"
50 #include "uds_daemon.h"
51
52 #include <stdio.h>
53 #include <stdarg.h> // For va_list support
54 #include <stdlib.h> // For arc4random
55 #include <net/if.h>
56 #include <net/if_types.h> // For IFT_ETHER
57 #include <net/if_dl.h>
58 #include <net/bpf.h> // For BIOCSETIF etc.
59 #include <sys/uio.h>
60 #include <sys/param.h>
61 #include <sys/socket.h>
62 #include <sys/sysctl.h>
63 #include <sys/event.h>
64 #include <fcntl.h>
65 #include <sys/ioctl.h>
66 #include <time.h> // platform support for UTC time
67 #include <arpa/inet.h> // for inet_aton
68 #include <pthread.h>
69
70 #include <netinet/in.h> // For IP_RECVTTL
71 #ifndef IP_RECVTTL
72 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
73 #endif
74
75 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
76 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
77 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
78 #include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
79
80 #if TARGET_OS_EMBEDDED
81 #define NO_SECURITYFRAMEWORK 1
82 #define NO_CFUSERNOTIFICATION 1
83 #endif
84
85 #ifndef NO_SECURITYFRAMEWORK
86 #include <Security/SecureTransport.h>
87 #include <Security/Security.h>
88 #endif /* NO_SECURITYFRAMEWORK */
89
90 #include <DebugServices.h>
91 #include "dnsinfo.h"
92
93 // Code contributed by Dave Heller:
94 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
95 // work on Mac OS X 10.1, which does not have the getifaddrs call.
96 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
97 #if RUN_ON_PUMA_WITHOUT_IFADDRS
98 #include "mDNSMacOSXPuma.c"
99 #else
100 #include <ifaddrs.h>
101 #endif
102
103 #include <IOKit/IOKitLib.h>
104 #include <IOKit/IOMessage.h>
105
106 #ifdef __LIB_DISPATCH__
107 // This is currently defined in IOKit/PrivateHeaders/IOKitLibPrivate.h. Till it becomes an Public
108 // API, we will have our own declaration
109 void IONotificationPortSetDispatchQueue(IONotificationPortRef notify, dispatch_queue_t queue);
110 #endif
111
112 #if USE_IOPMCOPYACTIVEPMPREFERENCES
113 #include <IOKit/ps/IOPowerSources.h>
114 #include <IOKit/ps/IOPowerSourcesPrivate.h>
115 #endif
116
117 #include <mach/mach_error.h>
118 #include <mach/mach_port.h>
119 #include <mach/mach_time.h>
120 #include "helper.h"
121
122 #include <asl.h>
123
124 #if APPLE_OSX_mDNSResponder
125 #include <DeviceToDeviceManager/DeviceToDeviceManager.h>
126 #include <AWACS.h>
127
128 #if ! NO_D2D
129 D2DStatus D2DInitialize(CFRunLoopRef runLoop, D2DServiceCallback serviceCallback, void* userData) __attribute__((weak_import));
130 D2DStatus D2DTerminate() __attribute__((weak_import));
131 D2DStatus D2DStartAdvertisingPair(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize) __attribute__((weak_import));
132 D2DStatus D2DStopAdvertisingPair(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize) __attribute__((weak_import));
133 D2DStatus D2DStartBrowsingForKey(const Byte *key, const size_t keySize) __attribute__((weak_import));
134 D2DStatus D2DStopBrowsingForKey(const Byte *key, const size_t keySize) __attribute__((weak_import));
135 void D2DStartResolvingPair(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize) __attribute__((weak_import));
136 void D2DStopResolvingPair(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize) __attribute__((weak_import));
137 D2DStatus D2DRetain(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
138 D2DStatus D2DRelease(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
139
140 #define CHECK_D2D_FUNCTION(X) if (X)
141
142 #endif // ! NO_D2D
143
144 #else
145 #define NO_D2D 1
146 #define NO_AWACS 1
147 #endif // APPLE_OSX_mDNSResponder
148
149 #define kInterfaceSpecificOption "interface="
150
151 // ***************************************************************************
152 // Globals
153
154 #if COMPILER_LIKES_PRAGMA_MARK
155 #pragma mark - Globals
156 #endif
157
158 // By default we don't offer sleep proxy service
159 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
160 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
161 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
162 mDNSexport int OfferSleepProxyService = 0;
163 mDNSexport int DisableSleepProxyClient = 0;
164
165 // We disable inbound relay connection if this value is set to true (typically via command-line switch).
166 mDNSBool DisableInboundRelayConnection = mDNSfalse;
167 mDNSexport int OSXVers;
168 mDNSexport int KQueueFD;
169
170 #ifndef NO_SECURITYFRAMEWORK
171 static CFArrayRef ServerCerts;
172 OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
173 #endif /* NO_SECURITYFRAMEWORK */
174
175 static CFStringRef NetworkChangedKey_IPv4;
176 static CFStringRef NetworkChangedKey_IPv6;
177 static CFStringRef NetworkChangedKey_Hostnames;
178 static CFStringRef NetworkChangedKey_Computername;
179 static CFStringRef NetworkChangedKey_DNS;
180 static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
181 static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
182 static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity");
183 static CFStringRef NetworkChangedKey_PowerSettings = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
184
185 static char HINFO_HWstring_buffer[32];
186 static char *HINFO_HWstring = "Device";
187 static int HINFO_HWstring_prefixlen = 6;
188
189 mDNSexport int WatchDogReportingThreshold = 250;
190
191 #ifdef __LIB_DISPATCH__
192 dispatch_queue_t SSLqueue;
193 #endif
194
195 #if APPLE_OSX_mDNSResponder
196 static mDNSu8 SPMetricPortability = 99;
197 static mDNSu8 SPMetricMarginalPower = 99;
198 static mDNSu8 SPMetricTotalPower = 99;
199 mDNSexport domainname ActiveDirectoryPrimaryDomain;
200 mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
201 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
202 #endif // APPLE_OSX_mDNSResponder
203
204 // ***************************************************************************
205 #if COMPILER_LIKES_PRAGMA_MARK
206 #pragma mark -
207 #pragma mark - D2D Support
208 #endif
209
210 #if ! NO_D2D
211
212 // Name compression items for fake packet version number 1
213 static const mDNSu8 compression_packet_v1 = 0x01;
214
215 static DNSMessage compression_base_msg = { { {{0}}, {{0}}, 2, 0, 0, 0 }, "\x04_tcp\x05local\x00\x00\x0C\x00\x01\x04_udp\xC0\x11\x00\x0C\x00\x01" };
216 static mDNSu8 *const compression_limit = (mDNSu8 *) &compression_base_msg + sizeof(DNSMessage);
217 static mDNSu8 *const compression_lhs = (mDNSu8 *const) compression_base_msg.data + 27;
218
219 mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
220 mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len);
221
222 static ARListElem *D2DRecords = NULL; // List of locally-generated PTR records to records found via D2D
223
224 typedef struct D2DBrowseListElem
225 {
226 struct D2DBrowseListElem *next;
227 domainname name;
228 mDNSu16 type;
229 unsigned int refCount;
230 } D2DBrowseListElem;
231
232 D2DBrowseListElem* D2DBrowseList = NULL;
233
234 mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
235 {
236 ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
237 ptr[1] = (mDNSu8)((val ) & 0xFF);
238 return ptr + sizeof(mDNSu16);
239 }
240
241 mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
242 {
243 ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
244 ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
245 ptr[2] = (mDNSu8)((val >> 8) & 0xFF);
246 ptr[3] = (mDNSu8)((val ) & 0xFF);
247 return ptr + sizeof(mDNSu32);
248 }
249
250 mDNSlocal void DomainnameToLower(const domainname * const in, domainname * const out)
251 {
252 const mDNSu8 * const start = (const mDNSu8 * const)in;
253 mDNSu8 *ptr = (mDNSu8*)start;
254 while(*ptr)
255 {
256 mDNSu8 c = *ptr;
257 out->c[ptr-start] = *ptr;
258 ptr++;
259 for (;c;c--,ptr++) out->c[ptr-start] = mDNSIsUpperCase(*ptr) ? (*ptr - 'A' + 'a') : *ptr;
260 }
261 out->c[ptr-start] = *ptr;
262 }
263
264 mDNSlocal mStatus DNSNameCompressionParseBytes(mDNS *const m, const mDNSu8 *const lhs, const mDNSu16 lhs_len, const mDNSu8 *const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
265 {
266 if (mDNS_LoggingEnabled)
267 {
268 LogInfo("%s", __func__);
269 LogInfo(" Static Bytes: ");
270 PrintHex((mDNSu8*)&compression_base_msg, compression_lhs - (mDNSu8*)&compression_base_msg);
271 }
272
273 mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet
274
275 // Check to make sure we're not going to go past the end of the DNSMessage data
276 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
277 if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr;
278
279 // Copy the LHS onto our fake wire packet
280 mDNSPlatformMemCopy(ptr, lhs, lhs_len);
281 ptr += lhs_len - 1;
282
283 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
284 if (*ptr != compression_packet_v1) return mStatus_Incompatible;
285
286 // two bytes of CLASS
287 ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet);
288
289 // four bytes of TTL
290 ptr = putVal32(ptr, 120);
291
292 // Copy the RHS length into the RDLENGTH of our fake wire packet
293 ptr = putVal16(ptr, rhs_len);
294
295 // Copy the RHS onto our fake wire packet
296 mDNSPlatformMemCopy(ptr, rhs, rhs_len);
297 ptr += rhs_len;
298
299 if (mDNS_LoggingEnabled)
300 {
301 LogInfo(" Our Bytes %d: ", __LINE__);
302 PrintHex(compression_lhs, ptr - compression_lhs);
303 }
304
305 ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec);
306 if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative)
307 { LogMsg("DNSNameCompressionParseBytes: failed to get large RR"); m->rec.r.resrec.RecordType = 0; return mStatus_UnknownErr; }
308 else LogInfo("DNSNameCompressionParseBytes: got rr: %s", CRDisplayString(m, &m->rec.r));
309
310 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, FreeD2DARElemCallback, NULL);
311 AssignDomainName(&rr->namestorage, &m->rec.namestorage);
312 rr->resrec.rdlength = m->rec.r.resrec.rdlength;
313 rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength;
314 mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength);
315 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
316 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
317
318 m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use
319
320 return mStatus_NoError;
321 }
322
323 mDNSlocal mDNSu8 * DNSNameCompressionBuildLHS(const domainname const *typeDomain, DNS_TypeValues qtype)
324 {
325 mDNSu8 *ptr = putDomainNameAsLabels(&compression_base_msg, compression_lhs, compression_limit, typeDomain);
326 if (!ptr) return ptr;
327 *ptr = (qtype >> 8) & 0xff;
328 ptr += 1;
329 *ptr = qtype & 0xff;
330 ptr += 1;
331 *ptr = compression_packet_v1;
332 return ptr + 1;
333 }
334
335 mDNSlocal mDNSu8 * DNSNameCompressionBuildRHS(mDNSu8 *start, const ResourceRecord *const resourceRecord)
336 {
337 return putRData(&compression_base_msg, start, compression_limit, resourceRecord);
338 }
339
340 mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len)
341 {
342 mDNSu8 *end = data + len;
343 char buffer[49] = {0};
344 char *bufend = buffer + sizeof(buffer);
345 while(data<end)
346 {
347 char *ptr = buffer;
348 for(; data < end && ptr < bufend-1; ptr+=3,data++)
349 mDNS_snprintf(ptr, bufend - ptr, "%02X ", *data);
350 LogInfo(" %s", buffer);
351 }
352 }
353
354 mDNSlocal void PrintHelper(const char *const tag, mDNSu8 *lhs, mDNSu16 lhs_len, mDNSu8 *rhs, mDNSu16 rhs_len)
355 {
356 if (!mDNS_LoggingEnabled) return;
357
358 LogInfo("%s:", tag);
359 LogInfo(" LHS: ");
360 PrintHex(lhs, lhs_len);
361
362 if (!rhs) return;
363
364 LogInfo(" RHS: ");
365 PrintHex(rhs, rhs_len);
366 }
367
368 mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
369 {
370 (void)m; // unused
371 if (result == mStatus_MemFree)
372 {
373 ARListElem **ptr = &D2DRecords;
374 ARListElem *tmp;
375 while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
376 if (!*ptr) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m, rr)); return; }
377 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m, rr));
378 tmp = *ptr;
379 *ptr = (*ptr)->next;
380 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
381 mDNSPlatformMemFree(tmp);
382 }
383 }
384
385 mDNSlocal void xD2DClearCache(mDNS *const m, const domainname *regType)
386 {
387 ARListElem *ptr = D2DRecords;
388 for ( ; ptr ; ptr = ptr->next)
389 {
390 if (SameDomainName(&ptr->ar.namestorage, regType))
391 {
392 char buffer[MAX_ESCAPED_DOMAIN_NAME];
393 mDNS_Deregister(m, &ptr->ar);
394 ConvertDomainNameToCString(regType, buffer);
395 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", buffer);
396 }
397 }
398 }
399
400 mDNSlocal D2DBrowseListElem ** D2DFindInBrowseList(const domainname *const name, mDNSu16 type)
401 {
402 D2DBrowseListElem **ptr = &D2DBrowseList;
403
404 for ( ; *ptr; ptr = &(*ptr)->next)
405 if ((*ptr)->type == type && SameDomainName(&(*ptr)->name, name))
406 break;
407
408 return ptr;
409 }
410
411 mDNSlocal unsigned int D2DBrowseListRefCount(const domainname *const name, mDNSu16 type)
412 {
413 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
414 return *ptr ? (*ptr)->refCount : 0;
415 }
416
417 mDNSlocal void D2DBrowseListRetain(const domainname *const name, mDNSu16 type)
418 {
419 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
420
421 if (!*ptr)
422 {
423 *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
424 mDNSPlatformMemZero(*ptr, sizeof(**ptr));
425 (*ptr)->type = type;
426 AssignDomainName(&(*ptr)->name, name);
427 }
428 (*ptr)->refCount += 1;
429
430 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
431 }
432
433 mDNSlocal void D2DBrowseListRelease(const domainname *const name, mDNSu16 type)
434 {
435 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
436
437 if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return; }
438
439 (*ptr)->refCount -= 1;
440
441 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
442
443 if (!(*ptr)->refCount)
444 {
445 D2DBrowseListElem *tmp = *ptr;
446 *ptr = (*ptr)->next;
447 mDNSPlatformMemFree(tmp);
448 }
449 }
450
451 mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
452 {
453 if (*(lhs + (lhs_len - 1)) == compression_packet_v1)
454 return DNSNameCompressionParseBytes(m, lhs, lhs_len, rhs, rhs_len, rr);
455 else
456 return mStatus_Incompatible;
457 }
458
459 mDNSlocal void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
460 {
461 (void)transportType; // We don't care about this, yet.
462 (void)instanceHandle; // We don't care about this, yet.
463
464 if (result == kD2DSuccess)
465 {
466 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
467
468 mStatus err;
469 ARListElem *ptr = mDNSPlatformMemAllocate(sizeof(ARListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
470
471 if (ptr == NULL) { LogMsg("xD2DAddToCache: memory allocation failure"); return; }
472
473 err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr->ar);
474 if (err)
475 {
476 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err);
477 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
478 mDNSPlatformMemFree(ptr);
479 return;
480 }
481
482 err = mDNS_Register(m, &ptr->ar);
483 if (err)
484 {
485 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err, ARDisplayString(m, &ptr->ar));
486 mDNSPlatformMemFree(ptr);
487 return;
488 }
489
490 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m, &ptr->ar));
491 ptr->next = D2DRecords;
492 D2DRecords = ptr;
493 }
494 else
495 LogMsg("xD2DAddToCache: Unexpected result %d", result);
496 }
497
498 mDNSlocal ARListElem * xD2DFindInList(mDNS *const m, const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize)
499 {
500 ARListElem *ptr = D2DRecords;
501 ARListElem *arptr;
502
503 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; }
504
505 arptr = mDNSPlatformMemAllocate(sizeof(ARListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
506 if (arptr == NULL) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL; }
507
508 if (xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr->ar) != mStatus_NoError)
509 {
510 LogMsg("xD2DFindInList: xD2DParse failed for key: %p (%u) value: %p (%u)", key, keySize, value, valueSize);
511 mDNSPlatformMemFree(arptr);
512 return NULL;
513 }
514
515 while (ptr)
516 {
517 if (IdenticalResourceRecord(&arptr->ar.resrec, &ptr->ar.resrec)) break;
518 ptr = ptr->next;
519 }
520
521 if (!ptr) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(m, &arptr->ar));
522 mDNSPlatformMemFree(arptr);
523 return ptr;
524 }
525
526 mDNSlocal void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
527 {
528 (void)transportType; // We don't care about this, yet.
529 (void)instanceHandle; // We don't care about this, yet.
530
531 if (result == kD2DSuccess)
532 {
533 ARListElem *ptr = xD2DFindInList(m, key, keySize, value, valueSize);
534 if (ptr)
535 {
536 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m, &ptr->ar));
537 mDNS_Deregister(m, &ptr->ar);
538 }
539 }
540 else
541 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result);
542 }
543
544 mDNSlocal void xD2DServiceResolved(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
545 {
546 (void)m;
547 (void)key;
548 (void)keySize;
549 (void)value;
550 (void)valueSize;
551
552 if (result == kD2DSuccess)
553 {
554 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle);
555 CHECK_D2D_FUNCTION(D2DRetain) D2DRetain(instanceHandle, transportType);
556 }
557 else LogMsg("xD2DServiceResolved: Unexpected result %d", result);
558 }
559
560 mDNSlocal void xD2DRetainHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
561 {
562 (void)m;
563 (void)instanceHandle;
564 (void)transportType;
565 (void)key;
566 (void)keySize;
567 (void)value;
568 (void)valueSize;
569
570 if (result == kD2DSuccess) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle);
571 else LogMsg("xD2DRetainHappened: Unexpected result %d", result);
572 }
573
574 mDNSlocal void xD2DReleaseHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
575 {
576 (void)m;
577 (void)instanceHandle;
578 (void)transportType;
579 (void)key;
580 (void)keySize;
581 (void)value;
582 (void)valueSize;
583
584 if (result == kD2DSuccess) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle);
585 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result);
586 }
587
588 mDNSlocal void xD2DServiceCallback(D2DServiceEvent event, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize, void *userData)
589 {
590 mDNS *m = (mDNS *) userData;
591 const char *eventString = "unknown";
592
593 KQueueLock(m);
594
595 if (keySize > 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize);
596 if (valueSize > 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize);
597
598 switch (event)
599 {
600 case D2DServiceFound:
601 eventString = "D2DServiceFound";
602 break;
603 case D2DServiceLost:
604 eventString = "D2DServiceLost";
605 break;
606 case D2DServiceResolved:
607 eventString = "D2DServiceResolved";
608 break;
609 case D2DServiceRetained:
610 eventString = "D2DServiceRetained";
611 break;
612 case D2DServiceReleased:
613 eventString = "D2DServiceReleased";
614 break;
615 default:
616 break;
617 }
618
619 LogInfo("xD2DServiceCallback: event=%s result=%d instanceHandle=%p transportType=%d LHS=%p (%u) RHS=%p (%u) userData=%p", eventString, result, instanceHandle, transportType, key, keySize, value, valueSize, userData);
620 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
621
622 switch (event)
623 {
624 case D2DServiceFound:
625 xD2DAddToCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
626 break;
627 case D2DServiceLost:
628 xD2DRemoveFromCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
629 break;
630 case D2DServiceResolved:
631 xD2DServiceResolved(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
632 break;
633 case D2DServiceRetained:
634 xD2DRetainHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
635 break;
636 case D2DServiceReleased:
637 xD2DReleaseHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
638 break;
639 default:
640 break;
641 }
642
643 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
644 KQueueUnlock(m, "xD2DServiceCallback");
645 }
646
647 mDNSexport void external_start_browsing_for_service(mDNS *const m, const domainname *const typeDomain, DNS_TypeValues qtype)
648 {
649 (void)m;
650 domainname lower;
651
652 if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
653 {
654 LogInfo("external_start_browsing_for_service: ignoring address record");
655 return;
656 }
657
658 DomainnameToLower(typeDomain, &lower);
659
660 if (!D2DBrowseListRefCount(&lower, qtype))
661 {
662 LogInfo("external_start_browsing_for_service: Starting browse for: %##s %s", lower.c, DNSTypeName(qtype));
663 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
664 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
665 CHECK_D2D_FUNCTION(D2DStartBrowsingForKey) D2DStartBrowsingForKey(compression_lhs, end - compression_lhs);
666 }
667 D2DBrowseListRetain(&lower, qtype);
668 }
669
670 mDNSexport void external_stop_browsing_for_service(mDNS *const m, const domainname *const typeDomain, DNS_TypeValues qtype)
671 {
672 domainname lower;
673
674 if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
675 {
676 LogInfo("external_stop_browsing_for_service: ignoring address record");
677 return;
678 }
679
680 DomainnameToLower(typeDomain, &lower);
681
682 D2DBrowseListRelease(&lower, qtype);
683 if (!D2DBrowseListRefCount(&lower, qtype))
684 {
685 LogInfo("external_stop_browsing_for_service: Stopping browse for: %##s %s", lower.c, DNSTypeName(qtype));
686 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
687 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
688 CHECK_D2D_FUNCTION(D2DStopBrowsingForKey) D2DStopBrowsingForKey(compression_lhs, end - compression_lhs);
689 xD2DClearCache(m, &lower);
690 }
691 }
692
693 mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord)
694 {
695 domainname lower;
696 mDNSu8 *rhs = NULL;
697 mDNSu8 *end = NULL;
698 DomainnameToLower(resourceRecord->name, &lower);
699
700 LogInfo("external_start_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
701 if (resourceRecord->rrtype == kDNSServiceType_A || resourceRecord->rrtype == kDNSServiceType_AAAA)
702 {
703 LogInfo("external_start_advertising_service: ignoring address record");
704 return;
705 }
706 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
707 end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
708 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
709 CHECK_D2D_FUNCTION(D2DStartAdvertisingPair) D2DStartAdvertisingPair(compression_lhs, rhs - compression_lhs, rhs, end - rhs);
710 }
711
712 mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord)
713 {
714 domainname lower;
715 mDNSu8 *rhs = NULL;
716 mDNSu8 *end = NULL;
717 DomainnameToLower(resourceRecord->name, &lower);
718
719 LogInfo("external_stop_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
720 if (resourceRecord->rrtype == kDNSServiceType_A || resourceRecord->rrtype == kDNSServiceType_AAAA)
721 {
722 LogInfo("external_stop_advertising_service: ignoring address record");
723 return;
724 }
725 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
726 end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
727 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
728 CHECK_D2D_FUNCTION(D2DStopAdvertisingPair) D2DStopAdvertisingPair(compression_lhs, rhs - compression_lhs, rhs, end - rhs);
729 }
730
731 mDNSexport void external_start_resolving_service(const domainname *const fqdn)
732 {
733 domainname lower;
734 mDNSu8 *rhs = NULL;
735 mDNSu8 *end = NULL;
736 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
737
738 LogInfo("external_start_resolving_service: %##s", fqdn->c);
739 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
740 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
741 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
742 CHECK_D2D_FUNCTION(D2DStartResolvingPair) D2DStartResolvingPair(compression_lhs, rhs - compression_lhs, rhs, end - rhs);
743 }
744
745 mDNSexport void external_stop_resolving_service(const domainname *const fqdn)
746 {
747 domainname lower;
748 mDNSu8 *rhs = NULL;
749 mDNSu8 *end = NULL;
750 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
751
752 LogInfo("external_stop_resolving_service: %##s", fqdn->c);
753 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
754 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
755 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
756 CHECK_D2D_FUNCTION(D2DStopResolvingPair) D2DStopResolvingPair(compression_lhs, rhs - compression_lhs, rhs, end - rhs);
757 }
758
759 #elif APPLE_OSX_mDNSResponder
760
761 mDNSexport void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype) { (void)m; (void)type; (void)qtype; }
762 mDNSexport void external_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype) { (void)m; (void)type; (void)qtype; }
763 mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord) { (void)resourceRecord; }
764 mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord) { (void)resourceRecord; }
765 mDNSexport void external_start_resolving_service(const domainname *const fqdn) { (void)fqdn; }
766 mDNSexport void external_stop_resolving_service(const domainname *const fqdn) { (void)fqdn; }
767
768 #endif // ! NO_D2D
769
770 // ***************************************************************************
771 // Functions
772
773 #if COMPILER_LIKES_PRAGMA_MARK
774 #pragma mark -
775 #pragma mark - Utility Functions
776 #endif
777
778 // We only attempt to send and receive multicast packets on interfaces that are
779 // (a) flagged as multicast-capable
780 // (b) *not* flagged as point-to-point (e.g. modem)
781 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
782 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
783 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
784 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
785
786 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
787 {
788 static int notifyCount = 0;
789 if (notifyCount) return;
790
791 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
792 // To avoid this, we don't try to display alerts in the first three minutes after boot.
793 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
794
795 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
796 #if !ForceAlerts
797 {
798 // Determine if we're at Apple (17.*.*.*)
799 extern mDNS mDNSStorage;
800 NetworkInterfaceInfoOSX *i;
801 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
802 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
803 break;
804 if (!i) return; // If not at Apple, don't show the alert
805 }
806 #endif
807
808 LogMsg("%s", title);
809 LogMsg("%s", msg);
810 // Display a notification to the user
811 notifyCount++;
812
813 #ifndef NO_CFUSERNOTIFICATION
814 mDNSNotify(title, msg);
815 #endif /* NO_CFUSERNOTIFICATION */
816 }
817
818 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
819 {
820 static struct ifaddrs *ifa = NULL;
821
822 if (refresh && ifa)
823 {
824 freeifaddrs(ifa);
825 ifa = NULL;
826 }
827
828 if (ifa == NULL) getifaddrs(&ifa);
829
830 return ifa;
831 }
832
833 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
834 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
835 {
836 NetworkInterfaceInfoOSX *i;
837 for (i = m->p->InterfaceList; i; i = i->next)
838 if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
839 ((type == AF_UNSPEC ) ||
840 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
841 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
842 return(NULL);
843 }
844
845 mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
846 {
847 struct ifaddrs *ifa;
848 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
849 if (ifa->ifa_addr->sa_family == AF_LINK)
850 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
851 { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
852 return -1;
853 }
854
855 mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex)
856 {
857 mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
858 NetworkInterfaceInfoOSX *i;
859
860 // Don't get tricked by inactive interfaces
861 for (i = m->p->InterfaceList; i; i = i->next)
862 if (i->Registered && i->scope_id == scope_id) return(i);
863
864 return mDNSNULL;
865 }
866
867 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
868 {
869 if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
870 if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
871 if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
872
873 NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
874 if (!ifi)
875 {
876 // Not found. Make sure our interface list is up to date, then try again.
877 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
878 mDNSMacOSXNetworkChanged(m);
879 ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
880 }
881
882 if (!ifi) return(mDNSNULL);
883
884 return(ifi->ifinfo.InterfaceID);
885 }
886
887
888 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
889 {
890 NetworkInterfaceInfoOSX *i;
891 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
892 if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
893 if (id == mDNSInterface_Any ) return(0);
894
895 mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
896
897 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
898 for (i = m->p->InterfaceList; i; i = i->next)
899 if (i->scope_id == scope_id) return(i->scope_id);
900
901 // Not found. Make sure our interface list is up to date, then try again.
902 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
903 mDNSMacOSXNetworkChanged(m);
904 for (i = m->p->InterfaceList; i; i = i->next)
905 if (i->scope_id == scope_id) return(i->scope_id);
906
907 return(0);
908 }
909
910 #if APPLE_OSX_mDNSResponder
911 mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...)
912 {
913 if (OSXVers < OSXVers_10_6_SnowLeopard) return;
914
915 static char buffer[512];
916 aslmsg asl_msg = asl_new(ASL_TYPE_MSG);
917
918 if (!asl_msg) { LogMsg("mDNSASLLog: asl_new failed"); return; }
919 if (uuid)
920 {
921 char uuidStr[37];
922 uuid_unparse(*uuid, uuidStr);
923 asl_set (asl_msg, "com.apple.message.uuid", uuidStr);
924 }
925
926 static char domainBase[] = "com.apple.mDNSResponder.%s";
927 mDNS_snprintf (buffer, sizeof(buffer), domainBase, subdomain);
928 asl_set (asl_msg, "com.apple.message.domain", buffer);
929
930 if (result) asl_set(asl_msg, "com.apple.message.result", result);
931 if (signature) asl_set(asl_msg, "com.apple.message.signature", signature);
932
933 va_list ptr;
934 va_start(ptr,fmt);
935 mDNS_vsnprintf(buffer, sizeof(buffer), fmt, ptr);
936 va_end(ptr);
937
938 int old_filter = asl_set_filter(NULL,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
939 asl_log(NULL, asl_msg, ASL_LEVEL_DEBUG, "%s", buffer);
940 asl_set_filter(NULL, old_filter);
941 asl_free(asl_msg);
942 }
943 #endif // APPLE_OSX_mDNSResponder
944
945 #if COMPILER_LIKES_PRAGMA_MARK
946 #pragma mark -
947 #pragma mark - UDP & TCP send & receive
948 #endif
949
950 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
951 {
952 mDNSBool result = mDNSfalse;
953 SCNetworkConnectionFlags flags;
954 SCNetworkReachabilityRef ReachRef = NULL;
955
956 ReachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, addr);
957 if (!ReachRef) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end; }
958 if (!SCNetworkReachabilityGetFlags(ReachRef, &flags)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end; }
959 result = flags & kSCNetworkFlagsConnectionRequired;
960
961 end:
962 if (ReachRef) CFRelease(ReachRef);
963 return result;
964 }
965
966 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
967 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
968 // OR send via our primary v4 unicast socket
969 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
970 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
971 mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstPort)
972 {
973 NetworkInterfaceInfoOSX *info = mDNSNULL;
974 struct sockaddr_storage to;
975 int s = -1, err;
976 mStatus result = mStatus_NoError;
977
978 if (InterfaceID)
979 {
980 info = IfindexToInterfaceInfoOSX(m, InterfaceID);
981 if (info == NULL)
982 {
983 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
984 return mStatus_BadParamErr;
985 }
986 }
987
988 char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
989
990 if (dst->type == mDNSAddrType_IPv4)
991 {
992 struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
993 sin_to->sin_len = sizeof(*sin_to);
994 sin_to->sin_family = AF_INET;
995 sin_to->sin_port = dstPort.NotAnInteger;
996 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
997 s = (src ? src->ss : m->p->permanentsockets).sktv4;
998
999 if (info) // Specify outgoing interface
1000 {
1001 if (!mDNSAddrIsDNSMulticast(dst))
1002 {
1003 #ifdef IP_BOUND_IF
1004 if (info->scope_id == 0)
1005 LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
1006 else
1007 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1008 #else
1009 {
1010 static int displayed = 0;
1011 if (displayed < 1000)
1012 {
1013 displayed++;
1014 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
1015 }
1016 }
1017 #endif
1018 }
1019 else
1020 #ifdef IP_MULTICAST_IFINDEX
1021 {
1022 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IFINDEX, &info->scope_id, sizeof(info->scope_id));
1023 // We get an error when we compile on a machine that supports this option and run the binary on
1024 // a different machine that does not support it
1025 if (err < 0)
1026 {
1027 if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno);
1028 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
1029 if (err < 0 && !m->p->NetworkChanged)
1030 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
1031 }
1032 }
1033 #else
1034 {
1035 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
1036 if (err < 0 && !m->p->NetworkChanged)
1037 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
1038
1039 }
1040 #endif
1041 }
1042 }
1043 #ifndef NO_IPV6
1044 else if (dst->type == mDNSAddrType_IPv6)
1045 {
1046 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
1047 sin6_to->sin6_len = sizeof(*sin6_to);
1048 sin6_to->sin6_family = AF_INET6;
1049 sin6_to->sin6_port = dstPort.NotAnInteger;
1050 sin6_to->sin6_flowinfo = 0;
1051 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
1052 sin6_to->sin6_scope_id = info ? info->scope_id : 0;
1053 s = (src ? src->ss : m->p->permanentsockets).sktv6;
1054 if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
1055 {
1056 err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
1057 if (err < 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno));
1058 }
1059 }
1060 #endif
1061 else
1062 {
1063 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1064 #if ForceAlerts
1065 *(long*)0 = 0;
1066 #endif
1067 return mStatus_BadParamErr;
1068 }
1069
1070 if (s >= 0)
1071 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1072 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
1073 else
1074 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1075 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
1076
1077 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1078 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1079 if (s < 0) return(mStatus_Invalid);
1080
1081 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
1082 if (err < 0)
1083 {
1084 static int MessageCount = 0;
1085 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1086 if (!mDNSAddressIsAllDNSLinkGroup(dst))
1087 if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
1088 // Don't report EHOSTUNREACH in the first three minutes after boot
1089 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1090 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1091 if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
1092 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1093 if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr);
1094 if (MessageCount < 1000)
1095 {
1096 MessageCount++;
1097 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
1098 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1099 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
1100 else
1101 LogMsg("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1102 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
1103 }
1104 result = mStatus_UnknownErr;
1105 }
1106
1107 #ifdef IP_BOUND_IF
1108 if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
1109 {
1110 static const mDNSu32 ifindex = 0;
1111 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
1112 }
1113 #endif
1114
1115 return(result);
1116 }
1117
1118 mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
1119 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
1120 {
1121 static unsigned int numLogMessages = 0;
1122 struct iovec databuffers = { (char *)buffer, max };
1123 struct msghdr msg;
1124 ssize_t n;
1125 struct cmsghdr *cmPtr;
1126 char ancillary[1024];
1127
1128 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1129
1130 // Set up the message
1131 msg.msg_name = (caddr_t)from;
1132 msg.msg_namelen = *fromlen;
1133 msg.msg_iov = &databuffers;
1134 msg.msg_iovlen = 1;
1135 msg.msg_control = (caddr_t)&ancillary;
1136 msg.msg_controllen = sizeof(ancillary);
1137 msg.msg_flags = 0;
1138
1139 // Receive the data
1140 n = recvmsg(s, &msg, 0);
1141 if (n<0)
1142 {
1143 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
1144 return(-1);
1145 }
1146 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
1147 {
1148 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1149 s, n, msg.msg_controllen, sizeof(struct cmsghdr));
1150 return(-1);
1151 }
1152 if (msg.msg_flags & MSG_CTRUNC)
1153 {
1154 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
1155 return(-1);
1156 }
1157
1158 *fromlen = msg.msg_namelen;
1159
1160 // Parse each option out of the ancillary data.
1161 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
1162 {
1163 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1164 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
1165 {
1166 dstaddr->type = mDNSAddrType_IPv4;
1167 dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
1168 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
1169 }
1170 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
1171 {
1172 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
1173 if (sdl->sdl_nlen < IF_NAMESIZE)
1174 {
1175 mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
1176 ifname[sdl->sdl_nlen] = 0;
1177 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1178 }
1179 }
1180 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
1181 *ttl = *(u_char*)CMSG_DATA(cmPtr);
1182 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
1183 {
1184 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
1185 dstaddr->type = mDNSAddrType_IPv6;
1186 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
1187 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
1188 }
1189 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
1190 *ttl = *(int*)CMSG_DATA(cmPtr);
1191 }
1192
1193 return(n);
1194 }
1195
1196 mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
1197 {
1198 KQSocketSet *const ss = (KQSocketSet *)context;
1199 mDNS *const m = ss->m;
1200 int err = 0, count = 0, closed = 0;
1201
1202 if (filter != EVFILT_READ)
1203 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
1204
1205 if (s1 != ss->sktv4
1206 #ifndef NO_IPV6
1207 && s1 != ss->sktv6
1208 #endif
1209 )
1210 {
1211 LogMsg("myKQSocketCallBack: native socket %d", s1);
1212 LogMsg("myKQSocketCallBack: sktv4 %d", ss->sktv4);
1213 #ifndef NO_IPV6
1214 LogMsg("myKQSocketCallBack: sktv6 %d", ss->sktv6);
1215 #endif
1216 }
1217
1218 while (!closed)
1219 {
1220 mDNSAddr senderAddr, destAddr;
1221 mDNSIPPort senderPort;
1222 struct sockaddr_storage from;
1223 size_t fromlen = sizeof(from);
1224 char packetifname[IF_NAMESIZE] = "";
1225 mDNSu8 ttl;
1226 err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
1227 if (err < 0) break;
1228
1229 count++;
1230 if (from.ss_family == AF_INET)
1231 {
1232 struct sockaddr_in *s = (struct sockaddr_in*)&from;
1233 senderAddr.type = mDNSAddrType_IPv4;
1234 senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
1235 senderPort.NotAnInteger = s->sin_port;
1236 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1237 }
1238 else if (from.ss_family == AF_INET6)
1239 {
1240 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
1241 senderAddr.type = mDNSAddrType_IPv6;
1242 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
1243 senderPort.NotAnInteger = sin6->sin6_port;
1244 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1245 }
1246 else
1247 {
1248 LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
1249 return;
1250 }
1251
1252 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1253 mDNSInterfaceID InterfaceID = mDNSNULL;
1254 //NetworkInterfaceInfo *intf = m->HostInterfaces;
1255 //while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
1256
1257 NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
1258 while (intf && strcmp(intf->ifinfo.ifname, packetifname)) intf = intf->next;
1259
1260 // When going to sleep we deregister all our interfaces, but if the machine
1261 // takes a few seconds to sleep we may continue to receive multicasts
1262 // during that time, which would confuse mDNSCoreReceive, because as far
1263 // as it's concerned, we should have no active interfaces any more.
1264 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1265 if (intf) InterfaceID = intf->ifinfo.InterfaceID;
1266 else if (mDNSAddrIsDNSMulticast(&destAddr)) continue;
1267
1268 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1269 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
1270
1271 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
1272 // loop when that happens, or we may try to read from an invalid FD. We do this by
1273 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
1274 // if it closes the socketset.
1275 ss->closeFlag = &closed;
1276
1277 mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
1278
1279 // if we didn't close, we can safely dereference the socketset, and should to
1280 // reset the closeFlag, since it points to something on the stack
1281 if (!closed) ss->closeFlag = mDNSNULL;
1282 }
1283
1284 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
1285 {
1286 // Something is busted here.
1287 // kqueue says there is a packet, but myrecvfrom says there is not.
1288 // Try calling select() to get another opinion.
1289 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1290 // All of this is racy, as data may have arrived after the call to select()
1291 static unsigned int numLogMessages = 0;
1292 int save_errno = errno;
1293 int so_error = -1;
1294 int so_nread = -1;
1295 int fionread = -1;
1296 socklen_t solen = sizeof(int);
1297 fd_set readfds;
1298 struct timeval timeout;
1299 int selectresult;
1300 FD_ZERO(&readfds);
1301 FD_SET(s1, &readfds);
1302 timeout.tv_sec = 0;
1303 timeout.tv_usec = 0;
1304 selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
1305 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
1306 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
1307 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
1308 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
1309 if (ioctl(s1, FIONREAD, &fionread) == -1)
1310 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
1311 if (numLogMessages++ < 100)
1312 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1313 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
1314 if (numLogMessages > 5)
1315 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1316 "Congratulations, you've reproduced an elusive bug.\r"
1317 "Please contact the current assignee of <rdar://problem/3375328>.\r"
1318 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1319 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1320
1321 sleep(1); // After logging this error, rate limit so we don't flood syslog
1322 }
1323 }
1324
1325 // TCP socket support
1326
1327 typedef enum
1328 {
1329 handshake_required,
1330 handshake_in_progress,
1331 handshake_completed,
1332 handshake_to_be_closed
1333 } handshakeStatus;
1334
1335 struct TCPSocket_struct
1336 {
1337 TCPSocketFlags flags; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
1338 TCPConnectionCallback callback;
1339 int fd;
1340 KQueueEntry *kqEntry;
1341 KQSocketSet ss;
1342 #ifndef NO_SECURITYFRAMEWORK
1343 SSLContextRef tlsContext;
1344 pthread_t handshake_thread;
1345 #endif /* NO_SECURITYFRAMEWORK */
1346 domainname hostname;
1347 void *context;
1348 mDNSBool setup;
1349 mDNSBool connected;
1350 handshakeStatus handshake;
1351 mDNS *m; // So we can call KQueueLock from the SSLHandshake thread
1352 mStatus err;
1353 };
1354
1355 mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
1356 {
1357 mDNSBool c = !sock->connected;
1358 sock->connected = mDNStrue;
1359 sock->callback(sock, sock->context, c, sock->err);
1360 // Note: the callback may call CloseConnection here, which frees the context structure!
1361 }
1362
1363 #ifndef NO_SECURITYFRAMEWORK
1364
1365 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
1366 {
1367 int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1368 if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1369 if (ret >= 0) { *dataLength = ret; return(noErr); }
1370 *dataLength = 0;
1371 if (errno == EAGAIN ) return(errSSLWouldBlock);
1372 if (errno == ENOENT ) return(errSSLClosedGraceful);
1373 if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
1374 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
1375 return(errSSLClosedAbort);
1376 }
1377
1378 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
1379 {
1380 int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1381 if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1382 if (ret > 0) { *dataLength = ret; return(noErr); }
1383 *dataLength = 0;
1384 if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
1385 if ( errno == EAGAIN ) return(errSSLWouldBlock);
1386 if ( errno == ECONNRESET) return(errSSLClosedAbort);
1387 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
1388 return(errSSLClosedAbort);
1389 }
1390
1391 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, mDNSBool server)
1392 {
1393 char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
1394
1395 mStatus err = SSLNewContext(server, &sock->tlsContext);
1396 if (err) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err); return(err); }
1397
1398 err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
1399 if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err); return(err); }
1400
1401 err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
1402 if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err); return(err); }
1403
1404 // Instead of listing all the acceptable ciphers, we just disable the bad ciphers. It does not disable
1405 // all the bad ciphers like RC4_MD5, but it assumes that the servers don't offer them.
1406 err = SSLSetAllowAnonymousCiphers(sock->tlsContext, 0);
1407 if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err); return(err); }
1408
1409 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
1410 // (error not in OSStatus space) is okay.
1411 if (!sock->hostname.c[0]) {LogMsg("ERROR: tlsSetupSock: hostname NULL"); return -1; }
1412
1413 ConvertDomainNameToCString(&sock->hostname, domname_cstr);
1414 err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
1415 if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err); return(err); }
1416
1417 return(err);
1418 }
1419
1420 #ifdef __LIB_DISPATCH__
1421 mDNSlocal void doSSLHandshake(void *ctx)
1422 {
1423 TCPSocket *sock = (TCPSocket*)ctx;
1424 mStatus err = SSLHandshake(sock->tlsContext);
1425
1426 //Can't have multiple threads in mDNS core. When __LIB_DISPATCH__ is
1427 //defined, KQueueLock is a noop. Hence we need to serialize here
1428 //
1429 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
1430 //We need the rest of the logic also. Otherwise, we can enable the READ
1431 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
1432 //ConnFailed which means we are going to free the tcpInfo. While it
1433 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
1434 //and potentially call doTCPCallback with error which can close the fd and free the
1435 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
1436 //is already freed.
1437
1438 dispatch_async(dispatch_get_main_queue(), ^{
1439
1440 LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1441
1442 if (sock->handshake == handshake_to_be_closed)
1443 {
1444 LogInfo("SSLHandshake completed after close");
1445 mDNSPlatformTCPCloseConnection(sock);
1446 }
1447 else
1448 {
1449 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1450 else LogMsg("doSSLHandshake: sock->fd is -1");
1451
1452 if (err == errSSLWouldBlock)
1453 sock->handshake = handshake_required;
1454 else
1455 {
1456 if (err)
1457 {
1458 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1459 SSLDisposeContext(sock->tlsContext);
1460 sock->tlsContext = NULL;
1461 }
1462
1463 sock->err = err ? mStatus_ConnFailed : 0;
1464 sock->handshake = handshake_completed;
1465
1466 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1467 doTcpSocketCallback(sock);
1468 }
1469 }
1470
1471 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1472 return;
1473 });
1474 }
1475 #else
1476 mDNSlocal void *doSSLHandshake(void *ctx)
1477 {
1478 // Warning: Touching sock without the kqueue lock!
1479 // We're protected because sock->handshake == handshake_in_progress
1480 TCPSocket *sock = (TCPSocket*)ctx;
1481 mDNS * const m = sock->m; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
1482 mStatus err = SSLHandshake(sock->tlsContext);
1483
1484 KQueueLock(m);
1485 debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1486
1487 if (sock->handshake == handshake_to_be_closed)
1488 {
1489 LogInfo("SSLHandshake completed after close");
1490 mDNSPlatformTCPCloseConnection(sock);
1491 }
1492 else
1493 {
1494 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1495 else LogMsg("doSSLHandshake: sock->fd is -1");
1496
1497 if (err == errSSLWouldBlock)
1498 sock->handshake = handshake_required;
1499 else
1500 {
1501 if (err)
1502 {
1503 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1504 SSLDisposeContext(sock->tlsContext);
1505 sock->tlsContext = NULL;
1506 }
1507
1508 sock->err = err ? mStatus_ConnFailed : 0;
1509 sock->handshake = handshake_completed;
1510
1511 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1512 doTcpSocketCallback(sock);
1513 }
1514 }
1515
1516 debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1517 KQueueUnlock(m, "doSSLHandshake");
1518 return NULL;
1519 }
1520 #endif
1521
1522 mDNSlocal mStatus spawnSSLHandshake(TCPSocket* sock)
1523 {
1524 debugf("spawnSSLHandshake %p: entry", sock);
1525 mStatus err;
1526
1527 if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
1528 sock->handshake = handshake_in_progress;
1529 KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
1530 #ifdef __LIB_DISPATCH__
1531
1532 // Dispatch it on a separate serial queue to avoid deadlocks with threads running on main queue
1533 dispatch_async(SSLqueue, ^{doSSLHandshake(sock);});
1534 err = 0;
1535 #else
1536 pthread_attr_t attr;
1537 pthread_attr_init(&attr);
1538 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1539 err = pthread_create(&sock->handshake_thread, &attr, doSSLHandshake, sock);
1540 pthread_attr_destroy(&attr);
1541 if (err)
1542 {
1543 LogMsg("Could not start SSLHandshake thread: (%d) %s", err, strerror(err));
1544 sock->handshake = handshake_completed;
1545 sock->err = err;
1546 KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1547 }
1548 #endif
1549 debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
1550 return err;
1551 }
1552
1553 mDNSlocal mDNSBool IsTunnelModeDomain(const domainname *d)
1554 {
1555 static const domainname *mmc = (const domainname*) "\x7" "members" "\x3" "mac" "\x3" "com";
1556 const domainname *d1 = mDNSNULL; // TLD
1557 const domainname *d2 = mDNSNULL; // SLD
1558 const domainname *d3 = mDNSNULL;
1559 while (d->c[0]) { d3 = d2; d2 = d1; d1 = d; d = (const domainname*)(d->c + 1 + d->c[0]); }
1560 return(d3 && SameDomainName(d3, mmc));
1561 }
1562
1563 #endif /* NO_SECURITYFRAMEWORK */
1564
1565 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
1566 {
1567 TCPSocket *sock = context;
1568 sock->err = mStatus_NoError;
1569
1570 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1571 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1572 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1573 if (filter == EVFILT_WRITE) KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
1574
1575 if (sock->flags & kTCPSocketFlags_UseTLS)
1576 {
1577 #ifndef NO_SECURITYFRAMEWORK
1578 if (!sock->setup) { sock->setup = mDNStrue; tlsSetupSock(sock, mDNSfalse); }
1579
1580 if (sock->handshake == handshake_required) { if (spawnSSLHandshake(sock) == 0) return; }
1581 else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed) return;
1582 else if (sock->handshake != handshake_completed)
1583 {
1584 if (!sock->err) sock->err = mStatus_UnknownErr;
1585 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
1586 }
1587 #else
1588 sock->err = mStatus_UnsupportedErr;
1589 #endif /* NO_SECURITYFRAMEWORK */
1590 }
1591
1592 doTcpSocketCallback(sock);
1593 }
1594
1595 #ifdef __LIB_DISPATCH__
1596 mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef)
1597 {
1598 dispatch_queue_t queue = dispatch_get_main_queue();
1599 dispatch_source_t source;
1600 if (flags == EV_DELETE)
1601 {
1602 if (filter == EVFILT_READ)
1603 {
1604 dispatch_source_cancel(entryRef->readSource);
1605 dispatch_release(entryRef->readSource);
1606 entryRef->readSource = mDNSNULL;
1607 debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource);
1608 }
1609 else if (filter == EVFILT_WRITE)
1610 {
1611 dispatch_source_cancel(entryRef->writeSource);
1612 dispatch_release(entryRef->writeSource);
1613 entryRef->writeSource = mDNSNULL;
1614 debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource);
1615 }
1616 else
1617 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
1618 return 0;
1619 }
1620 if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
1621
1622 if (filter == EVFILT_READ)
1623 {
1624 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
1625 }
1626 else if (filter == EVFILT_WRITE)
1627 {
1628 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
1629 }
1630 else
1631 {
1632 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
1633 return -1;
1634 }
1635 if (!source) return -1;
1636 dispatch_source_set_event_handler(source, ^{
1637
1638 mDNSs32 stime = mDNSPlatformRawTime();
1639 entryRef->KQcallback(fd, filter, entryRef->KQcontext);
1640 mDNSs32 etime = mDNSPlatformRawTime();
1641 if (etime - stime >= WatchDogReportingThreshold)
1642 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime);
1643
1644 // Trigger the event delivery to the application. Even though we trigger the
1645 // event completion after handling every event source, these all will hopefully
1646 // get merged
1647 TriggerEventCompletion();
1648
1649 });
1650 dispatch_source_set_cancel_handler(source, ^{
1651 if (entryRef->fdClosed)
1652 {
1653 //LogMsg("CancelHandler: closing fd %d", fd);
1654 close(fd);
1655 }
1656 });
1657 dispatch_resume(source);
1658 if (filter == EVFILT_READ)
1659 entryRef->readSource = source;
1660 else
1661 entryRef->writeSource = source;
1662
1663 return 0;
1664 }
1665
1666 mDNSexport void KQueueLock(mDNS *const m)
1667 {
1668 (void)m; //unused
1669 }
1670 mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
1671 {
1672 (void)m; //unused
1673 (void)task; //unused
1674 }
1675 #else
1676 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
1677 {
1678 struct kevent new_event;
1679 EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
1680 return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
1681 }
1682
1683 mDNSexport void KQueueLock(mDNS *const m)
1684 {
1685 pthread_mutex_lock(&m->p->BigMutex);
1686 m->p->BigMutexStartTime = mDNSPlatformRawTime();
1687 }
1688
1689 mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
1690 {
1691 mDNSs32 end = mDNSPlatformRawTime();
1692 (void)task;
1693 if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
1694 LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
1695
1696 pthread_mutex_unlock(&m->p->BigMutex);
1697
1698 char wake = 1;
1699 if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
1700 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
1701 }
1702 #endif
1703
1704 mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
1705 {
1706 #ifdef __LIB_DISPATCH__
1707 (void)fd; //unused
1708 if (kq->readSource)
1709 {
1710 dispatch_source_cancel(kq->readSource);
1711 kq->readSource = mDNSNULL;
1712 }
1713 if (kq->writeSource)
1714 {
1715 dispatch_source_cancel(kq->writeSource);
1716 kq->writeSource = mDNSNULL;
1717 }
1718 // Close happens in the cancellation handler
1719 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
1720 kq->fdClosed = mDNStrue;
1721 #else
1722 (void)kq; //unused
1723 close(fd);
1724 #endif
1725 }
1726
1727 mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port)
1728 {
1729 KQSocketSet *cp = &sock->ss;
1730 #ifndef NO_IPV6
1731 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
1732 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
1733 #else
1734 int *s = &cp->sktv4;
1735 KQueueEntry *k = &cp->kqsv4;
1736 #endif
1737 const int on = 1; // "on" for setsockopt
1738 mStatus err;
1739
1740 int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
1741 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
1742 if (sa_family == AF_INET)
1743 {
1744 // Bind it
1745 struct sockaddr_in addr;
1746 mDNSPlatformMemZero(&addr, sizeof(addr));
1747 addr.sin_family = AF_INET;
1748 addr.sin_port = port->NotAnInteger;
1749 err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
1750 if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); return err; }
1751
1752 // Receive interface identifiers
1753 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
1754 if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); return err; }
1755
1756 mDNSPlatformMemZero(&addr, sizeof(addr));
1757 socklen_t len = sizeof(addr);
1758 err = getsockname(skt, (struct sockaddr*) &addr, &len);
1759 if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); return err; }
1760
1761 port->NotAnInteger = addr.sin_port;
1762 }
1763 else
1764 {
1765 // Bind it
1766 struct sockaddr_in6 addr6;
1767 mDNSPlatformMemZero(&addr6, sizeof(addr6));
1768 addr6.sin6_family = AF_INET6;
1769 addr6.sin6_port = port->NotAnInteger;
1770 err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
1771 if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); return err; }
1772
1773 // We want to receive destination addresses and receive interface identifiers
1774 err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
1775 if (err < 0) { LogMsg("ERROR: setsockopt IPV6_PKTINFO %s", strerror(errno)); return err; }
1776
1777 mDNSPlatformMemZero(&addr6, sizeof(addr6));
1778 socklen_t len = sizeof(addr6);
1779 err = getsockname(skt, (struct sockaddr *) &addr6, &len);
1780 if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); return err; }
1781
1782 port->NotAnInteger = addr6.sin6_port;
1783
1784 }
1785 *s = skt;
1786 k->KQcallback = tcpKQSocketCallback;
1787 k->KQcontext = sock;
1788 k->KQtask = "mDNSPlatformTCPSocket";
1789 #ifdef __LIB_DISPATCH__
1790 k->readSource = mDNSNULL;
1791 k->writeSource = mDNSNULL;
1792 k->fdClosed = mDNSfalse;
1793 #endif
1794 return mStatus_NoError;
1795 }
1796
1797 mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port)
1798 {
1799 mStatus err;
1800 (void) m;
1801
1802 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
1803 if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
1804
1805 mDNSPlatformMemZero(sock, sizeof(TCPSocket));
1806
1807 sock->ss.m = m;
1808 sock->ss.sktv4 = -1;
1809 #ifndef NO_IPV6
1810 sock->ss.sktv6 = -1;
1811 #endif
1812 err = SetupTCPSocket(sock, AF_INET, port);
1813 #ifndef NO_IPV6
1814 if (!err)
1815 {
1816 err = SetupTCPSocket(sock, AF_INET6, port);
1817 if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
1818 }
1819 #endif
1820 if (err)
1821 {
1822 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
1823 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
1824 return(mDNSNULL);
1825 }
1826
1827 sock->callback = mDNSNULL;
1828 sock->flags = flags;
1829 sock->context = mDNSNULL;
1830 sock->setup = mDNSfalse;
1831 sock->connected = mDNSfalse;
1832 sock->handshake = handshake_required;
1833 sock->m = m;
1834 sock->err = mStatus_NoError;
1835
1836 return sock;
1837 }
1838
1839 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
1840 {
1841 KQSocketSet *cp = &sock->ss;
1842 #ifndef NO_IPV6
1843 int *s = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
1844 KQueueEntry *k = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
1845 #else
1846 int *s = &cp->sktv4;
1847 KQueueEntry *k = &cp->kqsv4;
1848 #endif
1849 mStatus err = mStatus_NoError;
1850 struct sockaddr_storage ss;
1851
1852 sock->callback = callback;
1853 sock->context = context;
1854 sock->setup = mDNSfalse;
1855 sock->connected = mDNSfalse;
1856 sock->handshake = handshake_required;
1857 sock->err = mStatus_NoError;
1858
1859 if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
1860
1861 if (dst->type == mDNSAddrType_IPv4)
1862 {
1863 struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
1864 mDNSPlatformMemZero(saddr, sizeof(*saddr));
1865 saddr->sin_family = AF_INET;
1866 saddr->sin_port = dstport.NotAnInteger;
1867 saddr->sin_len = sizeof(*saddr);
1868 saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1869 }
1870 else
1871 {
1872 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss;
1873 mDNSPlatformMemZero(saddr6, sizeof(*saddr6));
1874 saddr6->sin6_family = AF_INET6;
1875 saddr6->sin6_port = dstport.NotAnInteger;
1876 saddr6->sin6_len = sizeof(*saddr6);
1877 saddr6->sin6_addr = *(struct in6_addr *)&dst->ip.v6;
1878 }
1879
1880 // Watch for connect complete (write is ready)
1881 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1882 if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
1883 {
1884 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1885 return errno;
1886 }
1887
1888 // Watch for incoming data
1889 if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
1890 {
1891 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1892 return errno;
1893 }
1894
1895 if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
1896 {
1897 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
1898 return mStatus_UnknownErr;
1899 }
1900
1901 // We bind to the interface and all subsequent packets including the SYN will be sent out
1902 // on this interface
1903 //
1904 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
1905 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
1906 if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
1907 {
1908 extern mDNS mDNSStorage;
1909 NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
1910 if (dst->type == mDNSAddrType_IPv4)
1911 {
1912 #ifdef IP_BOUND_IF
1913 if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1914 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
1915 #else
1916 (void)InterfaceID; // Unused
1917 (void)info; // Unused
1918 #endif
1919 }
1920 else
1921 {
1922 #ifdef IPV6_BOUND_IF
1923 if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1924 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
1925 #else
1926 (void)InterfaceID; // Unused
1927 (void)info; // Unused
1928 #endif
1929 }
1930 }
1931
1932 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
1933 // from which we can infer the destination address family. Hence we need to remember that here.
1934 // Instead of remembering the address family, we remember the right fd.
1935 sock->fd = *s;
1936 sock->kqEntry = k;
1937 // initiate connection wth peer
1938 if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
1939 {
1940 if (errno == EINPROGRESS) return mStatus_ConnPending;
1941 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
1942 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
1943 else
1944 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
1945 return mStatus_ConnFailed;
1946 }
1947
1948 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1949 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1950 return err;
1951 }
1952
1953 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1954 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
1955 {
1956 mStatus err = mStatus_NoError;
1957
1958 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
1959 if (!sock) return(mDNSNULL);
1960
1961 mDNSPlatformMemZero(sock, sizeof(*sock));
1962 sock->fd = fd;
1963 sock->flags = flags;
1964
1965 if (flags & kTCPSocketFlags_UseTLS)
1966 {
1967 #ifndef NO_SECURITYFRAMEWORK
1968 if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
1969
1970 err = tlsSetupSock(sock, mDNStrue);
1971 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
1972
1973 err = SSLSetCertificate(sock->tlsContext, ServerCerts);
1974 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
1975 #else
1976 err = mStatus_UnsupportedErr;
1977 #endif /* NO_SECURITYFRAMEWORK */
1978 }
1979 #ifndef NO_SECURITYFRAMEWORK
1980 exit:
1981 #endif
1982
1983 if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
1984 return(sock);
1985 }
1986
1987 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
1988 {
1989 if (ss->sktv4 != -1)
1990 {
1991 mDNSPlatformCloseFD(&ss->kqsv4, ss->sktv4);
1992 ss->sktv4 = -1;
1993 }
1994 #ifndef NO_IPV6
1995 if (ss->sktv6 != -1)
1996 {
1997 mDNSPlatformCloseFD(&ss->kqsv6, ss->sktv6);
1998 ss->sktv6 = -1;
1999 }
2000 #endif
2001 if (ss->closeFlag) *ss->closeFlag = 1;
2002 }
2003
2004 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
2005 {
2006 if (sock)
2007 {
2008 #ifndef NO_SECURITYFRAMEWORK
2009 if (sock->tlsContext)
2010 {
2011 if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
2012 {
2013 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
2014 sock->handshake = handshake_to_be_closed;
2015 }
2016 if (sock->handshake == handshake_to_be_closed)
2017 return;
2018
2019 SSLClose(sock->tlsContext);
2020 SSLDisposeContext(sock->tlsContext);
2021 sock->tlsContext = NULL;
2022 }
2023 #endif /* NO_SECURITYFRAMEWORK */
2024 if (sock->ss.sktv4 != -1) shutdown(sock->ss.sktv4, 2);
2025 #ifndef NO_IPV6
2026 if (sock->ss.sktv6 != -1) shutdown(sock->ss.sktv6, 2);
2027 #endif
2028 CloseSocketSet(&sock->ss);
2029 sock->fd = -1;
2030
2031 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
2032 }
2033 }
2034
2035 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
2036 {
2037 size_t nread = 0;
2038 *closed = mDNSfalse;
2039
2040 if (sock->flags & kTCPSocketFlags_UseTLS)
2041 {
2042 #ifndef NO_SECURITYFRAMEWORK
2043 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
2044 else if (sock->handshake == handshake_in_progress) return 0;
2045 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
2046
2047 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
2048 mStatus err = SSLRead(sock->tlsContext, buf, buflen, &nread);
2049 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
2050 if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
2051 else if (err && err != errSSLWouldBlock)
2052 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
2053 #else
2054 nread = -1;
2055 *closed = mDNStrue;
2056 #endif /* NO_SECURITYFRAMEWORK */
2057 }
2058 else
2059 {
2060 static int CLOSEDcount = 0;
2061 static int EAGAINcount = 0;
2062 nread = recv(sock->fd, buf, buflen, 0);
2063
2064 if (nread > 0) { CLOSEDcount = 0; EAGAINcount = 0; } // On success, clear our error counters
2065 else if (nread == 0)
2066 {
2067 *closed = mDNStrue;
2068 if ((++CLOSEDcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount); sleep(1); }
2069 }
2070 // else nread is negative -- see what kind of error we got
2071 else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
2072 else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
2073 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
2074 {
2075 nread = 0;
2076 if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
2077 }
2078 }
2079
2080 return nread;
2081 }
2082
2083 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
2084 {
2085 int nsent;
2086
2087 if (sock->flags & kTCPSocketFlags_UseTLS)
2088 {
2089 #ifndef NO_SECURITYFRAMEWORK
2090 size_t processed;
2091 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
2092 if (sock->handshake == handshake_in_progress) return 0;
2093 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
2094
2095 mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
2096
2097 if (!err) nsent = (int) processed;
2098 else if (err == errSSLWouldBlock) nsent = 0;
2099 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
2100 #else
2101 nsent = -1;
2102 #endif /* NO_SECURITYFRAMEWORK */
2103 }
2104 else
2105 {
2106 nsent = send(sock->fd, msg, len, 0);
2107 if (nsent < 0)
2108 {
2109 if (errno == EAGAIN) nsent = 0;
2110 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
2111 }
2112 }
2113
2114 return nsent;
2115 }
2116
2117 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
2118 {
2119 return sock->fd;
2120 }
2121
2122 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
2123 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
2124 mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
2125 {
2126 #ifndef NO_IPV6
2127 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
2128 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
2129 #else
2130 int *s = &cp->sktv4;
2131 KQueueEntry *k = &cp->kqsv4;
2132 #endif
2133 const int on = 1;
2134 const int twofivefive = 255;
2135 mStatus err = mStatus_NoError;
2136 char *errstr = mDNSNULL;
2137
2138 #ifdef NO_IPV6
2139 if (sa_family != AF_INET) return -1;
2140 #endif
2141
2142 cp->closeFlag = mDNSNULL;
2143
2144 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
2145 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
2146
2147 // ... with a shared UDP port, if it's for multicast receiving
2148 if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
2149 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
2150
2151 if (sa_family == AF_INET)
2152 {
2153 // We want to receive destination addresses
2154 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
2155 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
2156
2157 // We want to receive interface identifiers
2158 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
2159 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
2160
2161 // We want to receive packet TTL value so we can check it
2162 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
2163 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
2164
2165 // Send unicast packets with TTL 255
2166 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
2167 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
2168
2169 // And multicast packets with TTL 255 too
2170 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
2171 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
2172
2173 // And start listening for packets
2174 struct sockaddr_in listening_sockaddr;
2175 listening_sockaddr.sin_family = AF_INET;
2176 listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
2177 listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0;
2178 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
2179 if (err) { errstr = "bind"; goto fail; }
2180 if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
2181 }
2182 #ifndef NO_IPV6
2183 else if (sa_family == AF_INET6)
2184 {
2185 // NAT-PMP Announcements make no sense on IPv6, so bail early w/o error
2186 if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; return mStatus_NoError; }
2187
2188 // We want to receive destination addresses and receive interface identifiers
2189 err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
2190 if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; }
2191
2192 // We want to receive packet hop count value so we can check it
2193 err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
2194 if (err < 0) { errstr = "setsockopt - IPV6_HOPLIMIT"; goto fail; }
2195
2196 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
2197 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
2198 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
2199 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
2200
2201 // Send unicast packets with TTL 255
2202 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
2203 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
2204
2205 // And multicast packets with TTL 255 too
2206 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
2207 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
2208
2209 // Want to receive our own packets
2210 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
2211 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
2212
2213 // And start listening for packets
2214 struct sockaddr_in6 listening_sockaddr6;
2215 mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
2216 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
2217 listening_sockaddr6.sin6_family = AF_INET6;
2218 listening_sockaddr6.sin6_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
2219 listening_sockaddr6.sin6_flowinfo = 0;
2220 listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
2221 listening_sockaddr6.sin6_scope_id = 0;
2222 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
2223 if (err) { errstr = "bind"; goto fail; }
2224 if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
2225 }
2226 #endif
2227
2228 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
2229 fcntl(skt, F_SETFD, 1); // set close-on-exec
2230 *s = skt;
2231 k->KQcallback = myKQSocketCallBack;
2232 k->KQcontext = cp;
2233 k->KQtask = "UDP packet reception";
2234 #ifdef __LIB_DISPATCH__
2235 k->readSource = mDNSNULL;
2236 k->writeSource = mDNSNULL;
2237 k->fdClosed = mDNSfalse;
2238 #endif
2239 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
2240
2241 return(err);
2242
2243 fail:
2244 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
2245 if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
2246 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
2247
2248 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
2249 if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
2250 {
2251 err = EADDRINUSE;
2252 if (mDNSSameIPPort(port, MulticastDNSPort))
2253 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
2254 "Congratulations, you've reproduced an elusive bug.\r"
2255 "Please contact the current assignee of <rdar://problem/3814904>.\r"
2256 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2257 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2258 }
2259
2260 mDNSPlatformCloseFD(k, skt);
2261 return(err);
2262 }
2263
2264 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
2265 {
2266 mStatus err;
2267 mDNSIPPort port = requestedport;
2268 mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
2269 int i = 10000; // Try at most 10000 times to get a unique random port
2270 UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
2271 if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
2272 mDNSPlatformMemZero(p, sizeof(UDPSocket));
2273 p->ss.port = zeroIPPort;
2274 p->ss.m = m;
2275 p->ss.sktv4 = -1;
2276 #ifndef NO_IPV6
2277 p->ss.sktv6 = -1;
2278 #endif
2279
2280 do
2281 {
2282 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
2283 if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
2284 err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
2285 #ifndef NO_IPV6
2286 if (!err)
2287 {
2288 err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
2289 if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
2290 }
2291 #endif
2292 i--;
2293 } while (err == EADDRINUSE && randomizePort && i);
2294
2295 if (err)
2296 {
2297 // In customer builds we don't want to log failures with port 5351, because this is a known issue
2298 // of failing to bind to this port when Internet Sharing has already bound to it
2299 // We also don't want to log about port 5350, due to a known bug when some other
2300 // process is bound to it.
2301 if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
2302 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2303 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2304 freeL("UDPSocket", p);
2305 return(mDNSNULL);
2306 }
2307 return(p);
2308 }
2309
2310 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
2311 {
2312 CloseSocketSet(&sock->ss);
2313 freeL("UDPSocket", sock);
2314 }
2315
2316 #if COMPILER_LIKES_PRAGMA_MARK
2317 #pragma mark -
2318 #pragma mark - BPF Raw packet sending/receiving
2319 #endif
2320
2321 #if APPLE_OSX_mDNSResponder
2322
2323 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
2324 {
2325 if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2326 NetworkInterfaceInfoOSX *info;
2327
2328 extern mDNS mDNSStorage;
2329 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
2330 if (info == NULL)
2331 {
2332 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
2333 return;
2334 }
2335 if (info->BPF_fd < 0)
2336 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
2337 else
2338 {
2339 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
2340 if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
2341 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
2342 }
2343 }
2344
2345 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
2346 {
2347 if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
2348 NetworkInterfaceInfoOSX *info;
2349 info = IfindexToInterfaceInfoOSX(m, InterfaceID);
2350 if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; }
2351 // Manually inject an entry into our local ARP cache.
2352 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
2353 if (!mDNS_AddressIsLocalSubnet(m, InterfaceID, tpa))
2354 LogSPS("Don't need address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
2355 else
2356 {
2357 int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b);
2358 if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
2359 else LogSPS("Set local address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
2360 }
2361 }
2362
2363 mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
2364 {
2365 LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
2366 #ifdef __LIB_DISPATCH__
2367 // close will happen in the cancel handler
2368 dispatch_source_cancel(i->BPF_source);
2369 #else
2370
2371 // Note: MUST NOT close() the underlying native BSD sockets.
2372 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
2373 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
2374 CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
2375 CFRelease(i->BPF_rls);
2376 CFSocketInvalidate(i->BPF_cfs);
2377 CFRelease(i->BPF_cfs);
2378 #endif
2379 i->BPF_fd = -1;
2380 if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
2381 }
2382
2383 mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
2384 {
2385 KQueueLock(info->m);
2386
2387 // Now we've got the lock, make sure the kqueue thread didn't close the fd out from under us (will not be a problem once the OS X
2388 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
2389 if (info->BPF_fd < 0) goto exit;
2390
2391 ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
2392 const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
2393 const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
2394 debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
2395
2396 if (n<0)
2397 {
2398 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
2399 CloseBPF(info);
2400 goto exit;
2401 }
2402
2403 while (ptr < end)
2404 {
2405 const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr;
2406 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
2407 info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen,
2408 ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
2409 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
2410 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
2411 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
2412 mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
2413 ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
2414 }
2415 exit:
2416 KQueueUnlock(info->m, "bpf_callback");
2417 }
2418 #ifdef __LIB_DISPATCH__
2419 mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
2420 {
2421 bpf_callback_common(info);
2422 }
2423 #else
2424 mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
2425 {
2426 (void)cfs;
2427 (void)CallBackType;
2428 (void)address;
2429 (void)data;
2430 bpf_callback_common((NetworkInterfaceInfoOSX *)context);
2431 }
2432 #endif
2433
2434 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2435
2436 mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *p4, int *p6)
2437 {
2438 int numv4 = 0, numv6 = 0;
2439 AuthRecord *rr;
2440
2441 for (rr = m->ResourceRecords; rr; rr=rr->next)
2442 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2443 {
2444 if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
2445 numv4++;
2446 }
2447
2448 for (rr = m->ResourceRecords; rr; rr=rr->next)
2449 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2450 {
2451 if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
2452 numv6++;
2453 }
2454
2455 if (p4) *p4 = numv4;
2456 if (p6) *p6 = numv6;
2457 return(numv4 + numv6);
2458 }
2459
2460 mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
2461 {
2462 NetworkInterfaceInfoOSX *x;
2463
2464 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
2465 for (x = m->p->InterfaceList; x; x = x->next) if (x->ifinfo.InterfaceID == InterfaceID) break;
2466
2467 if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
2468
2469 #define MAX_BPF_ADDRS 250
2470 int numv4 = 0, numv6 = 0;
2471
2472 if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS)
2473 {
2474 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
2475 if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
2476 numv6 = MAX_BPF_ADDRS - numv4;
2477 }
2478
2479 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
2480
2481 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
2482 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
2483 static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
2484 {
2485 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13)
2486
2487 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
2488 BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP
2489
2490 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
2491
2492 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
2493 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
2494 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
2495 BPF_STMT(BPF_RET + BPF_K, 86), // 7 Return 86-byte ND
2496
2497 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
2498 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
2499 };
2500
2501 struct bpf_insn *pc = &filter[9];
2502 struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0"
2503 struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks
2504 struct bpf_insn *ret4 = fail + 1;
2505 struct bpf_insn *ret6 = ret4 + 4;
2506
2507 static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing
2508
2509 static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
2510
2511 static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20)
2512 static const struct bpf_insn r4b = BPF_STMT(BPF_LD + BPF_IMM, 54); // A = 54 (14-byte Ethernet plus 20-byte TCP + 20 bytes spare)
2513 static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length
2514 static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
2515
2516 static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
2517
2518 BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail
2519 BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check
2520
2521 // BPF Byte-Order Note
2522 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
2523 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
2524 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
2525 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
2526 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
2527 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
2528 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
2529 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
2530 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
2531 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
2532
2533 // IPSEC capture size notes:
2534 // 8 bytes UDP header
2535 // 4 bytes Non-ESP Marker
2536 // 28 bytes IKE Header
2537 // --
2538 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
2539
2540 AuthRecord *rr;
2541 for (rr = m->ResourceRecords; rr; rr=rr->next)
2542 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2543 {
2544 mDNSv4Addr a = rr->AddressProxy.ip.v4;
2545 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2546 BPF_SetOffset(pc, jt, ret4);
2547 pc->jf = 0;
2548 pc->k = (bpf_u_int32)a.b[0] << 24 | (bpf_u_int32)a.b[1] << 16 | (bpf_u_int32)a.b[2] << 8 | (bpf_u_int32)a.b[3];
2549 pc++;
2550 }
2551 *pc++ = rf;
2552
2553 if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
2554 *pc++ = g6; // chk6 points here
2555
2556 // First cancel any previous ND group memberships we had, then create a fresh socket
2557 if (x->BPF_mcfd >= 0) close(x->BPF_mcfd);
2558 x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0);
2559
2560 for (rr = m->ResourceRecords; rr; rr=rr->next)
2561 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2562 {
2563 const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
2564 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2565 BPF_SetOffset(pc, jt, ret6);
2566 pc->jf = 0;
2567 pc->k = (bpf_u_int32)a->b[0x0C] << 24 | (bpf_u_int32)a->b[0x0D] << 16 | (bpf_u_int32)a->b[0x0E] << 8 | (bpf_u_int32)a->b[0x0F];
2568 pc++;
2569
2570 struct ipv6_mreq i6mr;
2571 i6mr.ipv6mr_interface = x->scope_id;
2572 i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix;
2573 i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD];
2574 i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE];
2575 i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF];
2576
2577 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
2578 mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
2579 if (err < 0 && (errno != EADDRNOTAVAIL))
2580 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2581
2582 err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
2583 if (err < 0 && (errno != EADDRINUSE)) // Joining same group twice can give "Address already in use" error -- no need to report that
2584 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2585
2586 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
2587 }
2588
2589 if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
2590 *pc++ = rf; // fail points here
2591
2592 if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
2593 *pc++ = r4a; // ret4 points here
2594 *pc++ = r4b;
2595 *pc++ = r4c;
2596 *pc++ = r4d;
2597
2598 if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
2599 *pc++ = r6a; // ret6 points here
2600
2601 struct bpf_program prog = { pc - filter, filter };
2602
2603 #if 0
2604 // For debugging BPF filter program
2605 unsigned int q;
2606 for (q=0; q<prog.bf_len; q++)
2607 LogSPS("mDNSPlatformUpdateProxyList: %2d { 0x%02x, %d, %d, 0x%08x },", q, prog.bf_insns[q].code, prog.bf_insns[q].jt, prog.bf_insns[q].jf, prog.bf_insns[q].k);
2608 #endif
2609
2610 if (!numv4 && !numv6)
2611 {
2612 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
2613 if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
2614 // Schedule check to see if we can close this BPF_fd now
2615 if (!m->p->NetworkChanged) m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
2616 // prog.bf_len = 0; This seems to panic the kernel
2617 if (x->BPF_fd < 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
2618 }
2619
2620 if (ioctl(x->BPF_fd, BIOCSETF, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETF(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
2621 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETF(%d) successful", prog.bf_len);
2622 }
2623
2624 mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd)
2625 {
2626 mDNS_Lock(m);
2627
2628 NetworkInterfaceInfoOSX *i;
2629 for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
2630 if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
2631 else
2632 {
2633 LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd);
2634
2635 struct bpf_version v;
2636 if (ioctl(fd, BIOCVERSION, &v) < 0)
2637 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2638 else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
2639 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
2640 fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
2641
2642 if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
2643 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2644
2645 if (i->BPF_len > sizeof(m->imsg))
2646 {
2647 i->BPF_len = sizeof(m->imsg);
2648 if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
2649 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2650 else LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", i->BPF_len);
2651 }
2652
2653 static const u_int opt_one = 1;
2654 if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0)
2655 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2656
2657 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
2658 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2659
2660 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
2661 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2662
2663 struct ifreq ifr;
2664 mDNSPlatformMemZero(&ifr, sizeof(ifr));
2665 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
2666 if (ioctl(fd, BIOCSETIF, &ifr) < 0)
2667 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
2668 else
2669 {
2670 #ifdef __LIB_DISPATCH__
2671 i->BPF_fd = fd;
2672 i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());
2673 if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed");return;}
2674 dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);});
2675 dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);});
2676 dispatch_resume(i->BPF_source);
2677 #else
2678 CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
2679 i->BPF_fd = fd;
2680 i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
2681 i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
2682 CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
2683 #endif
2684 mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID);
2685 }
2686 }
2687
2688 mDNS_Unlock(m);
2689 }
2690
2691 #endif // APPLE_OSX_mDNSResponder
2692
2693 #if COMPILER_LIKES_PRAGMA_MARK
2694 #pragma mark -
2695 #pragma mark - Key Management
2696 #endif
2697
2698 #ifndef NO_SECURITYFRAMEWORK
2699 mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity)
2700 {
2701 CFMutableArrayRef certChain = NULL;
2702 if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); }
2703 SecCertificateRef cert;
2704 OSStatus err = SecIdentityCopyCertificate(identity, &cert);
2705 if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
2706 else
2707 {
2708 SecPolicySearchRef searchRef;
2709 err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
2710 if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err);
2711 else
2712 {
2713 SecPolicyRef policy;
2714 err = SecPolicySearchCopyNext(searchRef, &policy);
2715 if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
2716 else
2717 {
2718 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
2719 if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL");
2720 else
2721 {
2722 SecTrustRef trust;
2723 err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
2724 if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
2725 else
2726 {
2727 err = SecTrustEvaluate(trust, NULL);
2728 if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err);
2729 else
2730 {
2731 CFArrayRef rawCertChain;
2732 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
2733 err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
2734 if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err);
2735 else
2736 {
2737 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
2738 if (!certChain) LogMsg("getCertChain: certChain is NULL");
2739 else
2740 {
2741 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
2742 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
2743 CFArraySetValueAtIndex(certChain, 0, identity);
2744 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
2745 if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
2746 }
2747 CFRelease(rawCertChain);
2748 // Do not free statusChain:
2749 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
2750 // certChain: Call the CFRelease function to release this object when you are finished with it.
2751 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
2752 }
2753 }
2754 CFRelease(trust);
2755 }
2756 CFRelease(wrappedCert);
2757 }
2758 CFRelease(policy);
2759 }
2760 CFRelease(searchRef);
2761 }
2762 CFRelease(cert);
2763 }
2764 return certChain;
2765 }
2766 #endif /* NO_SECURITYFRAMEWORK */
2767
2768 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
2769 {
2770 #ifdef NO_SECURITYFRAMEWORK
2771 return mStatus_UnsupportedErr;
2772 #else
2773 SecIdentityRef identity = nil;
2774 SecIdentitySearchRef srchRef = nil;
2775 OSStatus err;
2776
2777 // search for "any" identity matching specified key use
2778 // In this app, we expect there to be exactly one
2779 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
2780 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
2781
2782 err = SecIdentitySearchCopyNext(srchRef, &identity);
2783 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
2784
2785 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
2786 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
2787
2788 // Found one. Call getCertChain to create the correct certificate chain.
2789 ServerCerts = GetCertChain(identity);
2790 if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; }
2791
2792 return mStatus_NoError;
2793 #endif /* NO_SECURITYFRAMEWORK */
2794 }
2795
2796 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
2797 {
2798 #ifndef NO_SECURITYFRAMEWORK
2799 if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
2800 #endif /* NO_SECURITYFRAMEWORK */
2801 }
2802
2803 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
2804 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
2805 {
2806 CFStringEncoding encoding = kCFStringEncodingUTF8;
2807 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
2808 if (cfs)
2809 {
2810 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
2811 CFRelease(cfs);
2812 }
2813 }
2814
2815 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
2816 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
2817 {
2818 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
2819 if (cfs)
2820 {
2821 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
2822 CFRelease(cfs);
2823 }
2824 }
2825
2826 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
2827 {
2828 mDNSs32 val;
2829 CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
2830 if (!state) return mDNSfalse;
2831 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
2832 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
2833 return val ? mDNStrue : mDNSfalse;
2834 }
2835
2836 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
2837 {
2838 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
2839
2840 if (sa->sa_family == AF_INET)
2841 {
2842 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
2843 ip->type = mDNSAddrType_IPv4;
2844 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
2845 return(mStatus_NoError);
2846 }
2847
2848 if (sa->sa_family == AF_INET6)
2849 {
2850 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
2851 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
2852 // value into the second word of the IPv6 link-local address, so they can just
2853 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
2854 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
2855 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
2856 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
2857 ip->type = mDNSAddrType_IPv6;
2858 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
2859 return(mStatus_NoError);
2860 }
2861
2862 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
2863 return(mStatus_Invalid);
2864 }
2865
2866 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
2867 {
2868 mDNSEthAddr eth = zeroEthAddr;
2869 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
2870 if (!store)
2871 LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
2872 else
2873 {
2874 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
2875 if (entityname)
2876 {
2877 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
2878 if (dict)
2879 {
2880 CFRange range = { 0, 6 }; // Offset, length
2881 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
2882 if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
2883 CFRelease(dict);
2884 }
2885 CFRelease(entityname);
2886 }
2887 CFRelease(store);
2888 }
2889 return(eth);
2890 }
2891
2892 mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
2893 {
2894 struct ifaddrs *ifa;
2895 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
2896 if (ifa->ifa_addr->sa_family == AF_LINK)
2897 {
2898 const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
2899 if (sdl->sdl_index == ifindex)
2900 { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
2901 }
2902 *eth = zeroEthAddr;
2903 return -1;
2904 }
2905
2906 #ifndef SIOCGIFWAKEFLAGS
2907 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
2908 #endif
2909
2910 #ifndef IF_WAKE_ON_MAGIC_PACKET
2911 #define IF_WAKE_ON_MAGIC_PACKET 0x01
2912 #endif
2913
2914 #ifndef ifr_wake_flags
2915 #define ifr_wake_flags ifr_ifru.ifru_intval
2916 #endif
2917
2918 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
2919 {
2920 if (!MulticastInterface(i) ) return(mDNSfalse); // We only use Sleep Proxy Service on multicast-capable interfaces
2921 if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse); // except loopback
2922
2923 int s = socket(AF_INET, SOCK_DGRAM, 0);
2924 if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); }
2925
2926 struct ifreq ifr;
2927 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
2928 if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
2929 {
2930 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
2931 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
2932 // error code is being returned from the kernel, we need to use the kernel version.
2933 #define KERNEL_EOPNOTSUPP 102
2934 if (errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
2935 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno));
2936 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
2937 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
2938 ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
2939 }
2940
2941 close(s);
2942
2943 // ifr.ifr_wake_flags = IF_WAKE_ON_MAGIC_PACKET; // For testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
2944
2945 LogSPS("%-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
2946
2947 return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
2948 }
2949
2950 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
2951 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
2952 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
2953 // (e.g. sa_family not AF_INET or AF_INET6)
2954 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
2955 {
2956 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
2957 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
2958
2959 mDNSAddr ip, mask;
2960 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
2961 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
2962
2963 NetworkInterfaceInfoOSX **p;
2964 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
2965 if (scope_id == (*p)->scope_id &&
2966 mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
2967 mDNSSameEthAddress(&bssid, &(*p)->BSSID))
2968 {
2969 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, *p);
2970 (*p)->Exists = mDNStrue;
2971 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
2972 if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
2973
2974 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
2975 // we may need to start or stop or sleep proxy browse operation
2976 const mDNSBool NetWake = NetWakeInterface(*p);
2977 if ((*p)->ifinfo.NetWake != NetWake)
2978 {
2979 (*p)->ifinfo.NetWake = NetWake;
2980 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
2981 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
2982 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
2983 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
2984 if ((*p)->Registered)
2985 {
2986 mDNS_Lock(m);
2987 if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo);
2988 else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
2989 mDNS_Unlock(m);
2990 }
2991 }
2992
2993 return(*p);
2994 }
2995
2996 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
2997 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
2998 if (!i) return(mDNSNULL);
2999 mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
3000 i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
3001 i->ifinfo.ip = ip;
3002 i->ifinfo.mask = mask;
3003 strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
3004 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
3005 // We can be configured to disable multicast advertisement, but we want to to support
3006 // local-only services, which need a loopback address record.
3007 i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
3008 i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
3009
3010 i->next = mDNSNULL;
3011 i->m = m;
3012 i->Exists = mDNStrue;
3013 i->Flashing = mDNSfalse;
3014 i->Occulting = mDNSfalse;
3015 i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
3016 i->LastSeen = utc;
3017 i->ifa_flags = ifa->ifa_flags;
3018 i->scope_id = scope_id;
3019 i->BSSID = bssid;
3020 i->sa_family = ifa->ifa_addr->sa_family;
3021 i->BPF_fd = -1;
3022 i->BPF_mcfd = -1;
3023 i->BPF_len = 0;
3024 i->Registered = mDNSNULL;
3025
3026 // Do this AFTER i->BSSID has been set up
3027 i->ifinfo.NetWake = NetWakeInterface(i);
3028 GetMAC(&i->ifinfo.MAC, scope_id);
3029 if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
3030 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
3031
3032 *p = i;
3033 return(i);
3034 }
3035
3036 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
3037 mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
3038 {
3039 NetworkInterfaceInfoOSX *i;
3040 for (i = m->p->InterfaceList; i; i = i->next)
3041 if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
3042 if (!mDNSv4AddressIsLinkLocal(&i->ifinfo.ip.ip.v4))
3043 return(i);
3044 return(mDNSNULL);
3045 }
3046 #endif
3047
3048 #if APPLE_OSX_mDNSResponder
3049
3050 #if COMPILER_LIKES_PRAGMA_MARK
3051 #pragma mark -
3052 #pragma mark - AutoTunnel
3053 #endif
3054
3055 #define kRacoonPort 4500
3056
3057 static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
3058
3059 #ifndef NO_SECURITYFRAMEWORK
3060
3061 static CFMutableDictionaryRef domainStatusDict = NULL;
3062
3063 // MUST be called with lock held
3064 mDNSlocal void RemoveAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
3065 {
3066 char buffer[1024];
3067 CFStringRef domain;
3068
3069 LogInfo("RemoveAutoTunnelDomainStatus: %##s", info->domain.c);
3070
3071 if (!domainStatusDict) { LogMsg("RemoveAutoTunnelDomainStatus: No domainStatusDict"); return; }
3072
3073 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c) - 1] = 0;
3074 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3075 if (!domain) { LogMsg("RemoveAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3076
3077 if (CFDictionaryContainsKey(domainStatusDict, domain))
3078 {
3079 CFDictionaryRemoveValue(domainStatusDict, domain);
3080 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3081 }
3082 CFRelease(domain);
3083 }
3084
3085 mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
3086 {
3087 if (q->LongLived)
3088 {
3089 if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
3090 return mStatus_NoSuchRecord;
3091 else if (q->state == LLQ_Poll)
3092 return mStatus_PollingMode;
3093 else if (q->state != LLQ_Established && !q->DuplicateOf)
3094 return mStatus_TransientErr;
3095 }
3096
3097 return mStatus_NoError;
3098 }
3099
3100 mDNSlocal mStatus UpdateLLQStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
3101 {
3102 mStatus status = mStatus_NoError;
3103 DNSQuestion* q, *worst_q = mDNSNULL;
3104 for (q = m->Questions; q; q=q->next)
3105 if (q->AuthInfo == info)
3106 {
3107 mStatus newStatus = CheckQuestionForStatus(q);
3108 if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
3109 else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; }
3110 else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
3111 }
3112
3113 if (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success");
3114 else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
3115 else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
3116 else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
3117 return status;
3118 }
3119
3120 mDNSlocal mStatus UpdateRRStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
3121 {
3122 AuthRecord *r;
3123
3124 if (info->deltime) return mStatus_NoError;
3125 for (r = m->ResourceRecords; r; r = r->next)
3126 {
3127 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
3128 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
3129 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
3130 // has already checked
3131 const domainname *n = r->resrec.name;
3132 while (n->c[0])
3133 {
3134 DomainAuthInfo *ptr;
3135 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
3136 if (SameDomainName(&ptr->domain, n))
3137 {
3138 if (ptr == info && r->updateError == mStatus_BadSig)
3139 {
3140 mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
3141 return r->updateError;
3142 }
3143 }
3144 n = (const domainname *)(n->c + 1 + n->c[0]);
3145 }
3146 }
3147 return mStatus_NoError;
3148 }
3149
3150 #endif // ndef NO_SECURITYFRAMEWORK
3151
3152 // MUST be called with lock held
3153 mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
3154 {
3155 #ifdef NO_SECURITYFRAMEWORK
3156 (void)m;
3157 (void)info;
3158 #else
3159 const NATTraversalInfo *const llq = m->LLQNAT.clientContext ? &m->LLQNAT : mDNSNULL;
3160 const NATTraversalInfo *const tun = info->AutoTunnelNAT.clientContext ? &info->AutoTunnelNAT : mDNSNULL;
3161 char buffer[1024];
3162 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3163 CFStringRef domain = NULL;
3164 CFStringRef tmp = NULL;
3165 CFNumberRef num = NULL;
3166 mStatus status = mStatus_NoError;
3167
3168 if (!m->mDNS_busy) LogMsg("UpdateAutoTunnelDomainStatus: ERROR!! Lock not held");
3169 if (!domainStatusDict)
3170 {
3171 domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3172 if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
3173 }
3174
3175 if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
3176
3177 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c) - 1] = 0;
3178 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3179 if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3180
3181 mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
3182 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3183 if (!tmp)
3184 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
3185 else
3186 {
3187 CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
3188 CFRelease(tmp);
3189 }
3190
3191 mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &m->ExternalAddress);
3192 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3193 if (!tmp)
3194 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
3195 else
3196 {
3197 CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
3198 CFRelease(tmp);
3199 }
3200
3201 if (llq)
3202 {
3203 mDNSu32 port = mDNSVal16(llq->ExternalPort);
3204
3205 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3206 if (!num)
3207 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
3208 else
3209 {
3210 CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
3211 CFRelease(num);
3212 }
3213
3214 if (llq->Result)
3215 {
3216 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
3217 if (!num)
3218 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
3219 else
3220 {
3221 CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
3222 CFRelease(num);
3223 }
3224 }
3225 }
3226
3227 if (tun)
3228 {
3229 mDNSu32 port = mDNSVal16(tun->ExternalPort);
3230
3231 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3232 if (!num)
3233 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
3234 else
3235 {
3236 CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
3237 CFRelease(num);
3238 }
3239
3240 if (tun->Result)
3241 {
3242 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
3243 if (!num)
3244 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
3245 else
3246 {
3247 CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
3248 CFRelease(num);
3249 }
3250 }
3251 }
3252 if (tun || llq)
3253 {
3254 mDNSu32 code = m->LastNATMapResultCode;
3255
3256 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
3257 if (!num)
3258 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
3259 else
3260 {
3261 CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
3262 CFRelease(num);
3263 }
3264 }
3265
3266 // If we have a relay address which lets other hosts to reach us through the relay, then we should
3267 // report success except for the LLQs they don't go over the relay connection. If LLQs fail, then
3268 // report failure. In future, when LLQs go over the relay connection, we don't need this logic
3269 if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddrIn))
3270 {
3271 // If we have a bad signature error updating RR, it overrides any error as
3272 // the user needs to be notified immediately
3273 status = UpdateRRStatus(m, buffer, sizeof(buffer), info);
3274 if (status == mStatus_NoError)
3275 {
3276 status = UpdateLLQStatus(m, buffer, sizeof(buffer), info);
3277 if (status == mStatus_PollingMode)
3278 {
3279 // If we have a relay connection and we are in polling mode, report as success.
3280 // This normally happens when we are behind Double NAT or NAT with UPnP/NAT-PMP
3281 // disabled but we are able to successfully file share/screen share with the help
3282 // of the relay connection. As it just affects the discovery/update of the other
3283 // BTMM hosts, we consider it as minor issue and report it as success.
3284 LogInfo("UpdateAutoTunnelDomainStatus:NonzeroRelayAddress: Polling reported as success");
3285 status = mStatus_NoError;
3286 mDNS_snprintf(buffer, sizeof(buffer), "Success");
3287 }
3288 }
3289 LogInfo("UpdateAutoTunnelDomainStatus:NonzeroRelayAddress: Status %d, %s", status, buffer);
3290 }
3291 else if (!llq && !tun)
3292 {
3293 status = mStatus_NotInitializedErr;
3294 mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
3295 }
3296 else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
3297 {
3298 status = mStatus_DoubleNAT;
3299 mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting an external address");
3300 }
3301 else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) || (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
3302 (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
3303 {
3304 status = mStatus_NATPortMappingDisabled;
3305 mDNS_snprintf(buffer, sizeof(buffer), "NAT-PMP is disabled on the router");
3306 }
3307 else if ((llq && llq->Result) || (tun && tun->Result))
3308 {
3309 status = mStatus_NATTraversal;
3310 mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
3311 }
3312 else if (m->Router.type == mDNSAddrType_None)
3313 {
3314 status = mStatus_NoRouter;
3315 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
3316 }
3317 else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
3318 {
3319 status = mStatus_NoRouter;
3320 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
3321 }
3322 else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
3323 {
3324 status = mStatus_NATTraversal;
3325 mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
3326 }
3327 else
3328 {
3329 status = UpdateRRStatus(m, buffer, sizeof(buffer), info);
3330 if (status == mStatus_NoError)
3331 status = UpdateLLQStatus(m, buffer, sizeof(buffer), info);
3332 LogInfo("UpdateAutoTunnelDomainStatus:ZeroRelayAddress: Status %d, %s", status, buffer);
3333 }
3334
3335 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
3336 if (!num)
3337 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
3338 else
3339 {
3340 CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
3341 CFRelease(num);
3342 }
3343
3344 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3345 if (!tmp)
3346 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
3347 else
3348 {
3349 CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
3350 CFRelease(tmp);
3351 }
3352
3353 if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
3354 !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
3355 {
3356 CFDictionarySetValue(domainStatusDict, domain, dict);
3357 if (!m->ShutdownTime)
3358 {
3359 static char statusBuf[16];
3360 mDNS_snprintf(statusBuf, sizeof(statusBuf), "%d", (int)status);
3361 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.domainstatus", status ? "failure" : "success", statusBuf, "");
3362 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3363 }
3364 }
3365
3366 CFRelease(domain);
3367 CFRelease(dict);
3368
3369 debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
3370 #endif // def NO_SECURITYFRAMEWORK
3371 }
3372
3373 // MUST be called with lock held
3374 mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
3375 {
3376 #ifdef NO_SECURITYFRAMEWORK
3377 (void)m;
3378 #else
3379 if (!m->mDNS_busy) LogMsg("UpdateAutoTunnelDomainStatuses: ERROR!! Lock not held");
3380 DomainAuthInfo* info;
3381 for (info = m->AuthInfoList; info; info = info->next)
3382 if (info->AutoTunnel && !info->deltime)
3383 UpdateAutoTunnelDomainStatus(m, info);
3384 #endif // def NO_SECURITYFRAMEWORK
3385 }
3386
3387 // MUST be called with lock held
3388 mDNSlocal mDNSBool TunnelServers(mDNS *const m)
3389 {
3390 AuthRecord *r;
3391 for (r = m->ResourceRecords; r; r = r->next)
3392 if (r->resrec.rrtype == kDNSType_SRV)
3393 {
3394 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, r->resrec.name);
3395 if (AuthInfo && AuthInfo->AutoTunnel && !AuthInfo->deltime) return(mDNStrue);
3396 }
3397
3398 return(mDNSfalse);
3399 }
3400
3401 // MUST be called with lock held
3402 mDNSlocal mDNSBool TunnelClients(mDNS *const m)
3403 {
3404 ClientTunnel *p;
3405 for (p = m->TunnelClients; p; p = p->next)
3406 if (p->q.ThisQInterval < 0)
3407 return(mDNStrue);
3408 return(mDNSfalse);
3409 }
3410
3411 mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we need racoon to accept incoming connections
3412 {
3413 DomainAuthInfo *info;
3414
3415 for (info = m->AuthInfoList; info; info = info->next)
3416 if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddrIn)))
3417 break;
3418
3419 if (info != AnonymousRacoonConfig)
3420 {
3421 AnonymousRacoonConfig = info;
3422 // Create or revert configuration file, and start (or SIGHUP) Racoon
3423 (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, AnonymousRacoonConfig ? &AnonymousRacoonConfig->domain : mDNSNULL);
3424 }
3425 }
3426
3427 // Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
3428 // sometimes the caller may already be holding the lock e.g., RegisterAutoTunnel6Record and sometimes
3429 // not e.g., RegisterAutoTunnelServiceRecord
3430 mDNSlocal void RegisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
3431 {
3432 mStatus err;
3433 mDNSBool NATProblem;
3434
3435 if (!m->mDNS_busy) LogMsg("RegisterAutoTunnelHostRecord: ERROR!! Lock not held");
3436
3437 // We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
3438 // called at least once with some Services/Records in the domain and hence it is safe to register
3439 // records when this function is called.
3440 if (!info->AutoTunnelNAT.clientContext) { LogInfo("RegisterAutoTunnelHostRecord: No services registered, not registering the record\n"); return; }
3441
3442 // Are we behind a NAT with no NAT-PMP support or behind a Double NAT ? Double NATs may have
3443 // NAT-PMP support but it still does not provide inbound connectivity. If there is no NAT-PMP
3444 // support, ExternalPort is zero. If we are behind a Double NAT, then the NATResult is non-zero.
3445
3446 NATProblem = mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) || info->AutoTunnelNAT.Result;
3447
3448 if (mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddrIn))
3449 {
3450 // If we don't have a relay address, check to see if we are behind a Double NAT or NAT with no NAT-PMP
3451 // support.
3452 if (NATProblem)
3453 {
3454 LogInfo("RegisterAutoTunnelHostRecord %##s, not registering the Host Record, Neither AutoTunnel6 nor NAT is available, ClientContext %p, ExternalPort %d, NAT Result %d", info->domain.c, info->AutoTunnelNAT.clientContext, mDNSVal16(info->AutoTunnelNAT.ExternalPort), info->AutoTunnelNAT.Result);
3455 return;
3456 }
3457 }
3458 else
3459 {
3460 // Relay address may be non-zero but we might be going to sleep as the utun interface is not removed
3461 // when going to sleep. If we are awake, we don't care about the NATProblem as the relay connnection
3462 // is up. If we are going to sleep, we should not register the host record if we have a NAT problem.
3463 if (m->SleepState != SleepState_Awake && NATProblem)
3464 {
3465 LogInfo("RegisterAutoTunnelHostRecord %##s, not registering the Host Record, Not in awake state(%d), and some NAT Problem, ClientContext %p, ExternalPort %d, NAT Result %d", info->domain.c, m->SleepState, info->AutoTunnelNAT.clientContext, mDNSVal16(info->AutoTunnelNAT.ExternalPort), info->AutoTunnelNAT.Result);
3466 return;
3467 }
3468 }
3469
3470 // Note:
3471 //
3472 // We use zero Requested port to infer that we should not be calling Register anymore as it might
3473 // be shutdown or the DomainAuthInfo is going away.
3474 //
3475 // We can use a different set of state variables to track the above as the records registered in
3476 // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
3477 // reuse the NAT variables.
3478
3479 // Set up our address record for the internal tunnel address
3480 // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
3481 if (!mDNSIPPortIsZero(info->AutoTunnelNAT.RequestedPort) && info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
3482 {
3483 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
3484 AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
3485 AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
3486 info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = m->AutoTunnelHostAddr;
3487 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
3488
3489 err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
3490
3491 if (err) LogMsg("RegisterAutoTunnelHostRecord error %d registering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
3492 else
3493 {
3494 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
3495 m->NextSRVUpdate = NonZeroTime(m->timenow);
3496 LogInfo("RegisterAutoTunnelHostRecord registering AutoTunnelHostRecord %##s", info->AutoTunnelHostRecord.namestorage.c);
3497 }
3498 }
3499 else LogInfo("RegisterAutoTunnelHostRecord: Not registering Context %p Port %d Type %d", info->AutoTunnelNAT.clientContext, mDNSVal16(info->AutoTunnelNAT.RequestedPort), info->AutoTunnelHostRecord.resrec.RecordType);
3500 }
3501
3502 mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
3503 {
3504 LogInfo("DeregisterAutoTunnelHostRecord %##s", info->domain.c);
3505
3506 // Don't deregister if we have the AutoTunnel6 or AutoTunnelService records are registered.
3507 // They indicate that BTMM is working
3508 if (info->AutoTunnel6Record.resrec.RecordType > kDNSRecordTypeDeregistering ||
3509 info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering)
3510 {
3511 LogInfo("DeregisterAutoTunnelHostRecord %##s, not deregistering the Host Record AutoTunnel6 RecordType:%d AutoTunnel RecordType: %d", info->domain.c,
3512 info->AutoTunnel6Record.resrec.RecordType, info->AutoTunnelService.resrec.RecordType);
3513 return;
3514 }
3515
3516 if (info->AutoTunnelHostRecord.resrec.RecordType > kDNSRecordTypeDeregistering)
3517 {
3518 mStatus err = mDNS_Deregister(m, &info->AutoTunnelHostRecord);
3519 if (err)
3520 {
3521 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
3522 LogMsg("DeregisterAutoTunnelHostRecord error %d deregistering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
3523 }
3524 else LogInfo("DeregisterAutoTunnelHostRecord: Deregistered AutoTunnel Host Record");
3525 }
3526 else LogInfo("DeregisterAutoTunnelHostRecord: Not deregistering Host Record state:%d", info->AutoTunnelHostRecord.resrec.RecordType);
3527 }
3528
3529 mDNSlocal void RegisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
3530 {
3531 mStatus err;
3532
3533 //if (m->mDNS_busy) LogMsg("RegisterAutoTunnelServiceRecords: ERROR!! Lock already held");
3534
3535 if (info->AutoTunnelNAT.clientContext && !info->AutoTunnelNAT.Result && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) && info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
3536 {
3537 LogInfo("RegisterAutoTunnelServiceRecords %##s (%#s)", info->domain.c, m->hostlabel.c);
3538
3539 // 1. Set up our address record for the external tunnel address
3540 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
3541 info->AutoTunnelTarget.namestorage.c[0] = 0;
3542 AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->AutoTunnelLabel);
3543 AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
3544 info->AutoTunnelTarget.resrec.rdata->u.ipv4 = info->AutoTunnelNAT.ExternalAddress;
3545 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
3546
3547 err = mDNS_Register(m, &info->AutoTunnelTarget);
3548 if (err) LogMsg("RegisterAutoTunnelServiceRecords error %d registering AutoTunnelTarget %##s", err, info->AutoTunnelTarget.namestorage.c);
3549 else LogInfo("RegisterAutoTunnelServiceRecords registering AutoTunnelTarget %##s", info->AutoTunnelTarget.namestorage.c);
3550
3551 }
3552
3553 if (info->AutoTunnelNAT.clientContext && !info->AutoTunnelNAT.Result && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) && info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
3554 {
3555 // 2. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
3556 AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
3557 AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
3558 AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
3559 info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
3560 info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
3561 info->AutoTunnelService.resrec.rdata->u.srv.port = info->AutoTunnelNAT.ExternalPort;
3562 AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
3563 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
3564 err = mDNS_Register(m, &info->AutoTunnelService);
3565 if (err) LogMsg("RegisterAutoTunnelServiceRecords error %d registering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
3566 else LogInfo("RegisterAutoTunnelServiceRecords registering AutoTunnelService %##s", info->AutoTunnelService.namestorage.c);
3567
3568 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
3569 info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(info->AutoTunnelNAT.IntPort),
3570 info->AutoTunnelHostRecord.namestorage.c, &m->AutoTunnelHostAddr);
3571 }
3572 mDNS_Lock(m);
3573 RegisterAutoTunnelHostRecord(m, info);
3574 mDNS_Unlock(m);
3575 }
3576
3577 mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
3578 {
3579 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
3580 if (info->AutoTunnelTarget.resrec.RecordType > kDNSRecordTypeDeregistering)
3581 {
3582 mStatus err = mDNS_Deregister(m, &info->AutoTunnelTarget);
3583 if (err)
3584 {
3585 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeUnregistered;
3586 LogMsg("DeregisterAutoTunnelServiceRecords error %d deregistering AutoTunnelTarget %##s", err, info->AutoTunnelTarget.namestorage.c);
3587 }
3588 else LogInfo("DeregisterAutoTunnelServiceRecords: Deregistered AutoTunnel Target Record");
3589
3590 }
3591 else LogInfo("DeregisterAutoTunnelServiceRecords: Not deregistering Target record state:%d", info->AutoTunnelService.resrec.RecordType);
3592
3593 if (info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering)
3594 {
3595 mStatus err = mDNS_Deregister(m, &info->AutoTunnelService);
3596 if (err)
3597 {
3598 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeUnregistered;
3599 LogMsg("DeregisterAutoTunnelServiceRecords error %d deregistering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
3600 }
3601 else LogInfo("DeregisterAutoTunnelServiceRecords: Deregistered AutoTunnel Service Record");
3602
3603 }
3604 else LogInfo("DeregisterAutoTunnelServiceRecords: Not deregistering service records state:%d", info->AutoTunnelService.resrec.RecordType);
3605
3606 DeregisterAutoTunnelHostRecord(m, info);
3607 }
3608
3609 // Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
3610 // sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
3611 // not e.g., AutoTunnelHostNameChanged
3612 mDNSlocal void RegisterAutoTunnelDevInfoRecord(mDNS *m, DomainAuthInfo *info)
3613 {
3614 mStatus err;
3615
3616 if (!m->mDNS_busy) LogMsg("RegisterAutoTunnelDevInfoRecord: Lock not held");
3617 // Note:
3618 // a. We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
3619 // called at least once with some Services/Records in the domain and hence it is safe to register
3620 // records when this function is called.
3621 //
3622 // b. We use zero Requested port to infer that we should not be calling Register anymore as it might
3623 // be shutdown or the DomainAuthInfo is going away.
3624 //
3625 // We can use a different set of state variables to track the above as the records registered in
3626 // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
3627 // reuse the NAT variables.
3628
3629 // Set up device info record
3630 if (info->AutoTunnelNAT.clientContext && !mDNSIPPortIsZero(info->AutoTunnelNAT.RequestedPort) && info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
3631 {
3632 ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
3633 mDNSu8 len = m->HIHardware.c[0] < 255 - 6 ? m->HIHardware.c[0] : 255 - 6;
3634 mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 1, "model=", 6);
3635 mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 7, m->HIHardware.c + 1, len);
3636 info->AutoTunnelDeviceInfo.resrec.rdata->u.data[0] = 6 + len; // "model=" plus the device string
3637 info->AutoTunnelDeviceInfo.resrec.rdlength = 7 + len; // One extra for the length byte at the start of the string
3638 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
3639
3640 err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
3641 if (err) LogMsg("RegisterAutoTunnelDevInfoRecord error %d registering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
3642 else LogInfo("RegisterAutoTunnelDevInfoRecord registering AutoTunnelDeviceInfo %##s", info->AutoTunnelDeviceInfo.namestorage.c);
3643 }
3644 }
3645
3646 #ifndef NO_SECURITYFRAMEWORK
3647 mDNSlocal void DeregisterAutoTunnelDevInfoRecord(mDNS *m, DomainAuthInfo *info)
3648 {
3649 LogInfo("DeregisterAutoTunnelDevInfoRecord %##s", info->domain.c);
3650
3651 if (info->AutoTunnelDeviceInfo.resrec.RecordType > kDNSRecordTypeDeregistering)
3652 {
3653 mStatus err = mDNS_Deregister(m, &info->AutoTunnelDeviceInfo);
3654 if (err)
3655 {
3656 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
3657 LogMsg("DeregisterAutoTunnelDevInfoRecord error %d deregistering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
3658 }
3659 else LogInfo("DeregisterAutoTunnelDevInfoRecord: Deregistered AutoTunnel Device Info");
3660 }
3661 else LogInfo("DeregisterAutoTunnelDevInfoRecord: Not deregistering DeviceInfo Record state:%d", info->AutoTunnelDeviceInfo.resrec.RecordType);
3662 }
3663 #endif
3664
3665
3666 // Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
3667 // sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
3668 // not e.g., AutoTunnelHostNameChanged
3669 mDNSlocal void RegisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
3670 {
3671 mStatus err;
3672
3673 if (!m->mDNS_busy) LogMsg("RegisterAutoTunnel6Record: ERROR!! Lock not held");
3674
3675 // We deregister the AutoTunnel6Record during sleep and come back here (AutoTunnelRecordCallback) to
3676 // register the address if needed. During that time, we might get a network change event which finds
3677 // that the utun interface exists and tries to register the AutoTunnel6Record which should be stopped.
3678 // Also the RelayAddress is reinitialized during that process which in turn causes the AutoTunnelRecordCallback
3679 // to re-register again. To stop these, we check for the SleepState and register only if we are awake.
3680 if (m->SleepState != SleepState_Awake)
3681 {
3682 LogInfo("RegisterAutoTunnel6Record: Not in awake state, SleepState %d", m->SleepState);
3683 return;
3684 }
3685
3686 // if disabled administratively, don't register
3687 // if disabled administratively, don't register
3688 if (!m->RegisterAutoTunnel6 || DisableInboundRelayConnection)
3689 {
3690 LogInfo("RegisterAutoTunnel6Record: registration Disabled RegisterAutoTunnel6 %d, DisableInbound %d",
3691 m->RegisterAutoTunnel6, DisableInboundRelayConnection);
3692 return;
3693 }
3694 //
3695 // If we have a valid Relay address, we need to register it now. When we got a valid address, we may not
3696 // have registered it because it was waiting for at least one service to become active in the BTMM domain.
3697 // During network change event, we might be called multiple times while the "Connectivity" key did not
3698 // change, so check to see if the value has changed. This can also be zero when we are deregistering and
3699 // getting called from the AutoTunnelRecordCallback
3700
3701 if (mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddrIn))
3702 {
3703 LogInfo("RegisterAutoTunnel6Record: Relay address is zero, not registering");
3704 return;
3705 }
3706
3707 if ((info->AutoTunnel6Record.resrec.RecordType > kDNSRecordTypeDeregistering) &&
3708 (mDNSSameIPv6Address(info->AutoTunnel6Record.resrec.rdata->u.ipv6, m->AutoTunnelRelayAddrIn)))
3709 {
3710 LogInfo("RegisterAutoTunnel6Record: Relay address %.16a same, not registering", &m->AutoTunnelRelayAddrIn);
3711 return;
3712 }
3713
3714 // Note:
3715 // a. We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
3716 // called at least once with some Services/Records in the domain and hence it is safe to register
3717 // records when this function is called.
3718 //
3719 // b. We use zero Requested port to infer that we should not be calling Register anymore as it might
3720 // be shutdown or the DomainAuthInfo is going away.
3721 //
3722 // We can use a different set of state variables to track the above as the records registered in
3723 // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
3724 // reuse the NAT variables.
3725
3726 if (info->AutoTunnelNAT.clientContext && !mDNSIPPortIsZero(info->AutoTunnelNAT.RequestedPort) &&
3727 info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
3728 {
3729 AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
3730 AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
3731 AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
3732 info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddrIn;
3733 info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
3734
3735 err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
3736 if (err) LogMsg("RegisterAutoTunnel6Record error %d registering AutoTunnel6 Record %##s", err, info->AutoTunnel6Record.namestorage.c);
3737 else LogInfo("RegisterAutoTunnel6Record registering AutoTunnel6 Record %##s", info->AutoTunnel6Record.namestorage.c);
3738
3739 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
3740 info->AutoTunnel6Record.namestorage.c, &m->AutoTunnelRelayAddrIn,
3741 info->AutoTunnelHostRecord.namestorage.c, &m->AutoTunnelHostAddr);
3742
3743 } else {LogInfo("RegisterAutoTunnel6Record: client context %p, RequestedPort %d, Address %.16a, record type %d", info->AutoTunnelNAT.clientContext, info->AutoTunnelNAT.RequestedPort, &m->AutoTunnelRelayAddrIn, info->AutoTunnel6Record.resrec.RecordType);}
3744
3745 RegisterAutoTunnelHostRecord(m, info);
3746 // When the AutoTunnel6 record comes up, we need to kick racoon and update the status.
3747 // If we had a port mapping, we would have done it in RegisterAutoTunnelServiceRecords.
3748 // If we don't have a port mapping, we need to do it here.
3749 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
3750 UpdateAutoTunnelDomainStatus(m, info);
3751 }
3752
3753 mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
3754 {
3755 LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
3756
3757 if (info->AutoTunnel6Record.resrec.RecordType > kDNSRecordTypeDeregistering)
3758 {
3759 mStatus err = mDNS_Deregister(m, &info->AutoTunnel6Record);
3760 if (err)
3761 {
3762 info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeUnregistered;
3763 info->AutoTunnel6Record.resrec.rdata->u.ipv6 = zerov6Addr;
3764 LogMsg("DeregisterAutoTunnel6Record error %d deregistering AutoTunnel6Record %##s", err, info->AutoTunnel6Record.namestorage.c);
3765 }
3766 else LogInfo("DeregisterAutoTunnel6Record: Deregistered AutoTunnel6 Record");
3767 }
3768 else LogInfo("DeregisterAutoTunnel6Record: Not deregistering AuoTunnel6 record state:%d", info->AutoTunnel6Record.resrec.RecordType);
3769
3770 DeregisterAutoTunnelHostRecord(m, info);
3771 // UpdateAutoTunnelDomainStatus is careful enough not to turn it on if we don't have
3772 // a external port mapping. Otherwise, it will be turned off.
3773 mDNS_Lock(m);
3774 UpdateAutoTunnelDomainStatus(m, info);
3775 mDNS_Unlock(m);
3776 }
3777
3778 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
3779 {
3780 DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
3781 if (result == mStatus_MemFree)
3782 {
3783 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
3784 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
3785 if (rr == &info->AutoTunnelHostRecord)
3786 {
3787 rr->namestorage.c[0] = 0;
3788 m->NextSRVUpdate = NonZeroTime(m->timenow);
3789 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
3790 }
3791 if (m->ShutdownTime) {LogInfo("AutoTunnelRecordCallback: Shutdown, returning");return;}
3792 if (rr == &info->AutoTunnelHostRecord)
3793 {
3794 LogInfo("AutoTunnelRecordCallback: calling RegisterAutoTunnelHostRecord");
3795 RegisterAutoTunnelHostRecord(m,info);
3796 }
3797 else if (rr == &info->AutoTunnelDeviceInfo)
3798 {
3799 LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnelDevInfoRecord");
3800 RegisterAutoTunnelDevInfoRecord(m,info);
3801 }
3802 else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
3803 {
3804 LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnelServiceRecords");
3805 RegisterAutoTunnelServiceRecords(m,info);
3806 }
3807 else if (rr == &info->AutoTunnel6Record)
3808 {
3809 LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnel6Record");
3810 info->AutoTunnel6Record.resrec.rdata->u.ipv6 = zerov6Addr;
3811 RegisterAutoTunnel6Record(m,info);
3812 }
3813 }
3814 }
3815
3816 #ifndef NO_SECURITYFRAMEWORK
3817 mDNSlocal void AutoTunnelDeleteAuthInfoState(mDNS *m, DomainAuthInfo *info)
3818 {
3819 LogInfo("AutoTunnelDeleteAuthInfoState: Cleaning up state releated to Domain AuthInfo %##s", info->domain.c);
3820
3821 m->NextSRVUpdate = NonZeroTime(m->timenow);
3822 DeregisterAutoTunnelDevInfoRecord(m, info);
3823 DeregisterAutoTunnelServiceRecords(m, info);
3824 DeregisterAutoTunnel6Record(m, info);
3825 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
3826 UpdateAutoTunnelDomainStatus(m, info);
3827 }
3828 #endif // ndef NO_SECURITYFRAMEWORK
3829
3830 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
3831 {
3832 DomainAuthInfo *info = (DomainAuthInfo *)n->clientContext;
3833 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s",
3834 n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), m->hostlabel.c, info->domain.c);
3835
3836 m->NextSRVUpdate = NonZeroTime(m->timenow);
3837 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
3838
3839 DeregisterAutoTunnelServiceRecords(m, info);
3840 RegisterAutoTunnelServiceRecords(m, info);
3841
3842 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
3843
3844 UpdateAutoTunnelDomainStatus(m, (DomainAuthInfo *)n->clientContext);
3845 }
3846
3847 mDNSlocal void AbortDeregistration(mDNS *const m, AuthRecord *rr)
3848 {
3849 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
3850 {
3851 LogInfo("Aborting deregistration of %s", ARDisplayString(m, rr));
3852 CompleteDeregistration(m, rr);
3853 }
3854 else if (rr->resrec.RecordType != kDNSRecordTypeUnregistered)
3855 LogMsg("AbortDeregistration ERROR RecordType %02X for %s", ARDisplayString(m, rr));
3856 }
3857
3858 mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
3859 {
3860 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
3861
3862 DeregisterAutoTunnelDevInfoRecord(m, info);
3863 DeregisterAutoTunnelServiceRecords(m, info);
3864 DeregisterAutoTunnel6Record(m, info);
3865 RegisterAutoTunnelServiceRecords(m, info);
3866
3867 mDNS_Lock(m);
3868 RegisterAutoTunnelDevInfoRecord(m, info);
3869 RegisterAutoTunnel6Record(m, info);
3870 m->NextSRVUpdate = NonZeroTime(m->timenow);
3871 mDNS_Unlock(m);
3872 }
3873
3874 mDNSlocal void SetupLocalAutoTunnel6Records(mDNS *const m, DomainAuthInfo *info)
3875 {
3876 AbortDeregistration(m, &info->AutoTunnelDeviceInfo);
3877 AbortDeregistration(m, &info->AutoTunnel6Record);
3878
3879 // When the BTMM is turned on/off too quickly, following things happen.
3880 //
3881 // 1. Turning off BTMM triggers deregistration of the DevInfo/AutoTunnel6 etc. records
3882 // 2. While (1) is in progress, the BTMM is turned on
3883 //
3884 // At step (2), mDNS_SetSecretForDomain clears info->deltime indicating that the domain is valid
3885 // while we have not processed the turning off BTMM completely. Hence, we end up calling this
3886 // function to re-register the records. AbortDeregistration above aborts the Deregistration as the
3887 // records are still in Deregistering state and in AutoTunnelRecordCallback we end up registering
3888 // again. So, we have to be careful below to not call mDNS_SetupResourceRecord again which will
3889 // reset the state to Unregistered and registering again will lead to error as it is registered
3890 // and already in the list. Hence, register below only if needed.
3891
3892 if (info->AutoTunnelDeviceInfo.resrec.RecordType != kDNSRecordTypeUnregistered ||
3893 info->AutoTunnel6Record.resrec.RecordType != kDNSRecordTypeUnregistered)
3894 {
3895 LogInfo("SetupLocalAutoTunnel6Records: AutoTunnel Records not in Unregistered state: Device: %d, AutoTunnel6:%d",
3896 info->AutoTunnelDeviceInfo.resrec.RecordType, info->AutoTunnel6Record.resrec.RecordType);
3897 }
3898
3899 if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
3900 {
3901 mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
3902 RegisterAutoTunnelDevInfoRecord(m, info);
3903 }
3904 if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
3905 {
3906 mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
3907 RegisterAutoTunnel6Record(m, info);
3908 }
3909
3910 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
3911
3912 UpdateAutoTunnelDomainStatus(m, info);
3913 m->NextSRVUpdate = NonZeroTime(m->timenow);
3914 }
3915
3916 // Before SetupLocalAutoTunnelInterface_internal is called,
3917 // m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
3918 // Must be called with the lock held
3919 mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m, mDNSBool servicesStarting)
3920 {
3921 // 1. Configure the local IPv6 ULA BTMM address
3922 if (!m->AutoTunnelHostAddrActive)
3923 {
3924 m->AutoTunnelHostAddrActive = mDNStrue;
3925 LogInfo("SetupLocalAutoTunnelInterface_internal: Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
3926 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp, m->AutoTunnelHostAddr.b);
3927 }
3928
3929 // 2. If we have at least one server (pending) listening, publish our records
3930 // The services may not be in the list when it is first trying to resolve the target of the SRV record.
3931 // servicesStarting is an indication of that. Use that instead of looking up in the list of Services/Records.
3932 if (servicesStarting || TunnelServers(m))
3933 {
3934 DomainAuthInfo *info;
3935 for (info = m->AuthInfoList; info; info = info->next)
3936 {
3937 if (info->AutoTunnel && !info->deltime && !info->AutoTunnelNAT.clientContext)
3938 {
3939 // If we just resurrected a DomainAuthInfo that is still deregistering, we need to abort the
3940 // deregistration process before re-using the AuthRecord memory
3941 //
3942 // Note: We don't need the same caution as in SetupLocalAutoTunnel6Records (see the comments there)
3943 // as AutoTunnelRecordCallback (called as a result of AbortDeregistration) will not end up registering
3944 // the records because clientContext is still NULL
3945
3946 AbortDeregistration(m, &info->AutoTunnelTarget);
3947 AbortDeregistration(m, &info->AutoTunnelService);
3948 AbortDeregistration(m, &info->AutoTunnelHostRecord);
3949
3950 mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL,
3951 kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
3952 mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL,
3953 kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
3954 mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
3955 kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
3956
3957 // Try to get a NAT port mapping for the AutoTunnelService
3958 info->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
3959 info->AutoTunnelNAT.clientContext = info;
3960 info->AutoTunnelNAT.Protocol = NATOp_MapUDP;
3961 info->AutoTunnelNAT.IntPort = IPSECPort;
3962 info->AutoTunnelNAT.RequestedPort = IPSECPort;
3963 info->AutoTunnelNAT.NATLease = 0;
3964 mStatus err = mDNS_StartNATOperation_internal(m, &info->AutoTunnelNAT);
3965 if (err) LogMsg("SetupLocalAutoTunnelInterface_internal: error %d starting NAT mapping", err);
3966
3967 // Register the records that can be done without communicating with the NAT
3968 //
3969 // Note: This should be done after we setup the AutoTunnelNAT information
3970 // as some of the fields in that structure are used to infer other information
3971 // e.g., is it okay to register now ?
3972
3973 SetupLocalAutoTunnel6Records(m, info);
3974
3975 }
3976 }
3977 }
3978 }
3979
3980 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
3981 {
3982 mDNSv6Addr loc_outer6;
3983 mDNSv6Addr rmt_outer6;
3984
3985 // When we are tunneling over IPv6 Relay address, the port number is zero
3986 if (mDNSIPPortIsZero(tun->rmt_outer_port))
3987 {
3988 loc_outer6 = tun->loc_outer6;
3989 rmt_outer6 = tun->rmt_outer6;
3990 }
3991 else
3992 {
3993 loc_outer6 = zerov6Addr;
3994 loc_outer6.b[0] = tun->loc_outer.b[0];
3995 loc_outer6.b[1] = tun->loc_outer.b[1];
3996 loc_outer6.b[2] = tun->loc_outer.b[2];
3997 loc_outer6.b[3] = tun->loc_outer.b[3];
3998
3999 rmt_outer6 = zerov6Addr;
4000 rmt_outer6.b[0] = tun->rmt_outer.b[0];
4001 rmt_outer6.b[1] = tun->rmt_outer.b[1];
4002 rmt_outer6.b[2] = tun->rmt_outer.b[2];
4003 rmt_outer6.b[3] = tun->rmt_outer.b[3];
4004 }
4005
4006 return(mDNSAutoTunnelSetKeys(AddNew ? kmDNSAutoTunnelSetKeysReplace : kmDNSAutoTunnelSetKeysDelete, tun->loc_inner.b, loc_outer6.b, kRacoonPort, tun->rmt_inner.b, rmt_outer6.b, mDNSVal16(tun->rmt_outer_port), SkipLeadingLabels(&tun->dstname, 1)));
4007 }
4008
4009 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
4010 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
4011
4012 mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype)
4013 {
4014 DNSQuestion *q = m->Questions;
4015 while (q)
4016 {
4017 if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
4018 {
4019 LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4020 mDNSQuestionCallback *tmp = q->QuestionCallback;
4021 q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
4022 mDNS_StopQuery(m, q);
4023 mDNS_StartQuery(m, q);
4024 q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
4025 if (!success) q->NoAnswer = NoAnswer_Fail;
4026 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
4027 // In general we have to assume that the question list might have changed in arbitrary ways.
4028 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
4029 // already in use. The safest solution is just to go back to the start of the list and start again.
4030 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
4031 // just one suspended question, so it's really a 2n algorithm.
4032 q = m->Questions;
4033 }
4034 else
4035 q = q->next;
4036 }
4037 }
4038
4039 mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
4040 {
4041 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
4042 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
4043 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
4044 // even if the name does have a valid AAAA record, we don't want clients trying to connect to it without a properly encrypted tunnel.
4045 // 3. For A queries we never fabricate failures -- if a BTTM service is really using raw IPv4, then it doesn't need the IPv6 tunnel.
4046 ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA);
4047 ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A);
4048 }
4049
4050 mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
4051 {
4052 ClientTunnel **p = &m->TunnelClients;
4053 while (*p != tun && *p) p = &(*p)->next;
4054 if (*p) *p = tun->next;
4055 ReissueBlockedQuestions(m, &tun->dstname, success);
4056 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
4057 freeL("ClientTunnel", tun);
4058 }
4059
4060 mDNSlocal mDNSBool TunnelClientDeleteMatching(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
4061 {
4062 ClientTunnel **p;
4063 mDNSBool needSetKeys = mDNStrue;
4064
4065 p = &tun->next;
4066 while (*p)
4067 {
4068 // Is this a tunnel to the same host that we are trying to setup now?
4069 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4070 else
4071 {
4072 ClientTunnel *old = *p;
4073 if (v6Tunnel)
4074 {
4075 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4076 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4077 if (old->q.ThisQInterval >= 0)
4078 {
4079 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4080 mDNS_StopQuery(m, &old->q);
4081 }
4082 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4083 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4084 !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
4085 !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
4086 {
4087 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4088 // the other parameters of the tunnel are different
4089 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4090 AutoTunnelSetKeys(old, mDNSfalse);
4091 }
4092 else
4093 {
4094 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4095 // as "tun" and "old" are identical
4096 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
4097 &old->rmt_inner);
4098 needSetKeys = mDNSfalse;
4099 }
4100 }
4101 else
4102 {
4103 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4104 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4105 if (old->q.ThisQInterval >= 0)
4106 {
4107 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4108 mDNS_StopQuery(m, &old->q);
4109 }
4110 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4111 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4112 !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
4113 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
4114 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
4115 {
4116 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4117 // the other parameters of the tunnel are different
4118 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4119 AutoTunnelSetKeys(old, mDNSfalse);
4120 }
4121 else
4122 {
4123 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4124 // as "tun" and "old" are identical
4125 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
4126 &old->rmt_inner);
4127 needSetKeys = mDNSfalse;
4128 }
4129 }
4130
4131 *p = old->next;
4132 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
4133 freeL("ClientTunnel", old);
4134 }
4135 }
4136 return needSetKeys;
4137 }
4138
4139 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
4140 // tunnel will be deleted
4141 mDNSlocal void TunnelClientDeleteAny(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
4142 {
4143 ClientTunnel **p;
4144
4145 p = &tun->next;
4146 while (*p)
4147 {
4148 // If there is more than one client tunnel to the same host, delete all of them.
4149 // We do this by just checking against the EUI64 rather than the full address
4150 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4151 else
4152 {
4153 ClientTunnel *old = *p;
4154 if (v6Tunnel)
4155 {
4156 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4157 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4158 }
4159 else
4160 {
4161 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4162 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4163 }
4164 if (old->q.ThisQInterval >= 0)
4165 {
4166 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4167 mDNS_StopQuery(m, &old->q);
4168 }
4169 else
4170 {
4171 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4172 AutoTunnelSetKeys(old, mDNSfalse);
4173 }
4174 *p = old->next;
4175 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
4176 freeL("ClientTunnel", old);
4177 }
4178 }
4179 }
4180
4181 mDNSlocal void TunnelClientFinish(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer)
4182 {
4183 mDNSBool needSetKeys = mDNStrue;
4184 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4185 mDNSBool v6Tunnel = mDNSfalse;
4186
4187 // If the port is zero, then we have a relay address of the peer
4188 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4189 v6Tunnel = mDNStrue;
4190
4191 if (v6Tunnel)
4192 {
4193 LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
4194 tun->rmt_outer6 = answer->rdata->u.ipv6;
4195 tun->loc_outer6 = m->AutoTunnelRelayAddrOut;
4196 }
4197 else
4198 {
4199 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
4200 tun->rmt_outer = answer->rdata->u.ipv4;
4201 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
4202 tmpDst.ip.v4 = tun->rmt_outer;
4203 mDNSAddr tmpSrc = zeroAddr;
4204 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
4205 if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
4206 else tun->loc_outer = m->AdvertisedV4.ip.v4;
4207 }
4208
4209 question->ThisQInterval = -1; // So we know this tunnel setup has completed
4210 tun->loc_inner = m->AutoTunnelHostAddr;
4211
4212 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
4213 // look for existing tunnels to see whether they have the same information for our peer.
4214 // If not, delete them and need to create a new tunnel. If they are same, just use the
4215 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
4216 TunnelClientDeleteAny(m, tun, !v6Tunnel);
4217 needSetKeys = TunnelClientDeleteMatching(m, tun, v6Tunnel);
4218
4219 if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
4220 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
4221
4222 if (m->AutoTunnelHostAddr.b[0]) { mDNS_Lock(m); SetupLocalAutoTunnelInterface_internal(m, mDNSfalse); mDNS_Unlock(m); };
4223
4224 mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
4225 static char msgbuf[32];
4226 mDNS_snprintf(msgbuf, sizeof(msgbuf), "Tunnel setup - %d", result);
4227 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", result ? "failure" : "success", msgbuf, "");
4228 // Kick off any questions that were held pending this tunnel setup
4229 ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
4230 }
4231
4232 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
4233 {
4234 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4235
4236 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
4237
4238 if (!AddRecord) return;
4239 mDNS_StopQuery(m, question);
4240
4241 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
4242 // The code below will look for _autotunnel._udp SRV record followed by A record
4243 if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
4244 {
4245 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
4246 static char msgbuf[16];
4247 mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s lookup", DNSTypeName(question->qtype));
4248 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", "failure", msgbuf, "");
4249 UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
4250 return;
4251 }
4252
4253 switch (tun->tc_state)
4254 {
4255 case TC_STATE_AAAA_PEER:
4256 if (question->qtype != kDNSType_AAAA)
4257 {
4258 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
4259 }
4260 if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr))
4261 {
4262 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
4263 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
4264 return;
4265 }
4266 tun->rmt_inner = answer->rdata->u.ipv6;
4267 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
4268 if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddrOut))
4269 {
4270 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
4271 tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
4272 question->qtype = kDNSType_AAAA;
4273 AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
4274 }
4275 else
4276 {
4277 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
4278 tun->tc_state = TC_STATE_SRV_PEER;
4279 question->qtype = kDNSType_SRV;
4280 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4281 }
4282 AppendDomainName(&question->qname, &tun->dstname);
4283 mDNS_StartQuery(m, &tun->q);
4284 return;
4285 case TC_STATE_AAAA_PEER_RELAY:
4286 if (question->qtype != kDNSType_AAAA)
4287 {
4288 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
4289 }
4290 // If it failed, look for the SRV record.
4291 if (!answer->rdlength)
4292 {
4293 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
4294 tun->tc_state = TC_STATE_SRV_PEER;
4295 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4296 AppendDomainName(&question->qname, &tun->dstname);
4297 question->qtype = kDNSType_SRV;
4298 mDNS_StartQuery(m, &tun->q);
4299 return;
4300 }
4301 TunnelClientFinish(m, question, answer);
4302 return;
4303 case TC_STATE_SRV_PEER:
4304 if (question->qtype != kDNSType_SRV)
4305 {
4306 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
4307 }
4308 LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
4309 tun->tc_state = TC_STATE_ADDR_PEER;
4310 AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
4311 tun->rmt_outer_port = answer->rdata->u.srv.port;
4312 question->qtype = kDNSType_A;
4313 mDNS_StartQuery(m, &tun->q);
4314 return;
4315 case TC_STATE_ADDR_PEER:
4316 if (question->qtype != kDNSType_A)
4317 {
4318 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
4319 }
4320 TunnelClientFinish(m, question, answer);
4321 return;
4322 default:
4323 LogMsg("AutoTunnelCallback: Unknown question %p", question);
4324 }
4325 }
4326
4327 // Must be called with the lock held
4328 mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
4329 {
4330 ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
4331 if (!p) return;
4332 AssignDomainName(&p->dstname, &q->qname);
4333 p->MarkedForDeletion = mDNSfalse;
4334 p->loc_inner = zerov6Addr;
4335 p->loc_outer = zerov4Addr;
4336 p->loc_outer6 = zerov6Addr;
4337 p->rmt_inner = zerov6Addr;
4338 p->rmt_outer = zerov4Addr;
4339 p->rmt_outer6 = zerov6Addr;
4340 p->rmt_outer_port = zeroIPPort;
4341 p->tc_state = TC_STATE_AAAA_PEER;
4342 p->next = m->TunnelClients;
4343 m->TunnelClients = p; // We intentionally build list in reverse order
4344
4345 p->q.InterfaceID = mDNSInterface_Any;
4346 p->q.Target = zeroAddr;
4347 AssignDomainName(&p->q.qname, &q->qname);
4348 p->q.qtype = kDNSType_AAAA;
4349 p->q.qclass = kDNSClass_IN;
4350 p->q.LongLived = mDNSfalse;
4351 p->q.ExpectUnique = mDNStrue;
4352 p->q.ForceMCast = mDNSfalse;
4353 p->q.ReturnIntermed = mDNStrue;
4354 p->q.SuppressUnusable = mDNSfalse;
4355 p->q.WakeOnResolve = mDNSfalse;
4356 p->q.QuestionCallback = AutoTunnelCallback;
4357 p->q.QuestionContext = p;
4358
4359 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
4360 mDNS_StartQuery_internal(m, &p->q);
4361 }
4362
4363 #endif // APPLE_OSX_mDNSResponder
4364
4365 #if COMPILER_LIKES_PRAGMA_MARK
4366 #pragma mark -
4367 #pragma mark - Power State & Configuration Change Management
4368 #endif
4369
4370 mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
4371 {
4372 mDNSBool foundav4 = mDNSfalse;
4373 mDNSBool foundav6 = mDNSfalse;
4374 struct ifaddrs *ifa = myGetIfAddrs(1);
4375 struct ifaddrs *v4Loopback = NULL;
4376 struct ifaddrs *v6Loopback = NULL;
4377 char defaultname[64];
4378 #ifndef NO_IPV6
4379 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
4380 if (InfoSocket < 3 && errno != EAFNOSUPPORT) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
4381 #endif
4382 if (m->SleepState == SleepState_Sleeping) ifa = NULL;
4383
4384 while (ifa)
4385 {
4386 #if LIST_ALL_INTERFACES
4387 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
4388 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
4389 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4390 else if (ifa->ifa_addr->sa_family == AF_LINK)
4391 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
4392 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4393 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
4394 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
4395 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4396 if (!(ifa->ifa_flags & IFF_UP))
4397 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
4398 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4399 if (!(ifa->ifa_flags & IFF_MULTICAST))
4400 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
4401 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4402 if (ifa->ifa_flags & IFF_POINTOPOINT)
4403 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
4404 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4405 if (ifa->ifa_flags & IFF_LOOPBACK)
4406 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
4407 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4408 #endif
4409
4410 if (ifa->ifa_addr->sa_family == AF_LINK)
4411 {
4412 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
4413 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
4414 mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
4415 }
4416
4417 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
4418 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
4419 {
4420 if (!ifa->ifa_netmask)
4421 {
4422 mDNSAddr ip;
4423 SetupAddr(&ip, ifa->ifa_addr);
4424 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
4425 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
4426 }
4427 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
4428 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4429 else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0)
4430 {
4431 mDNSAddr ip;
4432 SetupAddr(&ip, ifa->ifa_addr);
4433 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
4434 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
4435 }
4436 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
4437 else if ((int)if_nametoindex(ifa->ifa_name) <= 0)
4438 {
4439 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
4440 }
4441 else
4442 {
4443 // Make sure ifa_netmask->sa_family is set correctly
4444 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4445 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
4446 int ifru_flags6 = 0;
4447 #ifndef NO_IPV6
4448 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
4449 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
4450 {
4451 struct in6_ifreq ifr6;
4452 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
4453 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
4454 ifr6.ifr_addr = *sin6;
4455 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
4456 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
4457 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
4458 }
4459 #endif
4460 if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
4461 {
4462 if (ifa->ifa_flags & IFF_LOOPBACK)
4463 {
4464 if (ifa->ifa_addr->sa_family == AF_INET) v4Loopback = ifa;
4465 #ifndef NO_IPV6
4466 else if (sin6->sin6_addr.s6_addr[0] != 0xFD) v6Loopback = ifa;
4467 #endif
4468 }
4469 else
4470 {
4471 NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
4472 if (i && MulticastInterface(i) && i->ifinfo.Advertise)
4473 {
4474 if (ifa->ifa_addr->sa_family == AF_INET) foundav4 = mDNStrue;
4475 else foundav6 = mDNStrue;
4476 }
4477 }
4478 }
4479 }
4480 }
4481 ifa = ifa->ifa_next;
4482 }
4483
4484 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
4485 if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
4486 if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
4487
4488 // Now the list is complete, set the McastTxRx setting for each interface.
4489 NetworkInterfaceInfoOSX *i;
4490 for (i = m->p->InterfaceList; i; i = i->next)
4491 if (i->Exists)
4492 {
4493 mDNSBool txrx = MulticastInterface(i);
4494 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
4495 txrx = txrx && ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
4496 #endif
4497 if (i->ifinfo.McastTxRx != txrx)
4498 {
4499 i->ifinfo.McastTxRx = txrx;
4500 i->Exists = 2; // State change; need to deregister and reregister this interface
4501 }
4502 }
4503
4504 #ifndef NO_IPV6
4505 if (InfoSocket >= 0) close(InfoSocket);
4506 #endif
4507
4508 // If we haven't set up AutoTunnelHostAddr yet, do it now
4509 if (!mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr) && m->AutoTunnelHostAddr.b[0] == 0)
4510 {
4511 m->AutoTunnelHostAddr.b[0x0] = 0xFD; // Required prefix for "locally assigned" ULA (See RFC 4193)
4512 m->AutoTunnelHostAddr.b[0x1] = mDNSRandom(255);
4513 m->AutoTunnelHostAddr.b[0x2] = mDNSRandom(255);
4514 m->AutoTunnelHostAddr.b[0x3] = mDNSRandom(255);
4515 m->AutoTunnelHostAddr.b[0x4] = mDNSRandom(255);
4516 m->AutoTunnelHostAddr.b[0x5] = mDNSRandom(255);
4517 m->AutoTunnelHostAddr.b[0x6] = mDNSRandom(255);
4518 m->AutoTunnelHostAddr.b[0x7] = mDNSRandom(255);
4519 m->AutoTunnelHostAddr.b[0x8] = m->PrimaryMAC.b[0] ^ 0x02; // See RFC 3513, Appendix A for explanation
4520 m->AutoTunnelHostAddr.b[0x9] = m->PrimaryMAC.b[1];
4521 m->AutoTunnelHostAddr.b[0xA] = m->PrimaryMAC.b[2];
4522 m->AutoTunnelHostAddr.b[0xB] = 0xFF;
4523 m->AutoTunnelHostAddr.b[0xC] = 0xFE;
4524 m->AutoTunnelHostAddr.b[0xD] = m->PrimaryMAC.b[3];
4525 m->AutoTunnelHostAddr.b[0xE] = m->PrimaryMAC.b[4];
4526 m->AutoTunnelHostAddr.b[0xF] = m->PrimaryMAC.b[5];
4527 m->AutoTunnelLabel.c[0] = mDNS_snprintf((char*)m->AutoTunnelLabel.c+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
4528 m->AutoTunnelHostAddr.b[0x8], m->AutoTunnelHostAddr.b[0x9], m->AutoTunnelHostAddr.b[0xA], m->AutoTunnelHostAddr.b[0xB],
4529 m->AutoTunnelHostAddr.b[0xC], m->AutoTunnelHostAddr.b[0xD], m->AutoTunnelHostAddr.b[0xE], m->AutoTunnelHostAddr.b[0xF]);
4530 LogInfo("m->AutoTunnelLabel %#s", m->AutoTunnelLabel.c);
4531 }
4532
4533 mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
4534 m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
4535
4536 // Set up the nice label
4537 domainlabel nicelabel;
4538 nicelabel.c[0] = 0;
4539 GetUserSpecifiedFriendlyComputerName(&nicelabel);
4540 if (nicelabel.c[0] == 0)
4541 {
4542 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
4543 MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
4544 }
4545
4546 // Set up the RFC 1034-compliant label
4547 domainlabel hostlabel;
4548 hostlabel.c[0] = 0;
4549 GetUserSpecifiedLocalHostName(&hostlabel);
4550 if (hostlabel.c[0] == 0)
4551 {
4552 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
4553 MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
4554 }
4555
4556 mDNSBool namechange = mDNSfalse;
4557
4558 // We use a case-sensitive comparison here because even though changing the capitalization
4559 // of the name alone is not significant to DNS, it's still a change from the user's point of view
4560 if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
4561 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
4562 else
4563 {
4564 if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
4565 LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
4566 m->p->usernicelabel = m->nicelabel = nicelabel;
4567 namechange = mDNStrue;
4568 }
4569
4570 if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
4571 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
4572 else
4573 {
4574 if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
4575 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
4576 m->p->userhostlabel = m->hostlabel = hostlabel;
4577 mDNS_SetFQDN(m);
4578 namechange = mDNStrue;
4579 }
4580
4581 #if APPLE_OSX_mDNSResponder
4582 if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
4583 {
4584 DomainAuthInfo *info;
4585 for (info = m->AuthInfoList; info; info = info->next)
4586 if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
4587 }
4588 #endif // APPLE_OSX_mDNSResponder
4589
4590 return(mStatus_NoError);
4591 }
4592
4593 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
4594 // Returns -1 if all the one-bits are not contiguous
4595 mDNSlocal int CountMaskBits(mDNSAddr *mask)
4596 {
4597 int i = 0, bits = 0;
4598 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
4599 while (i < bytes)
4600 {
4601 mDNSu8 b = mask->ip.v6.b[i++];
4602 while (b & 0x80) { bits++; b <<= 1; }
4603 if (b) return(-1);
4604 }
4605 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
4606 return(bits);
4607 }
4608
4609 // returns count of non-link local V4 addresses registered
4610 mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
4611 {
4612 NetworkInterfaceInfoOSX *i;
4613 int count = 0;
4614 for (i = m->p->InterfaceList; i; i = i->next)
4615 if (i->Exists)
4616 {
4617 NetworkInterfaceInfo *const n = &i->ifinfo;
4618 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
4619 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
4620
4621 if (i->Registered && i->Registered != primary) // Sanity check
4622 {
4623 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
4624 i->Registered = mDNSNULL;
4625 }
4626
4627 if (!i->Registered)
4628 {
4629 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
4630 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
4631 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it
4632 //
4633
4634 i->Registered = primary;
4635
4636 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
4637 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
4638 // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario.
4639 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
4640
4641 mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
4642
4643 if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
4644 LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
4645 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary, &n->ip, CountMaskBits(&n->mask),
4646 i->Flashing ? " (Flashing)" : "",
4647 i->Occulting ? " (Occulting)" : "",
4648 n->InterfaceActive ? " (Primary)" : "");
4649
4650 if (!n->McastTxRx)
4651 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, &n->ip);
4652 else
4653 {
4654 if (i->sa_family == AF_INET)
4655 {
4656 struct ip_mreq imr;
4657 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
4658 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
4659 imr.imr_interface = primary->ifa_v4addr;
4660
4661 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
4662 // before trying to join the group, to clear out stale kernel state which may be lingering.
4663 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
4664 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
4665 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
4666 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
4667 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
4668 // because by the time we get the configuration change notification, the interface is already gone,
4669 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
4670 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
4671 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET) == i)
4672 {
4673 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
4674 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
4675 if (err < 0 && (errno != EADDRNOTAVAIL))
4676 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
4677 }
4678
4679 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
4680 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
4681 // Joining same group twice can give "Address already in use" error -- no need to report that
4682 if (err < 0 && (errno != EADDRINUSE))
4683 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
4684 }
4685 #ifndef NO_IPV6
4686 if (i->sa_family == AF_INET6)
4687 {
4688 struct ipv6_mreq i6mr;
4689 i6mr.ipv6mr_interface = primary->scope_id;
4690 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
4691
4692 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET6) == i)
4693 {
4694 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
4695 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
4696 if (err < 0 && (errno != EADDRNOTAVAIL))
4697 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
4698 }
4699
4700 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
4701 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
4702 // Joining same group twice can give "Address already in use" error -- no need to report that
4703 if (err < 0 && (errno != EADDRINUSE))
4704 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
4705 }
4706 #endif
4707 }
4708 }
4709 }
4710
4711 return count;
4712 }
4713
4714 mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
4715 {
4716 NetworkInterfaceInfoOSX *i;
4717 for (i = m->p->InterfaceList; i; i = i->next)
4718 {
4719 if (i->Exists) i->LastSeen = utc;
4720 i->Exists = mDNSfalse;
4721 }
4722 }
4723
4724 // returns count of non-link local V4 addresses deregistered
4725 mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
4726 {
4727 // First pass:
4728 // If an interface is going away, then deregister this from the mDNSCore.
4729 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
4730 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
4731 // it refers to has gone away we'll crash.
4732 NetworkInterfaceInfoOSX *i;
4733 int count = 0;
4734 for (i = m->p->InterfaceList; i; i = i->next)
4735 {
4736 // If this interface is no longer active, or its InterfaceID is changing, deregister it
4737 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
4738 if (i->Registered)
4739 if (i->Exists == 0 || i->Exists == 2 || i->Registered != primary)
4740 {
4741 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
4742 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
4743 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary,
4744 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
4745 i->Flashing ? " (Flashing)" : "",
4746 i->Occulting ? " (Occulting)" : "",
4747 i->ifinfo.InterfaceActive ? " (Primary)" : "");
4748 mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
4749 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
4750 i->Registered = mDNSNULL;
4751 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
4752 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
4753 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
4754
4755 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
4756 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
4757 }
4758 }
4759
4760 // Second pass:
4761 // Now that everything that's going to deregister has done so, we can clean up and free the memory
4762 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
4763 while (*p)
4764 {
4765 i = *p;
4766 // If no longer active, delete interface from list and free memory
4767 if (!i->Exists)
4768 {
4769 if (i->LastSeen == utc) i->LastSeen = utc - 1;
4770 mDNSBool delete = (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0) && (utc - i->LastSeen >= 60);
4771 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
4772 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
4773 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
4774 i->ifinfo.InterfaceActive ? " (Primary)" : "");
4775 #if APPLE_OSX_mDNSResponder
4776 if (i->BPF_fd >= 0) CloseBPF(i);
4777 #endif // APPLE_OSX_mDNSResponder
4778 if (delete)
4779 {
4780 *p = i->next;
4781 freeL("NetworkInterfaceInfoOSX", i);
4782 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
4783 }
4784 }
4785 p = &i->next;
4786 }
4787 return count;
4788 }
4789
4790 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
4791 {
4792 DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
4793 if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
4794 else
4795 {
4796 dnle->next = mDNSNULL;
4797 dnle->uid = uid;
4798 AssignDomainName(&dnle->name, name);
4799 **List = dnle;
4800 *List = &dnle->next;
4801 }
4802 }
4803
4804 mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
4805 {
4806 dns_resolver_t *a = *(dns_resolver_t**)aa;
4807 dns_resolver_t *b = *(dns_resolver_t**)bb;
4808
4809 return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
4810 }
4811
4812 mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSBool scope, mDNSBool setsearch, mDNSBool setservers)
4813 {
4814 int i;
4815 domainname d;
4816 #if DNSINFO_VERSION >= 20091104
4817 dns_resolver_t **resolver = scope ? config->scoped_resolver : config->resolver;
4818 int nresolvers = scope ? config->n_scoped_resolver : config->n_resolver;
4819 #else
4820 (void) scope; // unused
4821 dns_resolver_t **resolver = config->resolver;
4822 int nresolvers = config->n_resolver;
4823 #endif
4824
4825 // Currently we don't support search lists for scoped resolvers. The WAB support for this will be added later.
4826 if (setsearch && !scope && nresolvers)
4827 {
4828 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
4829 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
4830 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
4831 // instead use the search domain list as the sole authority for what domains to search and in what order
4832 // (and the domain from the "domain" field will also appear somewhere in that list).
4833 // Also, all search domains get added to the search list for resolver[0], so the domains and/or
4834 // search lists for other resolvers in the list need to be ignored.
4835 //
4836 // Note: Starting DNSINFO_VERSION 20091104, search list is present only in the first resolver (resolver 0).
4837 // i.e., n_search for the first resolver is always non-zero. We don't guard it with #ifs for better readability
4838
4839 if (resolver[0]->n_search == 0)
4840 {
4841 LogInfo("ConfigResolvers: (%s) configuring zeroth domain as search list %s", scope ? "Scoped" : "Non-scoped", resolver[0]->domain);
4842 mDNS_AddSearchDomain_CString(resolver[0]->domain);
4843 }
4844 else
4845 {
4846 for (i = 0; i < resolver[0]->n_search; i++)
4847 {
4848 LogInfo("ConfigResolvers: (%s) configuring search list %s", scope ? "Scoped" : "Non-scoped", resolver[0]->search[i]);
4849 mDNS_AddSearchDomain_CString(resolver[0]->search[i]);
4850 }
4851 }
4852 }
4853
4854 if (!setservers) return;
4855
4856 // For the "default" resolver ("resolver #1") the "domain" value is bogus and we need to ignore it.
4857 // e.g. the default resolver's "domain" value might say "apple.com", which indicates that this resolver
4858 // is only for names that fall under "apple.com", but that's not correct. Actually the default resolver is
4859 // for all names not covered by a more specific resolver (i.e. its domain should be ".", the root domain).
4860 //
4861 // Note: Starting DNSINFO_VERSION 20091104, domain value of this first resolver (resolver 0) is always NULL.
4862 // We don't guard it with #ifs for better readability
4863 //
4864 if ((nresolvers != 0) && resolver[0]->domain)
4865 resolver[0]->domain[0] = 0; // don't stop pointing at the memory, just change the first byte
4866
4867 qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
4868
4869 for (i = 0; i < nresolvers; i++)
4870 {
4871 int n;
4872 dns_resolver_t *r = resolver[i];
4873 mDNSInterfaceID interface = mDNSInterface_Any;
4874 int disabled = 0;
4875
4876 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scope ? "Scoped" : "", i, r->domain, r->n_nameserver);
4877
4878 // On Tiger, dnsinfo entries for mDNS domains have port 5353, the mDNS port. Ignore them.
4879 // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
4880 // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
4881 // We also don't need to do any more work if there are no nameserver addresses
4882 if (r->port == 5353 || r->n_nameserver == 0) continue;
4883
4884 if (!r->domain || !*r->domain) d.c[0] = 0;
4885 else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
4886 { LogMsg("ConfigResolvers: config->resolver[%d] bad domain %s", i, r->domain); continue; }
4887
4888 // DNS server option parsing
4889 if (r->options != NULL)
4890 {
4891 char *nextOption = r->options;
4892 char *currentOption = NULL;
4893 while ((currentOption = strsep(&nextOption, " ")) != NULL && currentOption[0] != 0)
4894 {
4895 // The option may be in the form of interface=xxx where xxx is an interface name.
4896 if (strncmp(currentOption, kInterfaceSpecificOption, sizeof(kInterfaceSpecificOption) - 1) == 0)
4897 {
4898 NetworkInterfaceInfoOSX *ni;
4899 char ifname[IF_NAMESIZE+1];
4900 mDNSu32 ifindex = 0;
4901 // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
4902 // This allows us to block these special queries from going out on the wire.
4903 strlcpy(ifname, currentOption + sizeof(kInterfaceSpecificOption)-1, sizeof(ifname));
4904 ifindex = if_nametoindex(ifname);
4905 if (ifindex == 0) { disabled = 1; LogMsg("ConfigResolvers: RegisterSplitDNS interface specific - interface %s not found", ifname); continue; }
4906 LogInfo("ConfigResolvers: interface specific entry: %s on %s (%d)", r->domain, ifname, ifindex);
4907 // Find the interface. Can't use mDNSPlatformInterfaceIDFromInterfaceIndex
4908 // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
4909 for (ni = m->p->InterfaceList; ni; ni = ni->next)
4910 if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex) break;
4911 if (ni != NULL) interface = ni->ifinfo.InterfaceID;
4912 if (interface == mDNSNULL)
4913 {
4914 disabled = 1;
4915 LogMsg("ConfigResolvers: RegisterSplitDNS interface specific - index %d (%s) not found", ifindex, ifname);
4916 continue;
4917 }
4918 }
4919 }
4920 }
4921
4922 // flags and if_index are defined only from this DNSINFO_VERSION onwards. Currently these
4923 // fields are zero for non-scoped resolvers. For now, these fields have non-zero values only
4924 // for scoped_resolvers.
4925 #if DNSINFO_VERSION >= 20091104
4926 if (scope && (r->flags & DNS_RESOLVER_FLAGS_SCOPED) && (r->if_index != 0))
4927 {
4928 NetworkInterfaceInfoOSX *ni;
4929 interface = mDNSNULL;
4930 for (ni = m->p->InterfaceList; ni; ni = ni->next)
4931 if (ni->ifinfo.InterfaceID && ni->scope_id == r->if_index) break;
4932 if (ni != NULL) interface = ni->ifinfo.InterfaceID;
4933 if (interface == mDNSNULL)
4934 {
4935 disabled = 1;
4936 LogMsg("ConfigResolvers: interface specific index %d not found", r->if_index);
4937 continue;
4938 }
4939 }
4940 #endif
4941
4942 for (n = 0; n < r->n_nameserver; n++)
4943 if (r->nameserver[n]->sa_family == AF_INET || r->nameserver[n]->sa_family == AF_INET6)
4944 {
4945 mDNSAddr saddr;
4946 // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
4947 if (SetupAddr(&saddr, r->nameserver[n])) LogMsg("RegisterSplitDNS: bad IP address");
4948 else
4949 {
4950 mDNSBool scopedDNS = mDNSfalse;
4951 DNSServer *s;
4952 #if DNSINFO_VERSION >= 20091104
4953 // By setting scoped, this DNSServer can only be picked if the right interfaceID
4954 // is given in the question
4955 if (scope && (r->flags & DNS_RESOLVER_FLAGS_SCOPED) && (interface == mDNSNULL))
4956 LogMsg("ConfigResolvers: ERROR: scoped is set but if_index %d is invalid for DNSServer %#a:%d", r->if_index, &saddr, mDNSVal16(r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort));
4957 else
4958 scopedDNS = (scope && (r->flags & DNS_RESOLVER_FLAGS_SCOPED)) ? mDNStrue : mDNSfalse;
4959 #endif
4960 s = mDNS_AddDNSServer(m, &d, interface, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scopedDNS);
4961 if (s)
4962 {
4963 if (disabled) s->teststate = DNSServer_Disabled;
4964 LogInfo("ConfigResolvers: DNS server %#a:%d for domain %##s from slot %d,%d", &s->addr, mDNSVal16(s->port), d.c, i, n);
4965 }
4966 }
4967 }
4968 }
4969 }
4970
4971 mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
4972 {
4973 int i;
4974 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
4975 domainname d;
4976
4977 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
4978 if (fqdn) fqdn->c[0] = 0;
4979 if (RegDomains ) *RegDomains = NULL;
4980 if (BrowseDomains) *BrowseDomains = NULL;
4981
4982 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
4983 setservers ? " setservers" : "",
4984 setsearch ? " setsearch" : "",
4985 fqdn ? " fqdn" : "",
4986 RegDomains ? " RegDomains" : "",
4987 BrowseDomains ? " BrowseDomains" : "");
4988
4989 // Add the inferred address-based configuration discovery domains
4990 // (should really be in core code I think, not platform-specific)
4991 if (setsearch)
4992 {
4993 struct ifaddrs *ifa = mDNSNULL;
4994 struct sockaddr_in saddr;
4995 mDNSPlatformMemZero(&saddr, sizeof(saddr));
4996 saddr.sin_len = sizeof(saddr);
4997 saddr.sin_family = AF_INET;
4998 saddr.sin_port = 0;
4999 saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
5000
5001 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
5002 if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1);
5003
5004 while (ifa)
5005 {
5006 mDNSAddr a, n;
5007 if (ifa->ifa_addr->sa_family == AF_INET &&
5008 ifa->ifa_netmask &&
5009 !(ifa->ifa_flags & IFF_LOOPBACK) &&
5010 !SetupAddr(&a, ifa->ifa_addr) &&
5011 !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
5012 {
5013 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be incorrect, so we explicitly fix it here before calling SetupAddr
5014 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5015 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; // Make sure ifa_netmask->sa_family is set correctly
5016 SetupAddr(&n, ifa->ifa_netmask);
5017 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
5018 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
5019 a.ip.v4.b[2] & n.ip.v4.b[2],
5020 a.ip.v4.b[1] & n.ip.v4.b[1],
5021 a.ip.v4.b[0] & n.ip.v4.b[0]);
5022 mDNS_AddSearchDomain_CString(buf);
5023 }
5024 ifa = ifa->ifa_next;
5025 }
5026 }
5027
5028 #ifndef MDNS_NO_DNSINFO
5029 if (setservers || setsearch)
5030 {
5031 dns_config_t *config = dns_configuration_copy();
5032 if (!config)
5033 {
5034 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
5035 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
5036 // Apparently this is expected behaviour -- "not a bug".
5037 // Accordingly, we suppress syslog messages for the first three minutes after boot.
5038 // If we are still getting failures after three minutes, then we log them.
5039 if (OSXVers > OSXVers_10_3_Panther && (mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
5040 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
5041 }
5042 else
5043 {
5044 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config->n_resolver);
5045
5046 #if APPLE_OSX_mDNSResponder
5047 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
5048 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
5049 if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver && config->resolver[0]->nameserver[0])
5050 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
5051 else ActiveDirectoryPrimaryDomain.c[0] = 0;
5052 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
5053 ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
5054 if (config->n_resolver && config->resolver[0]->n_nameserver && SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
5055 SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
5056 else
5057 {
5058 AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
5059 ActiveDirectoryPrimaryDomainLabelCount = 0;
5060 ActiveDirectoryPrimaryDomainServer = zeroAddr;
5061 }
5062 #endif
5063
5064 ConfigResolvers(m, config, mDNSfalse, setsearch, setservers);
5065 #if DNSINFO_VERSION >= 20091104
5066 ConfigResolvers(m, config, mDNStrue, setsearch, setservers);
5067 #endif
5068 dns_configuration_free(config);
5069 setservers = mDNSfalse; // Done these now -- no need to fetch the same data from SCDynamicStore
5070 setsearch = mDNSfalse;
5071 }
5072 }
5073 #endif // MDNS_NO_DNSINFO
5074
5075 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL);
5076 if (!store)
5077 LogMsg("mDNSPlatformSetDNSConfig: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5078 else
5079 {
5080 CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
5081 if (ddnsdict)
5082 {
5083 if (fqdn)
5084 {
5085 CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
5086 if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
5087 {
5088 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
5089 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
5090 if (fqdnDict && DictionaryIsEnabled(fqdnDict))
5091 {
5092 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
5093 if (name)
5094 {
5095 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5096 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
5097 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
5098 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
5099 }
5100 }
5101 }
5102 }
5103
5104 if (RegDomains)
5105 {
5106 CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
5107 if (regArray && CFArrayGetCount(regArray) > 0)
5108 {
5109 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
5110 if (regDict && DictionaryIsEnabled(regDict))
5111 {
5112 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
5113 if (name)
5114 {
5115 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5116 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
5117 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
5118 else
5119 {
5120 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
5121 AppendDNameListElem(&RegDomains, 0, &d);
5122 }
5123 }
5124 }
5125 }
5126 }
5127
5128 if (BrowseDomains)
5129 {
5130 CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
5131 if (browseArray)
5132 {
5133 for (i = 0; i < CFArrayGetCount(browseArray); i++)
5134 {
5135 CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
5136 if (browseDict && DictionaryIsEnabled(browseDict))
5137 {
5138 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
5139 if (name)
5140 {
5141 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5142 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
5143 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
5144 else
5145 {
5146 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
5147 AppendDNameListElem(&BrowseDomains, 0, &d);
5148 }
5149 }
5150 }
5151 }
5152 }
5153 }
5154 CFRelease(ddnsdict);
5155 }
5156
5157 if (RegDomains)
5158 {
5159 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
5160 if (btmm)
5161 {
5162 CFIndex size = CFDictionaryGetCount(btmm);
5163 const void *key[size];
5164 const void *val[size];
5165 CFDictionaryGetKeysAndValues(btmm, key, val);
5166 for (i = 0; i < size; i++)
5167 {
5168 LogInfo("BackToMyMac %d", i);
5169 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
5170 LogMsg("Can't read BackToMyMac %d key %s", i, buf);
5171 else
5172 {
5173 mDNSu32 uid = atoi(buf);
5174 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
5175 LogMsg("Can't read BackToMyMac %d val %s", i, buf);
5176 else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
5177 {
5178 LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
5179 AppendDNameListElem(&RegDomains, uid, &d);
5180 }
5181 }
5182 }
5183 CFRelease(btmm);
5184 }
5185 }
5186
5187 if (setservers || setsearch)
5188 {
5189 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DNS);
5190 if (dict)
5191 {
5192 if (setservers)
5193 {
5194 CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
5195 if (values)
5196 {
5197 LogInfo("DNS Server Address values: %d", (int)CFArrayGetCount(values));
5198 for (i = 0; i < CFArrayGetCount(values); i++)
5199 {
5200 CFStringRef s = CFArrayGetValueAtIndex(values, i);
5201 mDNSAddr addr = { mDNSAddrType_IPv4, { { { 0 } } } };
5202 if (s && CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8) &&
5203 inet_aton(buf, (struct in_addr *) &addr.ip.v4))
5204 {
5205 LogInfo("Adding DNS server from dict: %s", buf);
5206 mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort, mDNSfalse);
5207 }
5208 }
5209 }
5210 else LogInfo("No DNS Server Address values");
5211 }
5212 if (setsearch)
5213 {
5214 // Add the manual and/or DHCP-dicovered search domains
5215 CFArrayRef searchDomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
5216 if (searchDomains)
5217 {
5218 for (i = 0; i < CFArrayGetCount(searchDomains); i++)
5219 {
5220 CFStringRef s = CFArrayGetValueAtIndex(searchDomains, i);
5221 if (s && CFStringGetCString(s, buf, sizeof(buf), kCFStringEncodingUTF8))
5222 mDNS_AddSearchDomain_CString(buf);
5223 }
5224 }
5225 else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
5226 {
5227 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
5228 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
5229 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
5230 // instead use the search domain list as the sole authority for what domains to search and in what order
5231 // (and the domain from the "domain" field will also appear somewhere in that list).
5232 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
5233 if (string && CFStringGetCString(string, buf, sizeof(buf), kCFStringEncodingUTF8))
5234 mDNS_AddSearchDomain_CString(buf);
5235 }
5236 }
5237 CFRelease(dict);
5238 }
5239 }
5240 CFRelease(store);
5241 }
5242 }
5243
5244 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
5245 {
5246 char buf[256];
5247 (void)m; // Unused
5248
5249 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
5250 if (!store)
5251 LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5252 else
5253 {
5254 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_IPv4);
5255 if (dict)
5256 {
5257 r->type = mDNSAddrType_IPv4;
5258 r->ip.v4 = zerov4Addr;
5259 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
5260 if (string)
5261 {
5262 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
5263 LogMsg("Could not convert router to CString");
5264 else
5265 {
5266 struct sockaddr_in saddr;
5267 saddr.sin_len = sizeof(saddr);
5268 saddr.sin_family = AF_INET;
5269 saddr.sin_port = 0;
5270 inet_aton(buf, &saddr.sin_addr);
5271
5272 *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
5273 }
5274 }
5275
5276 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
5277 if (string)
5278 {
5279 mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
5280 struct ifaddrs *ifa = myGetIfAddrs(1);
5281
5282 *v4 = *v6 = zeroAddr;
5283
5284 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; }
5285
5286 // find primary interface in list
5287 while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
5288 {
5289 mDNSAddr tmp6 = zeroAddr;
5290 if (!strcmp(buf, ifa->ifa_name))
5291 {
5292 if (ifa->ifa_addr->sa_family == AF_INET)
5293 {
5294 if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr);
5295 }
5296 else if (ifa->ifa_addr->sa_family == AF_INET6)
5297 {
5298 SetupAddr(&tmp6, ifa->ifa_addr);
5299 if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
5300 { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; }
5301 }
5302 }
5303 else
5304 {
5305 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
5306 if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
5307 {
5308 SetupAddr(&tmp6, ifa->ifa_addr);
5309 if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6;
5310 }
5311 }
5312 ifa = ifa->ifa_next;
5313 }
5314
5315 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
5316 // V4 to communicate w/ our DNS server
5317 }
5318
5319 exit:
5320 CFRelease(dict);
5321 }
5322 CFRelease(store);
5323 }
5324 return mStatus_NoError;
5325 }
5326
5327 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
5328 {
5329 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
5330 char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
5331 ConvertDomainNameToCString(dname, uname);
5332
5333 char *p = uname;
5334 while (*p)
5335 {
5336 *p = tolower(*p);
5337 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
5338 p++;
5339 }
5340
5341 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
5342 // That single entity is a CFDictionary with name "HostNames".
5343 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
5344 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
5345 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
5346 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
5347 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
5348
5349 const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
5350 const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
5351 const CFStringRef StatusKeys[1] = { CFSTR("Status") };
5352 if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
5353 else
5354 {
5355 const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
5356 if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
5357 else
5358 {
5359 const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
5360 if (HostVals[0])
5361 {
5362 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
5363 if (StateVals[0])
5364 {
5365 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
5366 if (StateDict)
5367 {
5368 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
5369 CFRelease(StateDict);
5370 }
5371 CFRelease(StateVals[0]);
5372 }
5373 CFRelease(HostVals[0]);
5374 }
5375 CFRelease(StatusVals[0]);
5376 }
5377 CFRelease(HostKeys[0]);
5378 }
5379 }
5380
5381 #if APPLE_OSX_mDNSResponder
5382 #if ! NO_AWACS
5383
5384 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
5385 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
5386 // help catch it
5387 mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
5388 {
5389 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
5390 if (!store)
5391 {
5392 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5393 return mDNSfalse;
5394 }
5395 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
5396 if (btmm)
5397 {
5398 CFIndex size = CFDictionaryGetCount(btmm);
5399 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
5400 const void *key[size];
5401 const void *val[size];
5402 domainname dom;
5403 int i;
5404 CFDictionaryGetKeysAndValues(btmm, key, val);
5405 for (i = 0; i < size; i++)
5406 {
5407 LogInfo("BackToMyMac %d", i);
5408 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
5409 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
5410 else
5411 {
5412 mDNSu32 uid = atoi(buf);
5413 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
5414 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
5415 else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
5416 {
5417 if (SameDomainName(&dom, d))
5418 {
5419 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
5420 CFRelease(btmm);
5421 CFRelease(store);
5422 return mDNStrue;
5423 }
5424 }
5425 }
5426 }
5427 CFRelease(btmm);
5428 }
5429 CFRelease(store);
5430 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
5431 return mDNSfalse;
5432 }
5433
5434 // Appends data to the buffer
5435 mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
5436 {
5437 int len;
5438
5439 len = strlcpy(buf + *currlen, data, bufsz - *currlen);
5440 if (len >= (bufsz - *currlen))
5441 {
5442 // if we have exceeded the space in buf, it has already been NULL terminated
5443 // and we have nothing more to do. Set currlen to the last byte so that the caller
5444 // knows to do the right thing
5445 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
5446 *currlen = bufsz - 1;
5447 return -1;
5448 }
5449 else { (*currlen) += len; }
5450
5451 buf[*currlen] = ',';
5452 if (*currlen >= bufsz)
5453 {
5454 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
5455 *currlen = bufsz - 1;
5456 buf[*currlen] = 0;
5457 return -1;
5458 }
5459 // if we have filled up the buffer exactly, then there is no more work to do
5460 if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
5461 (*currlen)++;
5462 return *currlen;
5463 }
5464
5465 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
5466 // BTMM domains, then bring down the connection to the relay.
5467 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
5468 {
5469 DomainAuthInfo *BTMMDomain = mDNSNULL;
5470 DomainAuthInfo *FoundInList;
5471 static mDNSBool AWACSDConnected = mDNSfalse;
5472 char AllUsers[1024]; // maximum size of mach message
5473 char AllPass[1024]; // maximum size of mach message
5474 char username[MAX_DOMAIN_LABEL + 1];
5475 int currulen = 0;
5476 int currplen = 0;
5477
5478 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
5479 // we may not be able to send the dns queries over the relay connection which may be needed
5480 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
5481 // need to make sure that we send the disconnect before attempting the next connect as the
5482 // awacs connections are redirected based on usernames.
5483 //
5484 // For now we send a disconnect immediately. When we start sending dns queries over the relay
5485 // connection, we will need to fix this.
5486
5487 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
5488 if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
5489 {
5490 // We need the passwd from the first domain.
5491 BTMMDomain = FoundInList;
5492 ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
5493 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
5494 if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
5495 if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
5496 }
5497
5498 if (BTMMDomain)
5499 {
5500 // In the normal case (where we neither exceed the buffer size nor write bytes that
5501 // fit exactly into the buffer), currulen/currplen should be a different size than
5502 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
5503
5504 if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
5505 if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
5506
5507 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
5508 AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
5509 AWACSDConnected = mDNStrue;
5510 }
5511 else
5512 {
5513 // Disconnect only if we connected previously
5514 if (AWACSDConnected)
5515 {
5516 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
5517 AWACS_Disconnect();
5518 AWACSDConnected = mDNSfalse;
5519 }
5520 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
5521 }
5522 }
5523 #else
5524 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
5525 {
5526 (void) m; // Unused
5527 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
5528 }
5529 #endif // ! NO_AWACS
5530 #endif // APPLE_OSX_mDNSResponder
5531
5532 // MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
5533 mDNSexport void SetDomainSecrets(mDNS *m)
5534 {
5535 #ifdef NO_SECURITYFRAMEWORK
5536 (void)m;
5537 LogMsg("Note: SetDomainSecrets: no keychain support");
5538 #else
5539 mDNSBool haveAutoTunnels = mDNSfalse;
5540
5541 LogInfo("SetDomainSecrets");
5542
5543 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
5544 // In the case where the user simultaneously removes their DDNS host name and the key
5545 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
5546 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
5547 // address records behind that we no longer have permission to delete.
5548 DomainAuthInfo *ptr;
5549 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
5550 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
5551
5552 #if APPLE_OSX_mDNSResponder
5553 {
5554 // Mark all TunnelClients for deletion
5555 ClientTunnel *client;
5556 for (client = m->TunnelClients; client; client = client->next)
5557 {
5558 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
5559 client->MarkedForDeletion = mDNStrue;
5560 }
5561 }
5562 #endif // APPLE_OSX_mDNSResponder
5563
5564 // String Array used to write list of private domains to Dynamic Store
5565 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
5566 if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
5567 CFIndex i;
5568 CFDataRef data = NULL;
5569 const int itemsPerEntry = 3; // domain name, key name, key value
5570 CFArrayRef secrets = NULL;
5571 int err = mDNSKeychainGetSecrets(&secrets);
5572 if (err || !secrets)
5573 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
5574 else
5575 {
5576 CFIndex ArrayCount = CFArrayGetCount(secrets);
5577 // Iterate through the secrets
5578 for (i = 0; i < ArrayCount; ++i)
5579 {
5580 int j;
5581 CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
5582 if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
5583 { LogMsg("SetDomainSecrets: malformed entry"); continue; }
5584 for (j = 0; j < CFArrayGetCount(entry); ++j)
5585 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
5586 { LogMsg("SetDomainSecrets: malformed entry item"); continue; }
5587
5588 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
5589
5590 // Get DNS domain this key is for
5591 char stringbuf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal domainname as C-string, including terminating NUL
5592 data = CFArrayGetValueAtIndex(entry, 0);
5593 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
5594 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
5595 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
5596 stringbuf[CFDataGetLength(data)] = '\0';
5597
5598 domainname domain;
5599 if (!MakeDomainNameFromDNSNameString(&domain, stringbuf)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
5600
5601 // Get key name
5602 data = CFArrayGetValueAtIndex(entry, 1);
5603 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
5604 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
5605 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
5606 stringbuf[CFDataGetLength(data)] = '\0';
5607
5608 domainname keyname;
5609 if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
5610
5611 // Get key data
5612 data = CFArrayGetValueAtIndex(entry, 2);
5613 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
5614 { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data)); continue; }
5615 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
5616 stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
5617
5618 DomainAuthInfo *FoundInList;
5619 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
5620 if (SameDomainName(&FoundInList->domain, &domain)) break;
5621
5622 #if APPLE_OSX_mDNSResponder
5623 if (FoundInList)
5624 {
5625 // If any client tunnel destination is in this domain, set deletion flag to false
5626 ClientTunnel *client;
5627 for (client = m->TunnelClients; client; client = client->next)
5628 if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
5629 {
5630 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
5631 client->MarkedForDeletion = mDNSfalse;
5632 }
5633 }
5634
5635 #endif // APPLE_OSX_mDNSResponder
5636
5637 // Uncomment the line below to view the keys as they're read out of the system keychain
5638 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
5639 //LogInfo("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, stringbuf);
5640
5641 // If didn't find desired domain in the list, make a new entry
5642 ptr = FoundInList;
5643 if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
5644 if (!FoundInList)
5645 {
5646 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
5647 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
5648 }
5649
5650 LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
5651 if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, IsTunnelModeDomain(&domain)) == mStatus_BadParamErr)
5652 {
5653 if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
5654 continue;
5655 }
5656
5657 #if APPLE_OSX_mDNSResponder
5658 if (ptr->AutoTunnel) UpdateAutoTunnelDomainStatus(m, ptr);
5659 #endif // APPLE_OSX_mDNSResponder
5660
5661 ConvertDomainNameToCString(&domain, stringbuf);
5662 CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
5663 if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
5664 }
5665 CFRelease(secrets);
5666 }
5667 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, sa);
5668 CFRelease(sa);
5669
5670 #if APPLE_OSX_mDNSResponder
5671 {
5672 // clean up ClientTunnels
5673 ClientTunnel **pp = &m->TunnelClients;
5674 while (*pp)
5675 {
5676 if ((*pp)->MarkedForDeletion)
5677 {
5678 ClientTunnel *cur = *pp;
5679 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
5680 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
5681 AutoTunnelSetKeys(cur, mDNSfalse);
5682 *pp = cur->next;
5683 freeL("ClientTunnel", cur);
5684 }
5685 else
5686 pp = &(*pp)->next;
5687 }
5688
5689 DomainAuthInfo *info = m->AuthInfoList;
5690 while (info)
5691 {
5692 if (info->AutoTunnel && info->deltime)
5693 {
5694 if (info->AutoTunnelNAT.clientContext)
5695 {
5696 // stop the NAT operation
5697 mDNS_StopNATOperation_internal(m, &info->AutoTunnelNAT);
5698 if (info->AutoTunnelNAT.clientCallback)
5699 {
5700 // Reset port and cleanup the state
5701 info->AutoTunnelNAT.ExternalAddress = m->ExternalAddress;
5702 info->AutoTunnelNAT.ExternalPort = zeroIPPort;
5703 info->AutoTunnelNAT.RequestedPort = zeroIPPort;
5704 info->AutoTunnelNAT.Lifetime = 0;
5705 info->AutoTunnelNAT.Result = mStatus_NoError;
5706 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
5707 AutoTunnelDeleteAuthInfoState(m, info);
5708 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
5709 }
5710 info->AutoTunnelNAT.clientContext = mDNSNULL;
5711 }
5712 RemoveAutoTunnelDomainStatus(m, info);
5713 }
5714 info = info->next;
5715 }
5716
5717 if (!haveAutoTunnels && !m->TunnelClients && m->AutoTunnelHostAddrActive)
5718 {
5719 // remove interface if no autotunnel servers and no more client tunnels
5720 LogInfo("SetDomainSecrets: Bringing tunnel interface DOWN");
5721 m->AutoTunnelHostAddrActive = mDNSfalse;
5722 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
5723 mDNSPlatformMemZero(m->AutoTunnelHostAddr.b, sizeof(m->AutoTunnelHostAddr.b));
5724 }
5725
5726 if (m->AutoTunnelHostAddr.b[0])
5727 if (TunnelClients(m) || TunnelServers(m))
5728 SetupLocalAutoTunnelInterface_internal(m, mDNSfalse);
5729
5730 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
5731 UpdateBTMMRelayConnection(m);
5732 }
5733 #endif // APPLE_OSX_mDNSResponder
5734
5735 CheckSuppressUnusableQuestions(m);
5736
5737 #endif /* NO_SECURITYFRAMEWORK */
5738 }
5739
5740 mDNSlocal void SetLocalDomains(void)
5741 {
5742 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
5743 if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
5744
5745 CFArrayAppendValue(sa, CFSTR("local"));
5746 CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
5747 CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
5748 CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
5749 CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
5750 CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
5751
5752 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
5753 CFRelease(sa);
5754 }
5755
5756 mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
5757 {
5758 #if USE_IOPMCOPYACTIVEPMPREFERENCES
5759 CFTypeRef blob = NULL;
5760 CFStringRef str = NULL;
5761 CFDictionaryRef odict = NULL;
5762 CFDictionaryRef idict = NULL;
5763 CFNumberRef number = NULL;
5764
5765 blob = IOPSCopyPowerSourcesInfo();
5766 if (!blob) { LogMsg("GetCurrentPMSetting: IOPSCopyPowerSourcesInfo failed!"); goto end; }
5767
5768 odict = IOPMCopyActivePMPreferences();
5769 if (!odict) { LogMsg("GetCurrentPMSetting: IOPMCopyActivePMPreferences failed!"); goto end; }
5770
5771 str = IOPSGetProvidingPowerSourceType(blob);
5772 if (!str) { LogMsg("GetCurrentPMSetting: IOPSGetProvidingPowerSourceType failed!"); goto end; }
5773
5774 idict = CFDictionaryGetValue(odict, str);
5775 if (!idict)
5776 {
5777 char buf[256];
5778 if (!CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
5779 LogMsg("GetCurrentPMSetting: CFDictionaryGetValue (%s) failed!", buf);
5780 goto end;
5781 }
5782
5783 number = CFDictionaryGetValue(idict, name);
5784 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
5785 *val = 0;
5786 end:
5787 if (blob) CFRelease(blob);
5788 if (odict) CFRelease(odict);
5789
5790 #else
5791
5792 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetCurrentPMSetting"), NULL, NULL);
5793 if (!store) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5794 else
5795 {
5796 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
5797 if (!dict) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
5798 else
5799 {
5800 CFNumberRef number = CFDictionaryGetValue(dict, name);
5801 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
5802 *val = 0;
5803 CFRelease(dict);
5804 }
5805 CFRelease(store);
5806 }
5807
5808 #endif
5809 }
5810
5811 #if APPLE_OSX_mDNSResponder
5812
5813 static CFMutableDictionaryRef spsStatusDict = NULL;
5814 static const CFStringRef kMetricRef = CFSTR("Metric");
5815
5816 mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
5817 {
5818 mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
5819 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
5820 if (!num)
5821 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
5822 else
5823 {
5824 CFDictionarySetValue(dict, key, num);
5825 CFRelease(num);
5826 }
5827 }
5828
5829 mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
5830 {
5831 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
5832 if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
5833
5834 char buffer[1024];
5835 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
5836 CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
5837 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
5838 CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
5839 CFRelease(spsname);
5840
5841 if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
5842 if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
5843 if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
5844 if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
5845
5846 mDNSu32 tmp = SPSMetric(ptr);
5847 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
5848 if (!num)
5849 LogMsg("SPSCreateDict: Could not create CFNumber");
5850 else
5851 {
5852 CFDictionarySetValue(dict, kMetricRef, num);
5853 CFRelease(num);
5854 }
5855
5856 if (ptr[0] >= 12)
5857 {
5858 memcpy(buffer, ptr + 13, ptr[0] - 12);
5859 buffer[ptr[0] - 12] = 0;
5860 spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
5861 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
5862 else
5863 {
5864 CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
5865 CFRelease(spsname);
5866 }
5867 }
5868
5869 return dict;
5870 }
5871
5872 mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
5873 {
5874 (void)context;
5875 return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
5876 (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
5877 NULL);
5878 }
5879
5880 mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
5881 {
5882 NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
5883 debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
5884
5885 mDNS_Lock(m);
5886 mDNS_UpdateAllowSleep(m);
5887 mDNS_Unlock(m);
5888
5889 if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names
5890
5891 if (!spsStatusDict)
5892 {
5893 spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
5894 if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
5895 }
5896
5897 CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
5898 if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
5899
5900 CFMutableArrayRef array = NULL;
5901
5902 if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
5903 {
5904 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
5905 if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
5906 CFDictionarySetValue(spsStatusDict, ifname, array);
5907 CFRelease(array); // let go of our reference, now that the dict has one
5908 }
5909 else
5910 if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
5911
5912 if (!answer) // special call that means the question has been stopped (because the interface is going away)
5913 CFArrayRemoveAllValues(array);
5914 else
5915 {
5916 CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
5917 if (!dict) { CFRelease(ifname); return; }
5918
5919 if (AddRecord)
5920 {
5921 if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
5922 {
5923 int i=0;
5924 for (i=0; i<CFArrayGetCount(array); i++)
5925 if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
5926 break;
5927 CFArrayInsertValueAtIndex(array, i, dict);
5928 }
5929 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
5930 }
5931 else
5932 {
5933 CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
5934 if (i != -1) CFArrayRemoveValueAtIndex(array, i);
5935 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
5936 }
5937
5938 CFRelease(dict);
5939 }
5940
5941 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
5942
5943 CFRelease(ifname);
5944 }
5945
5946 mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
5947 {
5948 mDNSs32 val = -1;
5949 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
5950 if (!store)
5951 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5952 else
5953 {
5954 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
5955 if (dict)
5956 {
5957 CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
5958 if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
5959 CFRelease(dict);
5960 }
5961 CFRelease(store);
5962 }
5963 return val;
5964 }
5965
5966 mDNSlocal void SetSPS(mDNS *const m)
5967 {
5968 SCPreferencesSynchronize(m->p->SCPrefs);
5969 CFDictionaryRef dict = SCPreferencesGetValue(m->p->SCPrefs, CFSTR("NAT"));
5970 mDNSBool natenabled = (dict && (CFGetTypeID(dict) == CFDictionaryGetTypeID()) && DictionaryIsEnabled(dict));
5971 mDNSu8 sps = natenabled ? 50 : (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? OfferSleepProxyService : 0;
5972
5973 // For devices that are not running NAT, but are set to never sleep, we may choose to act
5974 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
5975 if (sps > 50 && SPMetricPortability > 35) sps = 0;
5976
5977 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
5978
5979 // For devices that are unable to sleep at all to save power (e.g. the current Apple TV hardware)
5980 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
5981 // We rate such a device as metric 70 ("Incidentally Available Hardware")
5982 if (SPMetricMarginalPower == 10 && (!sps || sps > 70)) sps = 70;
5983
5984 mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower);
5985 }
5986
5987 mDNSlocal void InternetSharingChanged(SCPreferencesRef prefs, SCPreferencesNotification notificationType, void *context)
5988 {
5989 (void)prefs; // Parameter not used
5990 (void)notificationType; // Parameter not used
5991 mDNS *const m = (mDNS *const)context;
5992 KQueueLock(m);
5993 mDNS_Lock(m);
5994
5995 // Tell platform layer to open or close its BPF fds
5996 if (!m->p->NetworkChanged ||
5997 m->p->NetworkChanged - NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2) < 0)
5998 {
5999 m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
6000 LogInfo("InternetSharingChanged: Set NetworkChanged to %d (%d)", m->p->NetworkChanged - m->timenow, m->p->NetworkChanged);
6001 }
6002
6003 mDNS_Unlock(m);
6004 KQueueUnlock(m, "InternetSharingChanged");
6005 }
6006
6007 mDNSlocal mStatus WatchForInternetSharingChanges(mDNS *const m)
6008 {
6009 SCPreferencesRef SCPrefs = SCPreferencesCreate(NULL, CFSTR("mDNSResponder:WatchForInternetSharingChanges"), CFSTR("com.apple.nat.plist"));
6010 if (!SCPrefs) { LogMsg("SCPreferencesCreate failed: %s", SCErrorString(SCError())); return(mStatus_NoMemoryErr); }
6011
6012 SCPreferencesContext context = { 0, m, NULL, NULL, NULL };
6013 if (!SCPreferencesSetCallback(SCPrefs, InternetSharingChanged, &context))
6014 { LogMsg("SCPreferencesSetCallback failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs); return(mStatus_NoMemoryErr); }
6015
6016 #ifdef __LIB_DISPATCH__
6017 if (!SCPreferencesSetDispatchQueue( SCPrefs, dispatch_get_main_queue()))
6018 { LogMsg("SCPreferencesSetDispatchQueue failed: %s", SCErrorString(SCError())); return(mStatus_NoMemoryErr); }
6019 #else
6020 if (!SCPreferencesScheduleWithRunLoop(SCPrefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
6021 { LogMsg("SCPreferencesScheduleWithRunLoop failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs); return(mStatus_NoMemoryErr); }
6022 #endif
6023
6024 m->p->SCPrefs = SCPrefs;
6025 return(mStatus_NoError);
6026 }
6027
6028 // The definitions below should eventually come from some externally-supplied header file.
6029 // However, since these definitions can't really be changed without breaking binary compatibility,
6030 // they should never change, so in practice it should not be a big problem to have them defined here.
6031
6032 #define mDNS_IOREG_KEY "mDNS_KEY"
6033 #define mDNS_IOREG_VALUE "2009-07-30"
6034 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
6035
6036 enum
6037 { // commands from the daemon to the driver
6038 cmd_mDNSOffloadRR = 21, // give the mdns update buffer to the driver
6039 };
6040
6041 typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr;
6042
6043 typedef struct
6044 { // cmd_mDNSOffloadRR structure
6045 uint32_t command; // set to OffloadRR
6046 uint32_t rrBufferSize; // number of bytes of RR records
6047 uint32_t numUDPPorts; // number of SRV UDP ports
6048 uint32_t numTCPPorts; // number of SRV TCP ports
6049 uint32_t numRRRecords; // number of RR records
6050 uint32_t compression; // rrRecords - compression is base for compressed strings
6051 FatPtr rrRecords; // address of array of pointers to the rr records
6052 FatPtr udpPorts; // address of udp port list (SRV)
6053 FatPtr tcpPorts; // address of tcp port list (SRV)
6054 } mDNSOffloadCmd;
6055
6056 #include <IOKit/IOKitLib.h>
6057 #include <dns_util.h>
6058
6059 mDNSlocal mDNSu16 GetPortArray(mDNS *const m, int trans, mDNSIPPort *portarray)
6060 {
6061 const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
6062 int count = 0;
6063 AuthRecord *rr;
6064 for (rr = m->ResourceRecords; rr; rr=rr->next)
6065 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c))
6066 {
6067 if (portarray) portarray[count] = rr->resrec.rdata->u.srv.port;
6068 count++;
6069 }
6070
6071 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
6072 if (trans == mDNSTransport_UDP && TunnelServers(m))
6073 {
6074 LogSPS("GetPortArray Back to My Mac at %d", count);
6075 if (portarray) portarray[count] = IPSECPort;
6076 count++;
6077 }
6078 return(count);
6079 }
6080
6081 #define TfrRecordToNIC(RR) \
6082 (((RR)->resrec.InterfaceID && (RR)->resrec.InterfaceID != mDNSInterface_LocalOnly) || \
6083 (!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
6084
6085 mDNSlocal mDNSu32 CountProxyRecords(mDNS *const m, uint32_t *const numbytes)
6086 {
6087 *numbytes = 0;
6088 int count = 0;
6089 AuthRecord *rr;
6090 for (rr = m->ResourceRecords; rr; rr=rr->next)
6091 if (rr->resrec.RecordType > kDNSRecordTypeDeregistering)
6092 if (TfrRecordToNIC(rr))
6093 {
6094 *numbytes += DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate;
6095 LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
6096 count, DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate, *numbytes, ARDisplayString(m,rr));
6097 count++;
6098 }
6099 return(count);
6100 }
6101
6102 mDNSlocal void GetProxyRecords(mDNS *const m, DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records)
6103 {
6104 mDNSu8 *p = msg->data;
6105 const mDNSu8 *const limit = p + *numbytes;
6106 InitializeDNSMessage(&msg->h, zeroID, zeroID);
6107
6108 int count = 0;
6109 AuthRecord *rr;
6110 for (rr = m->ResourceRecords; rr; rr=rr->next)
6111 if (rr->resrec.RecordType > kDNSRecordTypeDeregistering)
6112 if (TfrRecordToNIC(rr))
6113 {
6114 records[count].sixtyfourbits = zeroOpaque64;
6115 records[count].ptr = p;
6116 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
6117 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it
6118 p = PutResourceRecordTTLWithLimit(msg, p, &msg->h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
6119 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state
6120 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
6121 count, records[count].ptr, p, p - (mDNSu8 *)records[count].ptr, p - msg->data, ARDisplayString(m,rr));
6122 count++;
6123 }
6124 *numbytes = p - msg->data;
6125 }
6126
6127 // If compiling with old headers and libraries (pre 10.5) that don't include IOConnectCallStructMethod
6128 // then we declare a dummy version here so that the code at least compiles
6129 #ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
6130 static kern_return_t
6131 IOConnectCallStructMethod(
6132 mach_port_t connection, // In
6133 uint32_t selector, // In
6134 const void *inputStruct, // In
6135 size_t inputStructCnt, // In
6136 void *outputStruct, // Out
6137 size_t *outputStructCnt) // In/Out
6138 {
6139 (void)connection;
6140 (void)selector;
6141 (void)inputStruct;
6142 (void)inputStructCnt;
6143 (void)outputStruct;
6144 (void)outputStructCnt;
6145 LogMsg("Compiled without IOConnectCallStructMethod");
6146 return(KERN_FAILURE);
6147 }
6148 #endif
6149
6150 mDNSexport mStatus ActivateLocalProxy(mDNS *const m, char *ifname) // Called with the lock held
6151 {
6152 mStatus result = mStatus_UnknownErr;
6153 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, ifname));
6154 if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", ifname); return(mStatus_UnknownErr); }
6155
6156 io_name_t n1, n2;
6157 IOObjectGetClass(service, n1);
6158 io_object_t parent;
6159 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
6160 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", ifname, n1, kr);
6161 else
6162 {
6163 IOObjectGetClass(parent, n2);
6164 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", ifname, n1, n2);
6165 const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
6166 if (!ref) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", ifname, n1, n2);
6167 else
6168 {
6169 if (CFGetTypeID(ref) != CFStringGetTypeID() || !CFEqual(ref, CFSTR(mDNS_IOREG_VALUE)))
6170 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
6171 ifname, n1, n2, CFStringGetCStringPtr(ref, mDNSNULL), mDNS_IOREG_VALUE);
6172 else
6173 {
6174 io_connect_t conObj;
6175 kr = IOServiceOpen(parent, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE, &conObj);
6176 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", ifname, n1, n2, kr);
6177 else
6178 {
6179 mDNSOffloadCmd cmd;
6180 mDNSPlatformMemZero(&cmd, sizeof(cmd)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
6181 cmd.command = cmd_mDNSOffloadRR;
6182 cmd.numUDPPorts = GetPortArray(m, mDNSTransport_UDP, mDNSNULL);
6183 cmd.numTCPPorts = GetPortArray(m, mDNSTransport_TCP, mDNSNULL);
6184 cmd.numRRRecords = CountProxyRecords(m, &cmd.rrBufferSize);
6185 cmd.compression = sizeof(DNSMessageHeader);
6186
6187 DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
6188 cmd.rrRecords.ptr = mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr));
6189 cmd.udpPorts .ptr = mallocL("mDNSOffloadCmd udpPorts", cmd.numUDPPorts * sizeof(mDNSIPPort));
6190 cmd.tcpPorts .ptr = mallocL("mDNSOffloadCmd tcpPorts", cmd.numTCPPorts * sizeof(mDNSIPPort));
6191
6192 LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
6193 msg, cmd.rrBufferSize,
6194 cmd.rrRecords.ptr, cmd.numRRRecords,
6195 cmd.udpPorts .ptr, cmd.numUDPPorts,
6196 cmd.tcpPorts .ptr, cmd.numTCPPorts);
6197
6198 if (!msg || !cmd.rrRecords.ptr || !cmd.udpPorts.ptr || !cmd.tcpPorts.ptr)
6199 LogMsg("ActivateLocalProxy: Failed to allocate memory: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
6200 msg, cmd.rrBufferSize,
6201 cmd.rrRecords.ptr, cmd.numRRRecords,
6202 cmd.udpPorts .ptr, cmd.numUDPPorts,
6203 cmd.tcpPorts .ptr, cmd.numTCPPorts);
6204 else
6205 {
6206 GetProxyRecords(m, msg, &cmd.rrBufferSize, cmd.rrRecords.ptr);
6207 GetPortArray(m, mDNSTransport_UDP, cmd.udpPorts.ptr);
6208 GetPortArray(m, mDNSTransport_TCP, cmd.tcpPorts.ptr);
6209 char outputData[2];
6210 size_t outputDataSize = sizeof(outputData);
6211 kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize);
6212 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", ifname, n1, n2, kr);
6213 if (kr == KERN_SUCCESS) result = mStatus_NoError;
6214 }
6215
6216 if (cmd.tcpPorts. ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts .ptr);
6217 if (cmd.udpPorts. ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts .ptr);
6218 if (cmd.rrRecords.ptr) freeL("mDNSOffloadCmd rrRecords", cmd.rrRecords.ptr);
6219 if (msg) freeL("mDNSOffloadCmd msg", msg);
6220 IOServiceClose(conObj);
6221 }
6222 }
6223 CFRelease(ref);
6224 }
6225 IOObjectRelease(parent);
6226 }
6227 IOObjectRelease(service);
6228 return result;
6229 }
6230
6231 #endif // APPLE_OSX_mDNSResponder
6232
6233 static io_service_t g_rootdomain = MACH_PORT_NULL;
6234
6235 mDNSlocal mDNSBool SystemWakeForNetworkAccess(void)
6236 {
6237 mDNSs32 val = 0;
6238 CFBooleanRef clamshellStop = NULL;
6239 mDNSBool retnow = mDNSfalse;
6240
6241 if (DisableSleepProxyClient) { LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option"); return mDNSfalse; }
6242
6243 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
6244 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", val);
6245 if (!val) return mDNSfalse;
6246
6247 if (!g_rootdomain) g_rootdomain = IORegistryEntryFromPath(MACH_PORT_NULL, kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
6248 if (!g_rootdomain) { LogMsg("SystemWakeForNetworkAccess: IORegistryEntryFromPath failed; assuming no clamshell so can WOMP"); return mDNStrue; }
6249
6250 clamshellStop = (CFBooleanRef)IORegistryEntryCreateCFProperty(g_rootdomain, CFSTR(kAppleClamshellStateKey), kCFAllocatorDefault, 0);
6251 if (!clamshellStop) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue; }
6252 retnow = clamshellStop == kCFBooleanFalse;
6253 CFRelease(clamshellStop);
6254 if (retnow) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey is false; clamshell is open so can WOMP"); return mDNStrue; }
6255
6256 clamshellStop = (CFBooleanRef)IORegistryEntryCreateCFProperty(g_rootdomain, CFSTR(kAppleClamshellCausesSleepKey), kCFAllocatorDefault, 0);
6257 if (!clamshellStop) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue; }
6258 retnow = (clamshellStop == kCFBooleanFalse);
6259 CFRelease(clamshellStop);
6260 if (retnow) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey is false; clamshell is closed but can WOMP"); return mDNStrue; }
6261
6262 LogSPS("SystemWakeForNetworkAccess: clamshell is closed and can't WOMP");
6263 return mDNSfalse;
6264 }
6265
6266 mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
6267 {
6268 mDNSs32 val = 0;
6269 GetCurrentPMSetting(CFSTR("Idle Sleep Requires Network Proxy"), &val);
6270 return val != 0 ? mDNStrue : mDNSfalse;
6271 }
6272
6273 #if APPLE_OSX_mDNSResponder
6274 // If the _autotunnel6 record is still there in the list, we are waiting for the ack from
6275 // the server.
6276 //
6277 // If we are behind a double-NAT or NAT with no NAT-PMP support, we should make sure that all our
6278 // BTMM records are deregistered so that it does not appear on the Finder sidebar of our peers
6279 // when we go to sleep. First _autotunnel6 and the host record gets deregistered, then SRV
6280 // (UpdateAllSrvRecords) and then PTR and TXT
6281 //
6282 // Note: We wait up to a maximum of 10 seconds before we ack the sleep. So, returning "false"
6283 // here does not necessarily mean that it will be honored.
6284 mDNSexport mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr)
6285 {
6286 if (!AuthRecord_uDNS(rr)) return mDNStrue;
6287
6288 if (SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
6289 {
6290 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
6291 return mDNSfalse;
6292 }
6293 // Just check for the SRV record alone as the PTR and TXT records are dependent on SRV
6294 // and will get deregistered together in a single update. We also don't check for TXT
6295 // records as _kerberos TXT record is always there even when there are no services
6296 // and we don't want to delay the sleep in that case.
6297 if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort) || m->LLQNAT.Result)
6298 {
6299 if ((rr->resrec.rrtype == kDNSType_SRV) && rr->state != regState_NoTarget && rr->zone)
6300 {
6301 DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
6302 if (info && info->AutoTunnel)
6303 {
6304 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
6305 return mDNSfalse;
6306 }
6307 }
6308 }
6309 return mDNStrue;
6310 }
6311
6312 // Note: BTMMDict needs to be retained by the caller if needed
6313 mDNSlocal CFDictionaryRef ParseBackToMyMacKey(CFDictionaryRef connd)
6314 {
6315 CFDictionaryRef BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
6316 if (!BTMMDict)
6317 {
6318 LogInfo("ParseBackToMyMacKey: CFDictionaryGetValue No value for BackToMyMac");
6319 return NULL;
6320 }
6321
6322 // Non-dictionary is treated as non-existent dictionary
6323 if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
6324 {LogMsg("ERROR: ParseBackToMyMacKey: CFDictionaryGetValue BackToMyMac not a dictionary"); CFRelease(BTMMDict); return NULL;}
6325
6326 return BTMMDict;
6327 }
6328
6329 mDNSlocal void ParseBTMMInterfaceKey(CFDictionaryRef BTMMDict, char *buf, int buflen)
6330 {
6331 CFTypeRef string;
6332 mDNSBool ifExists;
6333
6334 ifExists = CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Interface"), &string);
6335 if (ifExists)
6336 {
6337 if (!CFStringGetCString(string, buf, buflen, kCFStringEncodingUTF8))
6338 {
6339 LogMsg("ERROR: ParseBTMMInterfaceKey: Could not convert Interface to CString");
6340 if (buflen) buf[0] = 0;
6341 return;
6342 }
6343 else
6344 debugf("ParseBTMMInterfaceKey: Interface Key exists %s", buf);
6345 }
6346 else
6347 {
6348 if (buflen) buf[0] = 0;
6349 debugf("ParseBTMMInterfaceKey: Interface Key does not exist");
6350 }
6351 }
6352
6353 mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
6354 {
6355 DomainAuthInfo *info;
6356 char buf[IFNAMSIZ];
6357
6358 // Did we parse a non-empty dictionary before ?
6359 if (!m->p->ConndBTMMDict || (CFDictionaryGetCount(m->p->ConndBTMMDict) == 0))
6360 {
6361 LogInfo("RemoveAutoTunnel6Record: Never registered any records before, not deregistering %p", m->p->ConndBTMMDict);
6362 return;
6363 }
6364
6365 // Did we have a non-NULL Interface name before ?
6366 ParseBTMMInterfaceKey(m->p->ConndBTMMDict, buf, sizeof(buf));
6367 if (!strlen(buf))
6368 {
6369 LogInfo("RemoveAutoTunnel6Record: Interface name already NULL, not deregistering");
6370 return;
6371 }
6372
6373 // Set the address to zero before calling DeregisterAutoTunnel6Record. If we call
6374 // Deregister too quickly before the previous Register completed (just scheduled
6375 // to be sent out) and when DeregisterAutoTunnel6Record calls mDNS_Register_internal,
6376 // it invokes the AutoTunnelRecordCallback immediately and AutoTunnelRelayAddrIn should
6377 // be zero so that we don't register again.
6378 m->AutoTunnelRelayAddrIn = zerov6Addr;
6379 if (!m->AuthInfoList) LogInfo("RemoveAutoTunnel6Record: No Domain AuthInfo");
6380 for (info = m->AuthInfoList; info; info = info->next)
6381 {
6382 if (!info->AutoTunnel) { LogInfo("RemoveAutoTunnel6Record: Domain %##s not an AutoTunnel", info->domain.c); continue;}
6383
6384 if (info->deltime) {LogInfo("RemoveAutoTunnel6Record: Domain %##s about to be deleted", info->domain.c); continue;}
6385
6386 LogInfo("RemoveAutoTunnel6Record: Deregistering records for domain %##s", info->domain.c);
6387 DeregisterAutoTunnel6Record(m, info);
6388 }
6389 CFRelease(m->p->ConndBTMMDict);
6390 m->p->ConndBTMMDict = NULL;
6391 }
6392
6393 // Returns zero on success
6394 mDNSlocal int GetIPv6AddressForIfname(char *ifname, mDNSv6Addr *ipv6Addr)
6395 {
6396 struct ifaddrs *ifa;
6397 struct ifaddrs *ifaddrs;
6398 mDNSAddr addr;
6399
6400 if (if_nametoindex(ifname) == 0) {LogInfo("GetIPv6AddressForIfname: Invalid name %s", ifname); return (-1);}
6401
6402 if (getifaddrs(&ifaddrs) < 0) {LogInfo("GetIPv6AddressForIfname: getifaddrs failed"); return (-1);}
6403
6404 /*
6405 * Find the ifaddr entry corresponding to the interface name,
6406 * and return the first matching non-linklocal IPv6 address.
6407 */
6408 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
6409 {
6410 if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
6411 continue;
6412 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6)
6413 {
6414 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)ifa->ifa_addr;
6415 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr))
6416 continue;
6417 if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
6418 {
6419 LogInfo("GetIPv6AddressForIfname: SetupAddr error, continuing to the next address");
6420 continue;
6421 }
6422 else
6423 {
6424 *ipv6Addr = *(mDNSv6Addr *)&addr.ip.v6;
6425 LogInfo("GetIPv6AddressForIfname: Returning IPv6 address %.16a", ipv6Addr);
6426 freeifaddrs(ifaddrs);
6427 return 0;
6428 }
6429 }
6430 }
6431 LogInfo("GetIPv6AddressForIfname: No Valid IPv6 address");
6432 freeifaddrs(ifaddrs);
6433 return (-1);
6434 }
6435
6436 mDNSlocal void AddAutoTunnel6Record(mDNS *const m, char *ifname, CFDictionaryRef BTMMDict)
6437 {
6438 mDNSv6Addr v6addr;
6439 DomainAuthInfo *info;
6440
6441 if (GetIPv6AddressForIfname(ifname, &v6addr) != 0)
6442 {
6443 LogInfo("AddAutoTunnel6Record: No Valid IPv6 addresses found for %s", ifname);
6444 // If the interface does not exist but the dictionary has the value, we treat
6445 // this case as though the dictionary does not have the value
6446 RemoveAutoTunnel6Record(m);
6447 // If awacsd crashes or exits for some reason, restart the relay connection
6448 UpdateBTMMRelayConnection(m);
6449 return;
6450 }
6451
6452 m->AutoTunnelRelayAddrOut = v6addr;
6453
6454 // if disabled administratively, don't bother to register. RegisterAutoTunnel6Record makes these same
6455 // checks, but we do it here not just as an optimization but mainly to keep AutoTunnelRelayAddrIn zero
6456 // as a non-zero AutoTunnelRelayAddrIn indicates that we have registered _autotunnel6 record and hence
6457 // other hosts can connect to this host through the relay
6458 if (!m->RegisterAutoTunnel6 || DisableInboundRelayConnection)
6459 {
6460 LogInfo("RegisterAutoTunnel6Record: registration Disabled RegisterAutoTunnel6 %d, DisableInbound %d",
6461 m->RegisterAutoTunnel6, DisableInboundRelayConnection);
6462 return;
6463 }
6464 m->AutoTunnelRelayAddrIn = v6addr;
6465
6466 if (!m->AuthInfoList) LogInfo("AddAutoTunnel6Record: No Domain AuthInfo");
6467 for (info = m->AuthInfoList; info; info = info->next)
6468 {
6469 // clientContext for a domain tells us that we are listening for at least one Service/Record
6470 // in a domain and SetLocalAutoTunnelInterface_internal was called
6471 if (!info->AutoTunnel) { LogInfo("AddAutoTunnel6Record: Domain %##s not an AutoTunnel", info->domain.c); continue;}
6472
6473 if (!info->AutoTunnelNAT.clientContext) {LogInfo("AddAutoTunnel6Record: Domain %##s has no services", info->domain.c); continue;}
6474
6475 if (info->deltime) {LogInfo("AddAutoTunnel6Record: Domain %##s about to be deleted", info->domain.c); continue;}
6476
6477 LogInfo("AddAutoTunnel6Record: Registering records for domain %##s", info->domain.c);
6478 mDNS_Lock(m);
6479 RegisterAutoTunnel6Record(m, info);
6480 mDNS_Unlock(m);
6481 }
6482 if (m->p->ConndBTMMDict) CFRelease(m->p->ConndBTMMDict);
6483 m->p->ConndBTMMDict = CFRetain(BTMMDict);
6484 }
6485
6486 mDNSlocal void ParseBackToMyMac(mDNS *const m, CFDictionaryRef connd)
6487 {
6488 CFDictionaryRef BTMMDict;
6489 char buf[IFNAMSIZ];
6490
6491 BTMMDict = ParseBackToMyMacKey(connd);
6492 if (!BTMMDict)
6493 {
6494 LogInfo("ParseBackToMyMac: CFDictionaryGetValue No value for BackToMyMac, Removing autotunnel6");
6495 RemoveAutoTunnel6Record(m);
6496 // Note: AutoTunnelRelayAddrIn is zeroed out in RemoveAutoTunnel6Record as it is called
6497 // from other places.
6498 m->AutoTunnelRelayAddrOut = zerov6Addr;
6499 return;
6500 }
6501
6502 ParseBTMMInterfaceKey(BTMMDict, buf, sizeof(buf));
6503 if (!strlen(buf))
6504 {
6505 LogInfo("ParseBackToMyMac: NULL value for Interface, Removing autotunnel6");
6506 RemoveAutoTunnel6Record(m);
6507 m->AutoTunnelRelayAddrOut = zerov6Addr;
6508 // We don't have a utun interface, start the relay connection if possible
6509 UpdateBTMMRelayConnection(m);
6510 }
6511 else
6512 {
6513 LogInfo("ParseBackToMyMac: non-NULL value for Interface, Adding autotunnel6");
6514 AddAutoTunnel6Record(m, buf, BTMMDict);
6515 }
6516 }
6517
6518 mDNSexport void SetupConndConfigChanges(mDNS *const m)
6519 {
6520 CFDictionaryRef connd;
6521 SCDynamicStoreRef store;
6522
6523 store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SetupConndConfigChanges"), NULL, NULL);
6524 if (!store) {LogMsg("SetupConndConfigChanges: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); return;}
6525
6526 connd = SCDynamicStoreCopyValue(store, NetworkChangedKey_BTMMConnectivity);
6527 if (!connd)
6528 {LogInfo("SetupConndConfigChanges: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError())); CFRelease(store); return;}
6529 else
6530 {
6531 ParseBackToMyMac(m, connd);
6532 }
6533 CFRelease(connd);
6534 CFRelease(store);
6535 }
6536 #endif /* APPLE_OSX_mDNSResponder */
6537
6538
6539 mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
6540 {
6541 LogInfo("*** Network Configuration Change *** (%d)%s",
6542 m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0,
6543 m->p->NetworkChanged ? "" : " (no scheduled configuration change)");
6544 m->p->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
6545 mDNSs32 utc = mDNSPlatformUTC();
6546 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
6547 m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
6548 MarkAllInterfacesInactive(m, utc);
6549 UpdateInterfaceList(m, utc);
6550 ClearInactiveInterfaces(m, utc);
6551 SetupActiveInterfaces(m, utc);
6552
6553 #if APPLE_OSX_mDNSResponder
6554
6555 SetupConndConfigChanges(m);
6556
6557 if (m->AutoTunnelHostAddr.b[0])
6558 {
6559 mDNS_Lock(m);
6560 if (TunnelClients(m) || TunnelServers(m))
6561 SetupLocalAutoTunnelInterface_internal(m, mDNSfalse);
6562 mDNS_Unlock(m);
6563 }
6564
6565 // Scan to find client tunnels whose questions have completed,
6566 // but whose local inner/outer addresses have changed since the tunnel was set up
6567 ClientTunnel *p;
6568 for (p = m->TunnelClients; p; p = p->next)
6569 if (p->q.ThisQInterval < 0)
6570 {
6571 if (!mDNSIPPortIsZero(p->rmt_outer_port))
6572 {
6573 mDNSAddr tmpSrc = zeroAddr;
6574 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
6575 tmpDst.ip.v4 = p->rmt_outer;
6576 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
6577 if (!mDNSSameIPv6Address(p->loc_inner, m->AutoTunnelHostAddr) ||
6578 !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
6579 {
6580 AutoTunnelSetKeys(p, mDNSfalse);
6581 p->loc_inner = m->AutoTunnelHostAddr;
6582 p->loc_outer = tmpSrc.ip.v4;
6583 AutoTunnelSetKeys(p, mDNStrue);
6584 }
6585 }
6586 else
6587 {
6588 if (!mDNSSameIPv6Address(p->loc_inner, m->AutoTunnelHostAddr) ||
6589 !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddrOut))
6590 {
6591 AutoTunnelSetKeys(p, mDNSfalse);
6592 p->loc_inner = m->AutoTunnelHostAddr;
6593 p->loc_outer6 = m->AutoTunnelRelayAddrOut;
6594 AutoTunnelSetKeys(p, mDNStrue);
6595 }
6596 }
6597 }
6598
6599
6600 SetSPS(m);
6601
6602 NetworkInterfaceInfoOSX *i;
6603 for (i = m->p->InterfaceList; i; i = i->next)
6604 {
6605 if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
6606 {
6607 if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) CloseBPF(i);
6608 }
6609 else // else, we're Sleep Proxy Server; open BPF fds
6610 {
6611 if (i->Exists && i->Registered == i && i->ifinfo.McastTxRx && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1)
6612 { LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); }
6613 }
6614 }
6615
6616 #endif // APPLE_OSX_mDNSResponder
6617
6618 uDNS_SetupDNSConfig(m);
6619 mDNS_ConfigChanged(m);
6620 }
6621
6622 // Called with KQueueLock & mDNS lock
6623 mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay)
6624 {
6625 if (!m->p->NetworkChanged || m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
6626 {
6627 m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
6628 LogInfo("SetNetworkChanged: setting network changed to %d (%d)", delay, m->p->NetworkChanged);
6629 }
6630 }
6631
6632
6633 // Copy the fourth slash-delimited element from either:
6634 // State:/Network/Interface/<bsdname>/IPv4
6635 // or
6636 // Setup:/Network/Service/<servicename>/Interface
6637 mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
6638 {
6639 CFArrayRef a;
6640 CFStringRef name = NULL;
6641
6642 a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
6643 if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
6644 if (a != NULL) CFRelease(a);
6645
6646 return name;
6647 }
6648
6649 // Whether a key from a network change notification corresponds to
6650 // an IP service that is explicitly configured for IPv4 Link Local
6651 mDNSlocal mDNSBool ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
6652 {
6653 SCDynamicStoreRef store = NULL;
6654 CFDictionaryRef dict = NULL;
6655 CFMutableArrayRef a;
6656 const void **keys = NULL, **vals = NULL;
6657 CFStringRef pattern = NULL;
6658 int i, ic, j, jc;
6659 mDNSBool found = mDNSfalse;
6660
6661 jc = CFArrayGetCount(inkeys);
6662 if (!jc) goto done;
6663
6664 store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:ChangedKeysHaveIPv4LL"), NULL, NULL);
6665 if (store == NULL) goto done;
6666
6667 a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6668 if (a == NULL) goto done;
6669
6670 // Setup:/Network/Service/[^/]+/Interface
6671 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
6672 if (pattern == NULL) goto done;
6673 CFArrayAppendValue(a, pattern);
6674 CFRelease(pattern);
6675
6676 // Setup:/Network/Service/[^/]+/IPv4
6677 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
6678 if (pattern == NULL) goto done;
6679 CFArrayAppendValue(a, pattern);
6680 CFRelease(pattern);
6681
6682 dict = SCDynamicStoreCopyMultiple(store, NULL, a);
6683 CFRelease(a);
6684
6685 if (!dict)
6686 {
6687 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
6688 goto done;
6689 }
6690
6691 ic = CFDictionaryGetCount(dict);
6692 vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
6693 keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
6694 CFDictionaryGetKeysAndValues(dict, keys, vals);
6695
6696 for (j = 0; j < jc && !found; j++)
6697 {
6698 CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
6699 CFStringRef ifname = NULL;
6700
6701 char buf[256];
6702
6703 // It would be nice to use a regex here
6704 if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
6705
6706 if ((ifname = CopyNameFromKey(key)) == NULL) continue;
6707 if (mDNS_LoggingEnabled)
6708 {
6709 if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
6710 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
6711 }
6712
6713 for (i = 0; i < ic; i++)
6714 {
6715 CFDictionaryRef ipv4dict;
6716 CFStringRef name;
6717 CFStringRef serviceid;
6718 CFStringRef configmethod;
6719
6720 if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
6721
6722 if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
6723
6724 if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
6725
6726 if (!CFEqual(ifname, name)) continue;
6727
6728 if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
6729 if (mDNS_LoggingEnabled)
6730 {
6731 if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
6732 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
6733 }
6734
6735 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
6736 CFRelease(serviceid);
6737 if (pattern == NULL) continue;
6738
6739 ipv4dict = CFDictionaryGetValue(dict, pattern);
6740 CFRelease(pattern);
6741 if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
6742
6743 configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
6744 if (!configmethod) continue;
6745
6746 if (mDNS_LoggingEnabled)
6747 {
6748 if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
6749 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
6750 }
6751
6752 if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found = mDNStrue; break; }
6753 }
6754
6755 CFRelease(ifname);
6756 }
6757
6758 done:
6759 if (vals != NULL) mDNSPlatformMemFree(vals);
6760 if (keys != NULL) mDNSPlatformMemFree(keys);
6761 if (dict != NULL) CFRelease(dict);
6762 if (store != NULL) CFRelease(store);
6763
6764 return found;
6765 }
6766
6767 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
6768 {
6769 (void)store; // Parameter not used
6770 mDNS *const m = (mDNS *const)context;
6771 KQueueLock(m);
6772 mDNS_Lock(m);
6773
6774 mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
6775
6776 int c = CFArrayGetCount(changedKeys); // Count changes
6777 CFRange range = { 0, c };
6778 int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
6779 int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
6780 int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
6781 int c4 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0);
6782 if (c && c - c1 - c2 - c3 - c4 == 0) delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
6783
6784 if (mDNS_LoggingEnabled)
6785 {
6786 int i;
6787 for (i=0; i<c; i++)
6788 {
6789 char buf[256];
6790 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
6791 LogInfo("*** NetworkChanged SC key: %s", buf);
6792 }
6793 LogInfo("*** NetworkChanged *** %d change%s %s%s%s%sdelay %d",
6794 c, c>1?"s":"",
6795 c1 ? "(Local Hostname) " : "",
6796 c2 ? "(Computer Name) " : "",
6797 c3 ? "(DynamicDNS) " : "",
6798 c4 ? "(DNS) " : "",
6799 delay);
6800 }
6801
6802 SetNetworkChanged(m, delay);
6803
6804 // KeyChain frequently fails to notify clients of change events. To work around this
6805 // we set a timer and periodically poll to detect if any changes have occurred.
6806 // Without this Back To My Mac just does't work for a large number of users.
6807 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
6808 if (c3 || CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac))
6809 {
6810 LogInfo("*** NetworkChanged *** starting KeyChainBugTimer");
6811 m->p->KeyChainBugTimer = NonZeroTime(m->timenow + delay);
6812 m->p->KeyChainBugInterval = mDNSPlatformOneSecond;
6813 }
6814
6815 mDNS_Unlock(m);
6816
6817 // If DNS settings changed, immediately force a reconfig (esp. cache flush)
6818 // Similarly, if an interface changed that is explicitly IPv4 link local, immediately force a reconfig
6819 if (c4 || ChangedKeysHaveIPv4LL(changedKeys)) mDNSMacOSXNetworkChanged(m);
6820
6821 KQueueUnlock(m, "NetworkChanged");
6822 }
6823
6824 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
6825 {
6826 mStatus err = -1;
6827 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
6828 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
6829 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6830 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
6831 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
6832 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6833
6834 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
6835 if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
6836
6837 CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
6838 CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
6839 CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
6840 CFArrayAppendValue(keys, NetworkChangedKey_Computername);
6841 CFArrayAppendValue(keys, NetworkChangedKey_DNS);
6842 CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
6843 CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
6844 CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings); // should remove as part of <rdar://problem/6751656>
6845 CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
6846 CFArrayAppendValue(patterns, pattern1);
6847 CFArrayAppendValue(patterns, pattern2);
6848 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
6849 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
6850 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
6851
6852 #ifdef __LIB_DISPATCH__
6853 if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()))
6854 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
6855 #else
6856 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
6857 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
6858 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
6859 #endif
6860 m->p->Store = store;
6861 err = 0;
6862 goto exit;
6863
6864 error:
6865 if (store) CFRelease(store);
6866
6867 exit:
6868 if (patterns) CFRelease(patterns);
6869 if (pattern2) CFRelease(pattern2);
6870 if (pattern1) CFRelease(pattern1);
6871 if (keys) CFRelease(keys);
6872
6873 return(err);
6874 }
6875
6876 #if 0 // <rdar://problem/6751656>
6877 mDNSlocal void PMChanged(void *context)
6878 {
6879 mDNS *const m = (mDNS *const)context;
6880
6881 KQueueLock(m);
6882 mDNS_Lock(m);
6883
6884 LogSPS("PMChanged");
6885
6886 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
6887
6888 mDNS_Unlock(m);
6889 KQueueUnlock(m, "PMChanged");
6890 }
6891
6892 mDNSlocal mStatus WatchForPMChanges(mDNS *const m)
6893 {
6894 m->p->PMRLS = IOPMPrefsNotificationCreateRunLoopSource(PMChanged, m);
6895 if (!m->p->PMRLS) { LogMsg("IOPMPrefsNotificationCreateRunLoopSource failed!"); return mStatus_UnknownErr; }
6896
6897 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
6898
6899 return mStatus_NoError;
6900 }
6901 #endif
6902
6903 #ifndef KEV_DL_WAKEFLAGS_CHANGED
6904 #define KEV_DL_WAKEFLAGS_CHANGED 17
6905 #endif
6906
6907 mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context)
6908 {
6909 mDNS *const m = (mDNS *const)context;
6910
6911 mDNS_Lock(m);
6912
6913 struct { struct kern_event_msg k; char extra[256]; } msg;
6914 int bytes = recv(s1, &msg, sizeof(msg), 0);
6915 if (bytes < 0)
6916 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
6917 else
6918 {
6919 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
6920 bytes, msg.k.total_size,
6921 msg.k.vendor_code , msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?",
6922 msg.k.kev_class , msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
6923 msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?",
6924 msg.k.id, msg.k.event_code,
6925 msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" :
6926 msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" :
6927 msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" :
6928 msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" :
6929 msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" :
6930 msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" :
6931 msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" :
6932 msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" :
6933 msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" :
6934 msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" :
6935 msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" :
6936 msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" :
6937 msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" :
6938 msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" :
6939 msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" :
6940 msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
6941 msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" : "?");
6942
6943 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
6944 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
6945 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
6946 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
6947 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
6948
6949 if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
6950 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
6951 }
6952
6953 mDNS_Unlock(m);
6954 }
6955
6956 mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
6957 {
6958 m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
6959 if (m->p->SysEventNotifier < 0)
6960 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); }
6961
6962 struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
6963 int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
6964 if (err < 0)
6965 {
6966 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno));
6967 close(m->p->SysEventNotifier);
6968 m->p->SysEventNotifier = -1;
6969 return(mStatus_UnknownErr);
6970 }
6971
6972 m->p->SysEventKQueue.KQcallback = SysEventCallBack;
6973 m->p->SysEventKQueue.KQcontext = m;
6974 m->p->SysEventKQueue.KQtask = "System Event Notifier";
6975 KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
6976
6977 return(mStatus_NoError);
6978 }
6979
6980 #ifndef NO_SECURITYFRAMEWORK
6981 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
6982 {
6983 LogInfo("*** Keychain Changed ***");
6984 mDNS *const m = (mDNS *const)context;
6985 SecKeychainRef skc;
6986 OSStatus err = SecKeychainCopyDefault(&skc);
6987 if (!err)
6988 {
6989 if (info->keychain == skc)
6990 {
6991 // For delete events, attempt to verify what item was deleted fail because the item is already gone, so we just assume they may be relevant
6992 mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
6993 if (!relevant)
6994 {
6995 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
6996 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
6997 SecKeychainAttributeList *a = NULL;
6998 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
6999 if (!err)
7000 {
7001 relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
7002 (a->attr[1].length >= 4 && (!strncasecmp(a->attr[1].data, "dns:", 4))));
7003 SecKeychainItemFreeAttributesAndData(a, NULL);
7004 }
7005 }
7006 if (relevant)
7007 {
7008 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
7009 keychainEvent,
7010 keychainEvent == kSecAddEvent ? "kSecAddEvent" :
7011 keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
7012 keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
7013 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
7014 KQueueLock(m);
7015 mDNS_Lock(m);
7016 SetDomainSecrets(m);
7017 mDNS_Unlock(m);
7018 KQueueUnlock(m, "KeychainChanged");
7019 }
7020 }
7021 CFRelease(skc);
7022 }
7023
7024 return 0;
7025 }
7026 #endif
7027
7028 mDNSlocal void PowerOn(mDNS *const m)
7029 {
7030 mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
7031 if (m->p->WakeAtUTC)
7032 {
7033 long utc = mDNSPlatformUTC();
7034 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
7035 if (m->p->WakeAtUTC - utc > 30) LogInfo("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
7036 else if (utc - m->p->WakeAtUTC > 30) LogInfo("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
7037 else
7038 {
7039 mDNSs32 i = 20;
7040 //int result = mDNSPowerRequest(0, i);
7041 //if (result == kIOReturnNotReady) do i += (i<20) ? 1 : ((i+3)/4); while (mDNSPowerRequest(0, i) == kIOReturnNotReady);
7042 LogMsg("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in %d seconds", m->p->WakeAtUTC - utc, i);
7043 m->p->RequestReSleep = mDNS_TimeNow(m) + i * mDNSPlatformOneSecond;
7044 }
7045 }
7046 }
7047
7048 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
7049 {
7050 mDNS *const m = (mDNS *const)refcon;
7051 KQueueLock(m);
7052 (void)service; // Parameter not used
7053 debugf("PowerChanged %X %lX", messageType, messageArgument);
7054
7055 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
7056 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
7057
7058 switch(messageType)
7059 {
7060 case kIOMessageCanSystemPowerOff: LogInfo("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
7061 case kIOMessageSystemWillPowerOff: LogInfo("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
7062 mDNSCoreMachineSleep(m, true);
7063 if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
7064 break;
7065 case kIOMessageSystemWillNotPowerOff: LogInfo("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
7066 case kIOMessageCanSystemSleep: LogInfo("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
7067 case kIOMessageSystemWillSleep: LogInfo("PowerChanged kIOMessageSystemWillSleep"); // E0000280
7068 mDNSCoreMachineSleep(m, true);
7069 break;
7070 case kIOMessageSystemWillNotSleep: LogInfo("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
7071 case kIOMessageSystemHasPoweredOn: LogInfo("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
7072 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
7073 if (m->SleepState)
7074 {
7075 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
7076 PowerOn(m);
7077 }
7078 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
7079 // the System Configuration Framework "network changed" event that we expect
7080 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
7081 mDNS_Lock(m);
7082 if (!m->p->NetworkChanged ||
7083 m->p->NetworkChanged - NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2) < 0)
7084 m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
7085 mDNS_Unlock(m);
7086
7087 break;
7088 case kIOMessageSystemWillRestart: LogInfo("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
7089 case kIOMessageSystemWillPowerOn: LogInfo("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
7090
7091 #if ! TARGET_OS_EMBEDDED
7092 // On Leopard and earlier, on wake from sleep, instead of reporting link state down, Apple
7093 // Ethernet drivers report "hardware incapable of detecting link state", which the kernel
7094 // interprets as "should assume we have networking", which results in the first 4-5 seconds
7095 // of packets vanishing into a black hole. To work around this, on wake from sleep,
7096 // we block for five seconds to let Ethernet come up, and then resume normal operation.
7097 if (OSXVers < OSXVers_10_6_SnowLeopard)
7098 {
7099 sleep(5);
7100 LogMsg("Running on Mac OS X version 10.%d earlier than 10.6; "
7101 "PowerChanged did sleep(5) to wait for Ethernet hardware", OSXVers - OSXVers_Base);
7102 }
7103 #endif
7104
7105 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
7106 if (m->SleepState != SleepState_Sleeping)
7107 {
7108 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
7109 m->SleepState = SleepState_Sleeping;
7110 mDNSMacOSXNetworkChanged(m);
7111 }
7112 PowerOn(m);
7113 break;
7114 default: LogInfo("PowerChanged unknown message %X", messageType); break;
7115 }
7116
7117 if (messageType == kIOMessageSystemWillSleep) m->p->SleepCookie = (long)messageArgument;
7118 else IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
7119
7120 KQueueUnlock(m, "PowerChanged Sleep/Wake");
7121 }
7122
7123 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
7124 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
7125 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
7126 mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
7127 {
7128 mDNS *const m = (mDNS *const)refcon;
7129 KQueueLock(m);
7130 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
7131 connection, token, eventDescriptor,
7132 eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "",
7133 eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "",
7134 eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "",
7135 eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
7136 eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : "");
7137
7138 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
7139 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
7140
7141 if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
7142 {
7143 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
7144 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
7145 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
7146 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
7147 if (m->SleepLimit)
7148 {
7149 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
7150 IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie);
7151 m->SleepLimit = 0;
7152 }
7153 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
7154 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
7155 if (m->SleepState != SleepState_Awake) PowerOn(m);
7156 IOPMConnectionAcknowledgeEvent(connection, token);
7157 }
7158 else
7159 {
7160 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
7161 // we should hear nothing more until we're told that the CPU has started executing again.
7162 if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
7163 //sleep(5);
7164 //mDNSMacOSXNetworkChanged(m);
7165 mDNSCoreMachineSleep(m, true);
7166 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
7167 m->p->SleepCookie = token;
7168 }
7169
7170 KQueueUnlock(m, "SnowLeopardPowerChanged Sleep/Wake");
7171 }
7172 #endif
7173
7174 #if COMPILER_LIKES_PRAGMA_MARK
7175 #pragma mark -
7176 #pragma mark - Initialization & Teardown
7177 #endif
7178
7179 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
7180 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
7181 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
7182 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
7183
7184 // Major version 6 is 10.2.x (Jaguar)
7185 // Major version 7 is 10.3.x (Panther)
7186 // Major version 8 is 10.4.x (Tiger)
7187 // Major version 9 is 10.5.x (Leopard)
7188 // Major version 10 is 10.6.x (SnowLeopard)
7189 mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
7190 {
7191 int major = 0, minor = 0;
7192 char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
7193 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
7194 if (vers)
7195 {
7196 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
7197 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
7198 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
7199 if (cfprodname) CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
7200 if (cfprodvers) CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
7201 if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
7202 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
7203 CFRelease(vers);
7204 }
7205 if (!major) { major=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
7206 if (HINFO_SWstring) mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion));
7207 return(major);
7208 }
7209
7210 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
7211 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
7212 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
7213 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
7214 {
7215 int err = -1;
7216 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
7217 if (s < 3)
7218 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
7219 else
7220 {
7221 struct sockaddr_in s5353;
7222 s5353.sin_family = AF_INET;
7223 s5353.sin_port = MulticastDNSPort.NotAnInteger;
7224 s5353.sin_addr.s_addr = 0;
7225 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
7226 close(s);
7227 }
7228
7229 if (err) LogMsg("No unicast UDP responses");
7230 else debugf("Unicast UDP responses okay");
7231 return(err == 0);
7232 }
7233
7234 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
7235 // 1) query for b._dns-sd._udp.local on LocalOnly interface
7236 // (.local manually generated via explicit callback)
7237 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
7238 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
7239 // 4) result above should generate a callback from question in (1). result added to global list
7240 // 5) global list delivered to client via GetSearchDomainList()
7241 // 6) client calls to enumerate domains now go over LocalOnly interface
7242 // (!!!KRS may add outgoing interface in addition)
7243
7244 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
7245 {
7246 mStatus err;
7247 m->p->CFRunLoop = CFRunLoopGetCurrent();
7248
7249 char HINFO_SWstring[256] = "";
7250 OSXVers = mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
7251
7252 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
7253 // If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
7254 int i;
7255 for (i=0; i<100; i++)
7256 {
7257 domainlabel testlabel;
7258 testlabel.c[0] = 0;
7259 GetUserSpecifiedLocalHostName(&testlabel);
7260 if (testlabel.c[0]) break;
7261 usleep(50000);
7262 }
7263
7264 m->hostlabel.c[0] = 0;
7265
7266 int get_model[2] = { CTL_HW, HW_MODEL };
7267 size_t len_model = sizeof(HINFO_HWstring_buffer);
7268
7269 // Normal Apple model names are of the form "iPhone2,1", and
7270 // internal code names are strings containing no commas, e.g. "N88AP".
7271 // We used to ignore internal code names, but Apple now uses these internal code names
7272 // even in released shipping products, so we no longer ignore strings containing no commas.
7273 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
7274 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
7275 HINFO_HWstring = HINFO_HWstring_buffer;
7276 HINFO_HWstring_prefixlen = strcspn(HINFO_HWstring, "0123456789");
7277
7278 if (OSXVers < OSXVers_10_3_Panther ) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
7279 if (OSXVers <= OSXVers_10_6_SnowLeopard ) m->KnownBugs |= mDNS_KnownBug_LimitedIPv6;
7280 if (OSXVers >= OSXVers_10_6_SnowLeopard ) m->KnownBugs |= mDNS_KnownBug_LossySyslog;
7281 if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
7282
7283 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
7284 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
7285 if (hlen + slen < 254)
7286 {
7287 m->HIHardware.c[0] = hlen;
7288 m->HISoftware.c[0] = slen;
7289 mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
7290 mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
7291 }
7292
7293 m->p->permanentsockets.port = MulticastDNSPort;
7294 m->p->permanentsockets.m = m;
7295 m->p->permanentsockets.sktv4 = -1;
7296 m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack;
7297 m->p->permanentsockets.kqsv4.KQcontext = &m->p->permanentsockets;
7298 m->p->permanentsockets.kqsv4.KQtask = "UDP packet reception";
7299 #ifndef NO_IPV6
7300 m->p->permanentsockets.sktv6 = -1;
7301 m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
7302 m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
7303 m->p->permanentsockets.kqsv6.KQtask = "UDP packet reception";
7304 #endif
7305
7306 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
7307 #ifndef NO_IPV6
7308 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
7309 #endif
7310
7311 struct sockaddr_in s4;
7312 socklen_t n4 = sizeof(s4);
7313 if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
7314 else m->UnicastPort4.NotAnInteger = s4.sin_port;
7315 #ifndef NO_IPV6
7316 if (m->p->permanentsockets.sktv6 >= 0)
7317 {
7318 struct sockaddr_in6 s6;
7319 socklen_t n6 = sizeof(s6);
7320 if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
7321 else m->UnicastPort6.NotAnInteger = s6.sin6_port;
7322 }
7323 #endif
7324
7325 m->p->InterfaceList = mDNSNULL;
7326 m->p->userhostlabel.c[0] = 0;
7327 m->p->usernicelabel.c[0] = 0;
7328 m->p->prevoldnicelabel.c[0] = 0;
7329 m->p->prevnewnicelabel.c[0] = 0;
7330 m->p->prevoldhostlabel.c[0] = 0;
7331 m->p->prevnewhostlabel.c[0] = 0;
7332 m->p->NotifyUser = 0;
7333 m->p->KeyChainBugTimer = 0;
7334 m->p->WakeAtUTC = 0;
7335 m->p->RequestReSleep = 0;
7336
7337 #if APPLE_OSX_mDNSResponder
7338 uuid_generate(m->asl_uuid);
7339 #endif
7340
7341 m->AutoTunnelHostAddr.b[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
7342 m->AutoTunnelRelayAddrIn = zerov6Addr;
7343 m->AutoTunnelRelayAddrOut = zerov6Addr;
7344
7345 NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
7346 NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
7347 NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
7348 NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
7349 NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
7350 if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS)
7351 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
7352
7353 err = WatchForNetworkChanges(m);
7354 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
7355
7356 #if 0 // <rdar://problem/6751656>
7357 err = WatchForPMChanges(m);
7358 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForPMChanges failed %d", err); return(err); }
7359 #endif
7360
7361 err = WatchForSysEvents(m);
7362 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
7363
7364 mDNSs32 utc = mDNSPlatformUTC();
7365 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
7366 UpdateInterfaceList(m, utc);
7367 SetupActiveInterfaces(m, utc);
7368
7369 // Explicitly ensure that our Keychain operations utilize the system domain.
7370 #ifndef NO_SECURITYFRAMEWORK
7371 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
7372 #endif
7373
7374 mDNS_Lock(m);
7375 SetDomainSecrets(m);
7376 SetLocalDomains();
7377 mDNS_Unlock(m);
7378
7379 #ifndef NO_SECURITYFRAMEWORK
7380 err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
7381 if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
7382 #endif
7383
7384 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
7385 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
7386 #else
7387 IOPMConnection c;
7388 IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
7389 if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
7390 else
7391 {
7392 iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
7393 if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
7394 else
7395 {
7396 iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
7397 if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
7398 }
7399 }
7400 m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
7401 if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
7402 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
7403 {
7404 m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
7405 if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
7406 else
7407 {
7408 #ifdef __LIB_DISPATCH__
7409 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
7410 #else
7411 CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
7412 #endif /* __LIB_DISPATCH__ */
7413 }
7414 }
7415
7416 #if APPLE_OSX_mDNSResponder
7417 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
7418 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
7419 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
7420 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
7421 if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
7422 else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
7423 else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
7424 else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
7425 else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; }
7426 else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; }
7427 else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /* 4kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 13W */; }
7428 else if (!strncasecmp(HINFO_HWstring, "AirPort", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 12W */; }
7429 else if (!strncasecmp(HINFO_HWstring, "AppleTV", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 73 /* 20W */; }
7430 else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
7431 else if (!strncasecmp(HINFO_HWstring, "PowerBook", 9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
7432 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d",
7433 HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower);
7434
7435 err = WatchForInternetSharingChanges(m);
7436 if (err) { LogMsg("WatchForInternetSharingChanges failed %d", err); return(err); }
7437
7438 m->p->ConndBTMMDict = mDNSNULL;
7439 #endif // APPLE_OSX_mDNSResponder
7440
7441 #ifdef __LIB_DISPATCH__
7442 // Currently this is not defined. SSL code will eventually fix this. If it becomes
7443 // critical, we will define this to workaround the bug in SSL.
7444 #ifdef __SSL_NEEDS_SERIALIZATION__
7445 SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL);
7446 #else
7447 SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
7448 #endif
7449 if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
7450 #endif
7451 return(mStatus_NoError);
7452 }
7453
7454 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
7455 {
7456 #if MDNS_NO_DNSINFO
7457 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
7458 #endif
7459
7460 // Adding interfaces will use this flag, so set it now.
7461 m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
7462
7463 #if APPLE_OSX_mDNSResponder
7464 m->SPSBrowseCallback = UpdateSPSStatus;
7465 #endif // APPLE_OSX_mDNSResponder
7466
7467 mStatus result = mDNSPlatformInit_setup(m);
7468
7469 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
7470 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
7471 if (result == mStatus_NoError)
7472 {
7473 mDNSCoreInitComplete(m, mStatus_NoError);
7474
7475 #if ! NO_D2D
7476 // We only initialize if mDNSCore successfully initialized.
7477 CHECK_D2D_FUNCTION(D2DInitialize)
7478 {
7479 D2DStatus ds = D2DInitialize(m->p->CFRunLoop, xD2DServiceCallback, m) ;
7480 if (ds != kD2DSuccess)
7481 LogMsg("D2DInitialiize failed: %d", ds);
7482 else
7483 LogMsg("D2DInitialize succeeded");
7484 }
7485 #endif // ! NO_D2D
7486
7487 }
7488 return(result);
7489 }
7490
7491 mDNSexport void mDNSPlatformClose(mDNS *const m)
7492 {
7493 if (m->p->PowerConnection)
7494 {
7495 #ifdef __LIB_DISPATCH__
7496 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);
7497 #else
7498 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
7499 #endif
7500 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
7501 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
7502 IODeregisterForSystemPower(&m->p->PowerNotifier);
7503 IOServiceClose ( m->p->PowerConnection);
7504 IONotificationPortDestroy ( m->p->PowerPortRef);
7505 m->p->PowerConnection = 0;
7506 }
7507
7508 if (m->p->Store)
7509 {
7510 #ifdef __LIB_DISPATCH__
7511 if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
7512 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
7513 #else
7514 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
7515 CFRunLoopSourceInvalidate(m->p->StoreRLS);
7516 CFRelease(m->p->StoreRLS);
7517 m->p->StoreRLS = NULL;
7518 #endif
7519 CFRelease(m->p->Store);
7520 m->p->Store = NULL;
7521 }
7522
7523 if (m->p->PMRLS)
7524 {
7525 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
7526 CFRunLoopSourceInvalidate(m->p->PMRLS);
7527 CFRelease(m->p->PMRLS);
7528 m->p->PMRLS = NULL;
7529 }
7530
7531 if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
7532
7533 #if ! NO_D2D
7534 CHECK_D2D_FUNCTION(D2DTerminate)
7535 {
7536 D2DStatus ds = D2DTerminate();
7537 if (ds != kD2DSuccess)
7538 LogMsg("D2DTerminate failed: %d", ds);
7539 else
7540 LogMsg("D2DTerminate succeeded");
7541 }
7542 #endif // ! NO_D2D
7543
7544 mDNSs32 utc = mDNSPlatformUTC();
7545 MarkAllInterfacesInactive(m, utc);
7546 ClearInactiveInterfaces(m, utc);
7547 CloseSocketSet(&m->p->permanentsockets);
7548
7549 #if APPLE_OSX_mDNSResponder
7550 // clean up tunnels
7551 while (m->TunnelClients)
7552 {
7553 ClientTunnel *cur = m->TunnelClients;
7554 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
7555 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
7556 AutoTunnelSetKeys(cur, mDNSfalse);
7557 m->TunnelClients = cur->next;
7558 freeL("ClientTunnel", cur);
7559 }
7560
7561 if (AnonymousRacoonConfig)
7562 {
7563 AnonymousRacoonConfig = mDNSNULL;
7564 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel");
7565 (void)mDNSConfigureServer(kmDNSDown, mDNSNULL);
7566 }
7567
7568 if (m->AutoTunnelHostAddrActive && m->AutoTunnelHostAddr.b[0])
7569 {
7570 m->AutoTunnelHostAddrActive = mDNSfalse;
7571 LogInfo("mDNSPlatformClose: Removing AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
7572 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
7573 }
7574 if (m->p->ConndBTMMDict) CFRelease(m->p->ConndBTMMDict);
7575 #endif // APPLE_OSX_mDNSResponder
7576 }
7577
7578 #if COMPILER_LIKES_PRAGMA_MARK
7579 #pragma mark -
7580 #pragma mark - General Platform Support Layer functions
7581 #endif
7582
7583 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
7584 {
7585 return(arc4random());
7586 }
7587
7588 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
7589 mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
7590
7591 mDNSexport mStatus mDNSPlatformTimeInit(void)
7592 {
7593 // Notes: Typical values for mach_timebase_info:
7594 // tbi.numer = 1000 million
7595 // tbi.denom = 33 million
7596 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
7597 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
7598 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
7599 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
7600 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
7601 //
7602 // Arithmetic notes:
7603 // tbi.denom is at least 1, and not more than 2^32-1.
7604 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
7605 // tbi.denom is at least 1, and not more than 2^32-1.
7606 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
7607 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
7608 // which is unlikely on any current or future Macintosh.
7609 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
7610 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
7611 struct mach_timebase_info tbi;
7612 kern_return_t result = mach_timebase_info(&tbi);
7613 if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
7614 return(result);
7615 }
7616
7617 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
7618 {
7619 if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
7620
7621 static uint64_t last_mach_absolute_time = 0;
7622 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
7623 uint64_t this_mach_absolute_time = mach_absolute_time();
7624 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
7625 {
7626 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
7627 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
7628 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
7629 last_mach_absolute_time = this_mach_absolute_time;
7630 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later.
7631 // (This bug happens all the time on 10.3, and we know that's not going to be fixed.)
7632 if (OSXVers >= OSXVers_10_4_Tiger)
7633 NotifyOfElusiveBug("mach_absolute_time went backwards!",
7634 "This error occurs from time to time, often on newly released hardware, "
7635 "and usually the exact cause is different in each instance.\r\r"
7636 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
7637 "and assign it to Radar Component “Kernel” Version “X”.");
7638 }
7639 last_mach_absolute_time = this_mach_absolute_time;
7640
7641 return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
7642 }
7643
7644 mDNSexport mDNSs32 mDNSPlatformUTC(void)
7645 {
7646 return time(NULL);
7647 }
7648
7649 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
7650 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
7651 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
7652 mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); }
7653 mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); }
7654 mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
7655 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
7656 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); }
7657 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
7658 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
7659 #endif
7660 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
7661
7662 mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep)
7663 {
7664 if (allowSleep && m->p->IOPMAssertion)
7665 {
7666 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
7667 IOPMAssertionRelease(m->p->IOPMAssertion);
7668 m->p->IOPMAssertion = 0;
7669 }
7670 else if (!allowSleep && m->p->IOPMAssertion == 0)
7671 {
7672 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, CFSTR("mDNSResponder"), &m->p->IOPMAssertion);
7673 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__);
7674 }
7675 }
7676
7677 mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
7678 {
7679 mDNSu32 ifindex;
7680
7681 // Sanity check
7682 ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID);
7683 if (ifindex <= 0)
7684 {
7685 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
7686 return;
7687 }
7688 mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration);
7689 }