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