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