]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mDNSMacOSX.c
mDNSResponder-576.30.4.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / mDNSMacOSX.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2013 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 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
28 #include "DNSCommon.h"
29 #include "uDNS.h"
30 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
31 #include "dns_sd.h" // For mDNSInterface_LocalOnly etc.
32 #include "PlatformCommon.h"
33 #include "uds_daemon.h"
34 #include "CryptoSupport.h"
35
36 #include <stdio.h>
37 #include <stdarg.h> // For va_list support
38 #include <stdlib.h> // For arc4random
39 #include <net/if.h>
40 #include <net/if_types.h> // For IFT_ETHER
41 #include <net/if_dl.h>
42 #include <net/bpf.h> // For BIOCSETIF etc.
43 #include <sys/uio.h>
44 #include <sys/param.h>
45 #include <sys/socket.h>
46 #include <sys/sysctl.h>
47 #include <sys/event.h>
48 #include <fcntl.h>
49 #include <sys/ioctl.h>
50 #include <time.h> // platform support for UTC time
51 #include <arpa/inet.h> // for inet_aton
52 #include <pthread.h>
53 #include <netdb.h> // for getaddrinfo
54 #include <sys/sockio.h> // for SIOCGIFEFLAGS
55 #include <notify.h>
56 #include <netinet/in.h> // For IP_RECVTTL
57 #ifndef IP_RECVTTL
58 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
59 #endif
60
61 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
62 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
63 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
64 #include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
65
66 #include <netinet/tcp.h>
67
68 #include <DebugServices.h>
69 #include "dnsinfo.h"
70
71 #include <ifaddrs.h>
72
73 #include <IOKit/IOKitLib.h>
74 #include <IOKit/IOMessage.h>
75
76 #include <IOKit/ps/IOPowerSources.h>
77 #include <IOKit/ps/IOPowerSourcesPrivate.h>
78 #include <IOKit/ps/IOPSKeys.h>
79
80 #include <mach/mach_error.h>
81 #include <mach/mach_port.h>
82 #include <mach/mach_time.h>
83 #include "helper.h"
84 #include "P2PPacketFilter.h"
85
86 #include <asl.h>
87 #include <SystemConfiguration/SCPrivate.h>
88
89 // Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
90 #include <Kernel/IOKit/apple80211/apple80211_var.h>
91
92 #if APPLE_OSX_mDNSResponder
93 #include <DeviceToDeviceManager/DeviceToDeviceManager.h>
94 #include <AWACS.h>
95 #if !NO_D2D
96 D2DStatus D2DInitialize(CFRunLoopRef runLoop, D2DServiceCallback serviceCallback, void* userData) __attribute__((weak_import));
97 D2DStatus D2DRetain(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
98 D2DStatus D2DStopAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
99 D2DStatus D2DRelease(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
100 D2DStatus D2DStartAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
101 D2DStatus D2DStartBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
102 D2DStatus D2DStopBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
103 void D2DStartResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
104 void D2DStopResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
105 D2DStatus D2DTerminate() __attribute__((weak_import));
106
107 #endif // ! NO_D2D
108
109 #else
110 #define NO_D2D 1
111 #define NO_AWACS 1
112 #endif // APPLE_OSX_mDNSResponder
113
114 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
115 #include <IOKit/platform/IOPlatformSupportPrivate.h>
116 #endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
117
118 #define kInterfaceSpecificOption "interface="
119
120 #define mDNS_IOREG_KEY "mDNS_KEY"
121 #define mDNS_IOREG_VALUE "2009-07-30"
122 #define mDNS_IOREG_KA_KEY "mDNS_Keepalive"
123 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
124
125 // cache the InterfaceID of the AWDL interface
126 static mDNSInterfaceID AWDLInterfaceID;
127
128 // ***************************************************************************
129 // Globals
130
131 #if COMPILER_LIKES_PRAGMA_MARK
132 #pragma mark - Globals
133 #endif
134
135 // By default we don't offer sleep proxy service
136 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
137 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
138 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
139 mDNSexport int OfferSleepProxyService = 0;
140 mDNSexport int DisableSleepProxyClient = 0;
141 mDNSexport int UseInternalSleepProxy = 1; // Set to non-zero to use internal (in-NIC) Sleep Proxy
142
143 mDNSexport int OSXVers, iOSVers;
144 mDNSexport int KQueueFD;
145
146 #ifndef NO_SECURITYFRAMEWORK
147 static CFArrayRef ServerCerts;
148 OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
149 #endif /* NO_SECURITYFRAMEWORK */
150
151 static CFStringRef NetworkChangedKey_IPv4;
152 static CFStringRef NetworkChangedKey_IPv6;
153 static CFStringRef NetworkChangedKey_Hostnames;
154 static CFStringRef NetworkChangedKey_Computername;
155 static CFStringRef NetworkChangedKey_DNS;
156 static CFStringRef NetworkChangedKey_StateInterfacePrefix;
157 static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
158 static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
159 static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity");
160 static CFStringRef NetworkChangedKey_PowerSettings = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
161
162 static char HINFO_HWstring_buffer[32];
163 static char *HINFO_HWstring = "Device";
164 static int HINFO_HWstring_prefixlen = 6;
165
166 mDNSexport int WatchDogReportingThreshold = 250;
167
168 dispatch_queue_t SSLqueue;
169
170 //To prevent blocking the main queue, all writes to DynamicStore happen on the DynamicStoreQueue
171 static dispatch_queue_t DynamicStoreQueue;
172
173 #if TARGET_OS_EMBEDDED
174 #define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
175 #endif
176
177 #if APPLE_OSX_mDNSResponder
178 static mDNSu8 SPMetricPortability = 99;
179 static mDNSu8 SPMetricMarginalPower = 99;
180 static mDNSu8 SPMetricTotalPower = 99;
181 static mDNSu8 SPMetricFeatures = 1; /* The current version supports TCP Keep Alive Feature */
182 mDNSexport domainname ActiveDirectoryPrimaryDomain;
183 mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
184 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
185 #endif // APPLE_OSX_mDNSResponder
186
187 // Don't send triggers too often. We arbitrarily limit it to three minutes.
188 #define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
189
190 // Used by AutoTunnel
191 const char btmmprefix[] = "btmmdns:";
192 const char dnsprefix[] = "dns:";
193
194 // String Array used to write list of private domains to Dynamic Store
195 static CFArrayRef privateDnsArray = NULL;
196
197 // ***************************************************************************
198 #if COMPILER_LIKES_PRAGMA_MARK
199 #pragma mark -
200 #pragma mark - D2D Support
201 #endif
202
203 #if !NO_D2D
204
205 mDNSexport void D2D_start_advertising_interface(NetworkInterfaceInfo *interface)
206 {
207 // AWDL wants the address and reverse address PTR record communicated
208 // via the D2D interface layer.
209 if (interface->InterfaceID == AWDLInterfaceID)
210 {
211 // only log if we have a valid record to start advertising
212 if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType)
213 LogInfo("D2D_start_advertising_interface: %s", interface->ifname);
214
215 if (interface->RR_A.resrec.RecordType)
216 external_start_advertising_service(&interface->RR_A.resrec, NULL);
217 if (interface->RR_PTR.resrec.RecordType)
218 external_start_advertising_service(&interface->RR_PTR.resrec, NULL);
219 }
220 }
221
222 mDNSexport void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface)
223 {
224 if (interface->InterfaceID == AWDLInterfaceID)
225 {
226 // only log if we have a valid record to stop advertising
227 if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType)
228 LogInfo("D2D_stop_advertising_interface: %s", interface->ifname);
229
230 if (interface->RR_A.resrec.RecordType)
231 external_stop_advertising_service(&interface->RR_A.resrec, NULL);
232 if (interface->RR_PTR.resrec.RecordType)
233 external_stop_advertising_service(&interface->RR_PTR.resrec, NULL);
234 }
235 }
236
237 // Name compression items for fake packet version number 1
238 static const mDNSu8 compression_packet_v1 = 0x01;
239
240 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" };
241 static mDNSu8 *const compression_limit = (mDNSu8 *) &compression_base_msg + sizeof(DNSMessage);
242 static mDNSu8 *const compression_lhs = (mDNSu8 *const) compression_base_msg.data + 27;
243
244 mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
245 mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len);
246
247 typedef struct D2DRecordListElem
248 {
249 struct D2DRecordListElem *next;
250 D2DServiceInstance instanceHandle;
251 D2DTransportType transportType;
252 AuthRecord ar; // must be last in the structure to accomodate extra space
253 // allocated for large records.
254 } D2DRecordListElem;
255
256 static D2DRecordListElem *D2DRecords = NULL; // List of records returned with D2DServiceFound events
257
258 typedef struct D2DBrowseListElem
259 {
260 struct D2DBrowseListElem *next;
261 domainname name;
262 mDNSu16 type;
263 unsigned int refCount;
264 } D2DBrowseListElem;
265
266 D2DBrowseListElem* D2DBrowseList = NULL;
267
268 mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
269 {
270 ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
271 ptr[1] = (mDNSu8)((val ) & 0xFF);
272 return ptr + sizeof(mDNSu16);
273 }
274
275 mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
276 {
277 ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
278 ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
279 ptr[2] = (mDNSu8)((val >> 8) & 0xFF);
280 ptr[3] = (mDNSu8)((val ) & 0xFF);
281 return ptr + sizeof(mDNSu32);
282 }
283
284 mDNSlocal void DomainnameToLower(const domainname * const in, domainname * const out)
285 {
286 const mDNSu8 * const start = (const mDNSu8 * const)in;
287 mDNSu8 *ptr = (mDNSu8*)start;
288 while(*ptr)
289 {
290 mDNSu8 c = *ptr;
291 out->c[ptr-start] = *ptr;
292 ptr++;
293 for (; c; c--,ptr++) out->c[ptr-start] = mDNSIsUpperCase(*ptr) ? (*ptr - 'A' + 'a') : *ptr;
294 }
295 out->c[ptr-start] = *ptr;
296 }
297
298 mDNSlocal mStatus DNSNameCompressionParseBytes(mDNS *const m, const mDNSu8 *const lhs, const mDNSu16 lhs_len, const mDNSu8 *const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
299 {
300 if (mDNS_LoggingEnabled)
301 {
302 LogInfo("%s", __func__);
303 LogInfo(" Static Bytes: (%d bytes)", compression_lhs - (mDNSu8*)&compression_base_msg);
304 PrintHex((mDNSu8*)&compression_base_msg, compression_lhs - (mDNSu8*)&compression_base_msg);
305 }
306
307 mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet
308
309 // Check to make sure we're not going to go past the end of the DNSMessage data
310 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
311 if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr;
312
313 // Copy the LHS onto our fake wire packet
314 mDNSPlatformMemCopy(ptr, lhs, lhs_len);
315 ptr += lhs_len - 1;
316
317 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
318 if (*ptr != compression_packet_v1) return mStatus_Incompatible;
319
320 // two bytes of CLASS
321 ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet);
322
323 // four bytes of TTL
324 ptr = putVal32(ptr, 120);
325
326 // Copy the RHS length into the RDLENGTH of our fake wire packet
327 ptr = putVal16(ptr, rhs_len);
328
329 // Copy the RHS onto our fake wire packet
330 mDNSPlatformMemCopy(ptr, rhs, rhs_len);
331 ptr += rhs_len;
332
333 if (mDNS_LoggingEnabled)
334 {
335 LogInfo(" Our Bytes (%d bytes): ", ptr - compression_lhs);
336 PrintHex(compression_lhs, ptr - compression_lhs);
337 }
338
339 ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec);
340 if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative)
341 { LogMsg("DNSNameCompressionParseBytes: failed to get large RR"); m->rec.r.resrec.RecordType = 0; return mStatus_UnknownErr; }
342 else LogInfo("DNSNameCompressionParseBytes: got rr: %s", CRDisplayString(m, &m->rec.r));
343
344 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, AuthRecordP2P, FreeD2DARElemCallback, NULL);
345 AssignDomainName(&rr->namestorage, &m->rec.namestorage);
346 rr->resrec.rdlength = m->rec.r.resrec.rdlength;
347 rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength;
348 mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength);
349 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
350 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
351
352 m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use
353
354 return mStatus_NoError;
355 }
356
357 mDNSlocal mDNSu8 * DNSNameCompressionBuildLHS(const domainname* typeDomain, DNS_TypeValues qtype)
358 {
359 mDNSu8 *ptr = putDomainNameAsLabels(&compression_base_msg, compression_lhs, compression_limit, typeDomain);
360 if (!ptr) return ptr;
361 *ptr = (qtype >> 8) & 0xff;
362 ptr += 1;
363 *ptr = qtype & 0xff;
364 ptr += 1;
365 *ptr = compression_packet_v1;
366 return ptr + 1;
367 }
368
369 mDNSlocal mDNSu8 * DNSNameCompressionBuildRHS(mDNSu8 *start, const ResourceRecord *const resourceRecord)
370 {
371 return putRData(&compression_base_msg, start, compression_limit, resourceRecord);
372 }
373
374 #define PRINT_DEBUG_BYTES_LIMIT 64 // set limit on number of record bytes printed for debugging
375
376 mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len)
377 {
378 mDNSu8 *end;
379 char buffer[49] = {0};
380 char *bufend = buffer + sizeof(buffer);
381
382 if (len > PRINT_DEBUG_BYTES_LIMIT)
383 {
384 LogInfo(" (limiting debug output to %d bytes)", PRINT_DEBUG_BYTES_LIMIT);
385 len = PRINT_DEBUG_BYTES_LIMIT;
386 }
387 end = data + len;
388
389 while(data < end)
390 {
391 char *ptr = buffer;
392 for(; data < end && ptr < bufend-1; ptr+=3,data++)
393 mDNS_snprintf(ptr, bufend - ptr, "%02X ", *data);
394 LogInfo(" %s", buffer);
395 }
396 }
397
398 mDNSlocal void PrintHelper(const char *const tag, mDNSu8 *lhs, mDNSu16 lhs_len, mDNSu8 *rhs, mDNSu16 rhs_len)
399 {
400 if (!mDNS_LoggingEnabled) return;
401
402 LogInfo("%s:", tag);
403 LogInfo(" LHS: (%d bytes)", lhs_len);
404 PrintHex(lhs, lhs_len);
405
406 if (!rhs) return;
407
408 LogInfo(" RHS: (%d bytes)", rhs_len);
409 PrintHex(rhs, rhs_len);
410 }
411
412 mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
413 {
414 (void)m; // unused
415 if (result == mStatus_MemFree)
416 {
417 D2DRecordListElem **ptr = &D2DRecords;
418 D2DRecordListElem *tmp;
419 while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
420 if (!*ptr) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m, rr)); return; }
421 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m, rr));
422 tmp = *ptr;
423 *ptr = (*ptr)->next;
424 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
425 mDNSPlatformMemFree(tmp);
426 }
427 }
428
429 mDNSexport void external_connection_release(const domainname *instance)
430 {
431 (void) instance;
432 D2DRecordListElem *ptr = D2DRecords;
433
434 for ( ; ptr ; ptr = ptr->next)
435 {
436 if ((ptr->ar.resrec.rrtype == kDNSServiceType_PTR) &&
437 SameDomainName(&ptr->ar.rdatastorage.u.name, instance))
438 {
439 LogInfo("external_connection_release: Calling D2DRelease(instanceHandle = %p, transportType = %d",
440 ptr->instanceHandle, ptr->transportType);
441 if (D2DRelease) D2DRelease(ptr->instanceHandle, ptr->transportType);
442 }
443 }
444 }
445
446 mDNSlocal void xD2DClearCache(const domainname *regType, DNS_TypeValues qtype)
447 {
448 D2DRecordListElem *ptr = D2DRecords;
449 for ( ; ptr ; ptr = ptr->next)
450 {
451 if ((ptr->ar.resrec.rrtype == qtype) && SameDomainName(&ptr->ar.namestorage, regType))
452 {
453 mDNS_Deregister(&mDNSStorage, &ptr->ar);
454 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage, &ptr->ar));
455 }
456 }
457 }
458
459 mDNSlocal D2DBrowseListElem ** D2DFindInBrowseList(const domainname *const name, mDNSu16 type)
460 {
461 D2DBrowseListElem **ptr = &D2DBrowseList;
462
463 for ( ; *ptr; ptr = &(*ptr)->next)
464 if ((*ptr)->type == type && SameDomainName(&(*ptr)->name, name))
465 break;
466
467 return ptr;
468 }
469
470 mDNSlocal unsigned int D2DBrowseListRefCount(const domainname *const name, mDNSu16 type)
471 {
472 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
473 return *ptr ? (*ptr)->refCount : 0;
474 }
475
476 mDNSlocal void D2DBrowseListRetain(const domainname *const name, mDNSu16 type)
477 {
478 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
479
480 if (!*ptr)
481 {
482 *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
483 mDNSPlatformMemZero(*ptr, sizeof(**ptr));
484 (*ptr)->type = type;
485 AssignDomainName(&(*ptr)->name, name);
486 }
487 (*ptr)->refCount += 1;
488
489 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
490 }
491
492 mDNSlocal void D2DBrowseListRelease(const domainname *const name, mDNSu16 type)
493 {
494 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
495
496 if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return; }
497
498 (*ptr)->refCount -= 1;
499
500 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
501
502 if (!(*ptr)->refCount)
503 {
504 D2DBrowseListElem *tmp = *ptr;
505 *ptr = (*ptr)->next;
506 mDNSPlatformMemFree(tmp);
507 }
508 }
509
510 mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
511 {
512 if (*(lhs + (lhs_len - 1)) == compression_packet_v1)
513 return DNSNameCompressionParseBytes(m, lhs, lhs_len, rhs, rhs_len, rr);
514 else
515 return mStatus_Incompatible;
516 }
517
518 mDNSlocal void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
519 {
520 if (result == kD2DSuccess)
521 {
522 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
523
524 mStatus err;
525 D2DRecordListElem *ptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
526
527 if (ptr == NULL) { LogMsg("xD2DAddToCache: memory allocation failure"); return; }
528
529 err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr->ar);
530 if (err)
531 {
532 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err);
533 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
534 mDNSPlatformMemFree(ptr);
535 return;
536 }
537 err = mDNS_Register(m, &ptr->ar);
538 if (err)
539 {
540 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err, ARDisplayString(m, &ptr->ar));
541 mDNSPlatformMemFree(ptr);
542 return;
543 }
544
545 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m, &ptr->ar));
546 ptr->instanceHandle = instanceHandle;
547 ptr->transportType = transportType;
548 ptr->next = D2DRecords;
549 D2DRecords = ptr;
550 }
551 else
552 LogMsg("xD2DAddToCache: Unexpected result %d", result);
553 }
554
555 mDNSlocal D2DRecordListElem * xD2DFindInList(mDNS *const m, const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize)
556 {
557 D2DRecordListElem *ptr = D2DRecords;
558 D2DRecordListElem *arptr;
559
560 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; }
561
562 arptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
563 if (arptr == NULL) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL; }
564
565 if (xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr->ar) != mStatus_NoError)
566 {
567 LogMsg("xD2DFindInList: xD2DParse failed for key: %p (%u) value: %p (%u)", key, keySize, value, valueSize);
568 mDNSPlatformMemFree(arptr);
569 return NULL;
570 }
571
572 while (ptr)
573 {
574 if (IdenticalResourceRecord(&arptr->ar.resrec, &ptr->ar.resrec)) break;
575 ptr = ptr->next;
576 }
577
578 if (!ptr) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(m, &arptr->ar));
579 mDNSPlatformMemFree(arptr);
580 return ptr;
581 }
582
583 mDNSlocal void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
584 {
585 (void)transportType; // We don't care about this, yet.
586 (void)instanceHandle; // We don't care about this, yet.
587
588 if (result == kD2DSuccess)
589 {
590 D2DRecordListElem *ptr = xD2DFindInList(m, key, keySize, value, valueSize);
591 if (ptr)
592 {
593 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m, &ptr->ar));
594 mDNS_Deregister(m, &ptr->ar);
595 }
596 }
597 else
598 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result);
599 }
600
601 mDNSlocal void xD2DServiceResolved(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
602 {
603 (void)m;
604 (void)key;
605 (void)keySize;
606 (void)value;
607 (void)valueSize;
608
609 if (result == kD2DSuccess)
610 {
611 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle);
612 if (D2DRetain) D2DRetain(instanceHandle, transportType);
613 }
614 else LogMsg("xD2DServiceResolved: Unexpected result %d", result);
615 }
616
617 mDNSlocal void xD2DRetainHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
618 {
619 (void)m;
620 (void)instanceHandle;
621 (void)transportType;
622 (void)key;
623 (void)keySize;
624 (void)value;
625 (void)valueSize;
626
627 if (result == kD2DSuccess) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle);
628 else LogMsg("xD2DRetainHappened: Unexpected result %d", result);
629 }
630
631 mDNSlocal void xD2DReleaseHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
632 {
633 (void)m;
634 (void)instanceHandle;
635 (void)transportType;
636 (void)key;
637 (void)keySize;
638 (void)value;
639 (void)valueSize;
640
641 if (result == kD2DSuccess) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle);
642 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result);
643 }
644
645 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)
646 {
647 mDNS *m = (mDNS *) userData;
648 const char *eventString = "unknown";
649
650 KQueueLock(m);
651
652 if (keySize > 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize);
653 if (valueSize > 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize);
654
655 switch (event)
656 {
657 case D2DServiceFound:
658 eventString = "D2DServiceFound";
659 break;
660 case D2DServiceLost:
661 eventString = "D2DServiceLost";
662 break;
663 case D2DServiceResolved:
664 eventString = "D2DServiceResolved";
665 break;
666 case D2DServiceRetained:
667 eventString = "D2DServiceRetained";
668 break;
669 case D2DServiceReleased:
670 eventString = "D2DServiceReleased";
671 break;
672 default:
673 break;
674 }
675
676 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);
677 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
678
679 switch (event)
680 {
681 case D2DServiceFound:
682 xD2DAddToCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
683 break;
684 case D2DServiceLost:
685 xD2DRemoveFromCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
686 break;
687 case D2DServiceResolved:
688 xD2DServiceResolved(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
689 break;
690 case D2DServiceRetained:
691 xD2DRetainHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
692 break;
693 case D2DServiceReleased:
694 xD2DReleaseHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
695 break;
696 default:
697 break;
698 }
699
700 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
701 KQueueUnlock(m, "xD2DServiceCallback");
702 }
703
704 // Map interface index and flags to a specific D2D transport type or D2DTransportMax if all plugins
705 // should be called.
706 // When D2DTransportMax is returned, if a specific transport should not be called, *excludedTransportType
707 // will be set to the excluded transport value, otherwise, it will be set to D2DTransportMax.
708 // If the return value is not D2DTransportMax, excludedTransportType is undefined.
709
710 mDNSlocal D2DTransportType xD2DInterfaceToTransportType(mDNSInterfaceID InterfaceID, DNSServiceFlags flags, D2DTransportType * excludedTransportType)
711 {
712 NetworkInterfaceInfoOSX *info;
713
714 // Default exludes the D2DAWDLTransport when D2DTransportMax is returned.
715 *excludedTransportType = D2DAWDLTransport;
716
717 // Call all D2D plugins when both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set.
718 if ((flags & kDNSServiceFlagsIncludeP2P) && (flags & kDNSServiceFlagsIncludeAWDL))
719 {
720 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (including AWDL) since both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set");
721 *excludedTransportType = D2DTransportMax;
722 return D2DTransportMax;
723 }
724 // Call all D2D plugins (exlcluding AWDL) when only kDNSServiceFlagsIncludeP2P is set.
725 else if (flags & kDNSServiceFlagsIncludeP2P)
726 {
727 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) since only kDNSServiceFlagsIncludeP2P is set");
728 return D2DTransportMax;
729 }
730 // Call AWDL D2D plugin when only kDNSServiceFlagsIncludeAWDL is set.
731 else if (flags & kDNSServiceFlagsIncludeAWDL)
732 {
733 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport since only kDNSServiceFlagsIncludeAWDL is set");
734 return D2DAWDLTransport;
735 }
736
737 if (InterfaceID == mDNSInterface_P2P)
738 {
739 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) for interface index mDNSInterface_P2P");
740 return D2DTransportMax;
741 }
742
743 // Compare to cached AWDL interface ID.
744 if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
745 {
746 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport for interface index %d", InterfaceID);
747 return D2DAWDLTransport;
748 }
749
750 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
751 if (info == NULL)
752 {
753 LogInfo("xD2DInterfaceToTransportType: Invalid interface index %d", InterfaceID);
754 return D2DTransportMax;
755 }
756
757 // Recognize AirDrop specific p2p* interface based on interface name.
758 if (strncmp(info->ifinfo.ifname, "p2p", 3) == 0)
759 {
760 LogInfo("xD2DInterfaceToTransportType: returning D2DWifiPeerToPeerTransport for interface index %d", InterfaceID);
761 return D2DWifiPeerToPeerTransport;
762 }
763
764 // Currently there is no way to identify Bluetooth interface by name,
765 // since they use "en*" based name strings.
766
767 LogInfo("xD2DInterfaceToTransportType: returning default D2DTransportMax for interface index %d", InterfaceID);
768 return D2DTransportMax;
769 }
770
771 mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
772 {
773 domainname lower;
774
775 if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
776 {
777 LogInfo("external_start_browsing_for_service: ignoring address record");
778 return;
779 }
780
781 DomainnameToLower(typeDomain, &lower);
782
783 if (!D2DBrowseListRefCount(&lower, qtype))
784 {
785 D2DTransportType transportType, excludedTransport;
786
787 LogInfo("external_start_browsing_for_service: Starting browse for: %##s %s", lower.c, DNSTypeName(qtype));
788 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
789 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
790
791 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
792 if (transportType == D2DTransportMax)
793 {
794 D2DTransportType i;
795 for (i = 0; i < D2DTransportMax; i++)
796 {
797 if (i == excludedTransport) continue;
798 if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
799 }
800 }
801 else
802 {
803 if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
804 }
805 }
806 D2DBrowseListRetain(&lower, qtype);
807 }
808
809 mDNSexport void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
810 {
811 domainname lower;
812
813 if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
814 {
815 LogInfo("external_stop_browsing_for_service: ignoring address record");
816 return;
817 }
818
819 DomainnameToLower(typeDomain, &lower);
820
821 D2DBrowseListRelease(&lower, qtype);
822 if (!D2DBrowseListRefCount(&lower, qtype))
823 {
824 D2DTransportType transportType, excludedTransport;
825
826 LogInfo("external_stop_browsing_for_service: Stopping browse for: %##s %s", lower.c, DNSTypeName(qtype));
827 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
828 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
829
830 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
831 if (transportType == D2DTransportMax)
832 {
833 D2DTransportType i;
834 for (i = 0; i < D2DTransportMax; i++)
835 {
836 if (i == excludedTransport) continue;
837 if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
838 }
839 }
840 else
841 {
842 if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
843 }
844
845 // The D2D driver may not generate the D2DServiceLost event for this key after
846 // the D2DStopBrowsingForKey*() call above. So, we flush the key from the D2D
847 // record cache now.
848 xD2DClearCache(&lower, qtype);
849 }
850 }
851
852 mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
853 {
854 domainname lower;
855 mDNSu8 *rhs = NULL;
856 mDNSu8 *end = NULL;
857 D2DTransportType transportType, excludedTransport;
858 DomainnameToLower(resourceRecord->name, &lower);
859
860 LogInfo("external_start_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
861 // For SRV records, update packet filter if p2p interface already exists, otherwise,
862 // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface.
863 if (resourceRecord->rrtype == kDNSType_SRV)
864 mDNSUpdatePacketFilter(NULL);
865
866 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
867 end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
868 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
869
870 transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
871 if (transportType == D2DTransportMax)
872 {
873 D2DTransportType i;
874 for (i = 0; i < D2DTransportMax; i++)
875 {
876 if (i == excludedTransport) continue;
877 if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
878 }
879 }
880 else
881 {
882 if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
883 }
884 }
885
886 mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
887 {
888 domainname lower;
889 mDNSu8 *rhs = NULL;
890 mDNSu8 *end = NULL;
891 D2DTransportType transportType, excludedTransport;
892 DomainnameToLower(resourceRecord->name, &lower);
893
894 LogInfo("external_stop_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
895
896 // For SRV records, update packet filter to to remove this port from list
897 if (resourceRecord->rrtype == kDNSType_SRV)
898 mDNSUpdatePacketFilter(resourceRecord);
899
900 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
901 end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
902 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
903
904 transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
905 if (transportType == D2DTransportMax)
906 {
907 D2DTransportType i;
908 for (i = 0; i < D2DTransportMax; i++)
909 {
910 if (i == excludedTransport) continue;
911 if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
912 }
913 }
914 else
915 {
916 if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
917 }
918 }
919
920 mDNSexport void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags)
921 {
922 domainname lower;
923 mDNSu8 *rhs = NULL;
924 mDNSu8 *end = NULL;
925 mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
926 D2DTransportType transportType, excludedTransport;
927 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
928
929 LogInfo("external_start_resolving_service: %##s", fqdn->c);
930 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
931 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
932 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
933
934 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
935 if (transportType == D2DTransportMax)
936 {
937 // Resolving over all the transports, except for excludedTransport if set.
938 D2DTransportType i;
939 for (i = 0; i < D2DTransportMax; i++)
940 {
941 if (i == excludedTransport) continue;
942 if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
943
944 if (i == D2DAWDLTransport)
945 AWDL_used = true;
946 }
947 }
948 else
949 {
950 // Resolving over one specific transport.
951 if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
952
953 if (transportType == D2DAWDLTransport)
954 AWDL_used = true;
955 }
956
957 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
958 // We only want these records going to AWDL, so use AWDLInterfaceID as the
959 // interface and don't set any other flags.
960 if (AWDL_used && AWDLInterfaceID)
961 {
962 LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL");
963 external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, NULL);
964 external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, NULL);
965 }
966 }
967
968 mDNSexport void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags)
969 {
970 domainname lower;
971 mDNSu8 *rhs = NULL;
972 mDNSu8 *end = NULL;
973 mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
974 D2DTransportType transportType, excludedTransport;
975 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
976
977 LogInfo("external_stop_resolving_service: %##s", fqdn->c);
978 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
979 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
980 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
981
982 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
983 if (transportType == D2DTransportMax)
984 {
985 D2DTransportType i;
986 for (i = 0; i < D2DTransportMax; i++)
987 {
988 if (i == excludedTransport) continue;
989 if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
990
991 if (i == D2DAWDLTransport)
992 AWDL_used = true;
993 }
994 }
995 else
996 {
997 if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
998
999 if (transportType == D2DAWDLTransport)
1000 AWDL_used = true;
1001 }
1002
1003 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
1004 // We only want these records going to AWDL, so use AWDLInterfaceID as the
1005 // interface and don't set any other flags.
1006 if (AWDL_used && AWDLInterfaceID)
1007 {
1008 LogInfo("external_stop_resolving_service: stop browse for TXT and SRV on AWDL");
1009 external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, NULL);
1010 external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, NULL);
1011 }
1012 }
1013
1014 #elif APPLE_OSX_mDNSResponder
1015
1016 mDNSexport void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;}
1017 mDNSexport void external_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;}
1018 mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
1019 mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
1020 mDNSexport void external_start_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;}
1021 mDNSexport void external_stop_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;}
1022
1023 #endif // ! NO_D2D
1024
1025 // ***************************************************************************
1026 // Functions
1027
1028 #if COMPILER_LIKES_PRAGMA_MARK
1029 #pragma mark -
1030 #pragma mark - Utility Functions
1031 #endif
1032
1033 // We only attempt to send and receive multicast packets on interfaces that are
1034 // (a) flagged as multicast-capable
1035 // (b) *not* flagged as point-to-point (e.g. modem)
1036 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
1037 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
1038 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
1039
1040 // We also don't want to use multicast on *any* interface on very constrained devices.
1041 #if TARGET_OS_NANO
1042 #define MulticastInterface(i) (mDNSfalse)
1043 #else
1044 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
1045 #endif
1046
1047 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
1048 {
1049 static int notifyCount = 0;
1050 if (notifyCount) return;
1051
1052 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
1053 // To avoid this, we don't try to display alerts in the first three minutes after boot.
1054 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
1055
1056 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
1057 #if !ForceAlerts
1058 {
1059 // Determine if we're at Apple (17.*.*.*)
1060 NetworkInterfaceInfoOSX *i;
1061 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
1062 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
1063 break;
1064 if (!i) return; // If not at Apple, don't show the alert
1065 }
1066 #endif
1067
1068 LogMsg("%s", title);
1069 LogMsg("%s", msg);
1070 // Display a notification to the user
1071 notifyCount++;
1072
1073 #ifndef NO_CFUSERNOTIFICATION
1074 mDNSNotify(title, msg);
1075 #endif /* NO_CFUSERNOTIFICATION */
1076 }
1077
1078 // Returns true if it is an AppleTV based hardware running iOS, false otherwise
1079 mDNSlocal mDNSBool IsAppleTV(void)
1080 {
1081 #if TARGET_OS_EMBEDDED
1082 static mDNSBool sInitialized = mDNSfalse;
1083 static mDNSBool sIsAppleTV = mDNSfalse;
1084 CFStringRef deviceClass = NULL;
1085
1086 if(!sInitialized)
1087 {
1088 deviceClass = (CFStringRef) MGCopyAnswer(kMGQDeviceClass, NULL);
1089 if(deviceClass)
1090 {
1091 if(CFEqual(deviceClass, kMGDeviceClassAppleTV))
1092 sIsAppleTV = mDNStrue;
1093 CFRelease(deviceClass);
1094 }
1095 sInitialized = mDNStrue;
1096 }
1097 return(sIsAppleTV);
1098 #else
1099 return mDNSfalse;
1100 #endif // TARGET_OS_EMBEDDED
1101 }
1102
1103 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
1104 {
1105 static struct ifaddrs *ifa = NULL;
1106
1107 if (refresh && ifa)
1108 {
1109 freeifaddrs(ifa);
1110 ifa = NULL;
1111 }
1112
1113 if (ifa == NULL)
1114 getifaddrs(&ifa);
1115 return ifa;
1116 }
1117
1118 mDNSlocal void DynamicStoreWrite(int key, const char* subkey, uintptr_t value, signed long valueCnt)
1119 {
1120 CFStringRef sckey = NULL;
1121 Boolean release_sckey = FALSE;
1122 CFDataRef bytes = NULL;
1123 CFPropertyListRef plist = NULL;
1124 SCDynamicStoreRef store = NULL;
1125
1126 switch ((enum mDNSDynamicStoreSetConfigKey)key)
1127 {
1128 case kmDNSMulticastConfig:
1129 sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
1130 break;
1131 case kmDNSDynamicConfig:
1132 sckey = CFSTR("State:/Network/DynamicDNS");
1133 break;
1134 case kmDNSPrivateConfig:
1135 sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
1136 break;
1137 case kmDNSBackToMyMacConfig:
1138 sckey = CFSTR("State:/Network/BackToMyMac");
1139 break;
1140 case kmDNSSleepProxyServersState:
1141 {
1142 CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0);
1143 CFStringAppend(tmp, CFSTR("State:/Network/Interface/"));
1144 CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8);
1145 CFStringAppend(tmp, CFSTR("/SleepProxyServers"));
1146 sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp);
1147 release_sckey = TRUE;
1148 CFRelease(tmp);
1149 break;
1150 }
1151 case kmDNSDebugState:
1152 sckey = CFSTR("State:/Network/mDNSResponder/DebugState");
1153 break;
1154 default:
1155 LogMsg("unrecognized key %d", key);
1156 goto fin;
1157 }
1158 if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
1159 valueCnt, kCFAllocatorNull)))
1160 {
1161 LogMsg("CFDataCreateWithBytesNoCopy of value failed");
1162 goto fin;
1163 }
1164 if (NULL == (plist = CFPropertyListCreateFromXMLData(NULL, bytes,
1165 kCFPropertyListImmutable, NULL)))
1166 {
1167 LogMsg("CFPropertyListCreateFromXMLData of bytes failed");
1168 goto fin;
1169 }
1170 CFRelease(bytes);
1171 bytes = NULL;
1172 if (NULL == (store = SCDynamicStoreCreate(NULL,
1173 CFSTR(kmDNSResponderServName), NULL, NULL)))
1174 {
1175 LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
1176 goto fin;
1177 }
1178 SCDynamicStoreSetValue(store, sckey, plist);
1179
1180 fin:
1181 if (NULL != bytes)
1182 CFRelease(bytes);
1183 if (NULL != plist)
1184 CFRelease(plist);
1185 if (NULL != store)
1186 CFRelease(store);
1187 if (release_sckey && sckey)
1188 CFRelease(sckey);
1189 }
1190
1191 mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value)
1192 {
1193 CFPropertyListRef valueCopy;
1194 char *subkeyCopy = NULL;
1195 if (!value)
1196 return;
1197
1198 // We need to copy the key and value before we dispatch off the block below as the
1199 // caller will free the memory once we return from this function.
1200 valueCopy = CFPropertyListCreateDeepCopy(NULL, value, kCFPropertyListImmutable);
1201 if (!valueCopy)
1202 {
1203 LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
1204 return;
1205 }
1206 if (subkey)
1207 {
1208 int len = strlen(subkey);
1209 subkeyCopy = mDNSPlatformMemAllocate(len + 1);
1210 if (!subkeyCopy)
1211 {
1212 LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
1213 return;
1214 }
1215 mDNSPlatformMemCopy(subkeyCopy, subkey, len);
1216 subkeyCopy[len] = 0;
1217 }
1218
1219 dispatch_async(DynamicStoreQueue, ^{
1220 CFWriteStreamRef stream = NULL;
1221 CFDataRef bytes = NULL;
1222 CFStringRef error;
1223 CFIndex ret;
1224
1225 if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL)))
1226 {
1227 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
1228 goto END;
1229 }
1230 CFWriteStreamOpen(stream);
1231 ret = CFPropertyListWriteToStream(valueCopy, stream, kCFPropertyListBinaryFormat_v1_0, &error);
1232 if (ret == 0)
1233 {
1234 LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
1235 goto END;
1236 }
1237 if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten)))
1238 {
1239 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
1240 goto END;
1241 }
1242 CFWriteStreamClose(stream);
1243 CFRelease(stream);
1244 stream = NULL;
1245 LogInfo("mDNSDynamicStoreSetConfig: key %d subkey %s", key, subkeyCopy);
1246 DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes));
1247
1248 END:
1249 CFRelease(valueCopy);
1250 if (NULL != stream)
1251 {
1252 CFWriteStreamClose(stream);
1253 CFRelease(stream);
1254 }
1255 if (NULL != bytes)
1256 CFRelease(bytes);
1257 if (subkeyCopy)
1258 mDNSPlatformMemFree(subkeyCopy);
1259 });
1260 }
1261
1262 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
1263 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
1264 {
1265 NetworkInterfaceInfoOSX *i;
1266 for (i = m->p->InterfaceList; i; i = i->next)
1267 if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
1268 ((type == AF_UNSPEC ) ||
1269 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
1270 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
1271 return(NULL);
1272 }
1273
1274 #if TARGET_OS_EMBEDDED
1275 mDNSlocal SCPreferencesRef mDNSManagedPrefsGet(void)
1276 {
1277 SCPreferencesRef smDNSManagedPrefs = NULL;
1278 smDNSManagedPrefs = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("mDNSManagedPrefs"), kmDNSResponderManagedPrefsID);
1279
1280 return (smDNSManagedPrefs);
1281 }
1282
1283 mDNSlocal mDNSBool GetmDNSManagedPrefKeyVal(SCPreferencesRef prefs, CFStringRef key)
1284 {
1285 mDNSBool val = mDNSfalse;
1286 CFBooleanRef val_cf = NULL;
1287
1288 if (prefs != NULL)
1289 {
1290 val_cf = SCPreferencesGetValue(prefs, key);
1291 if (isA_CFBoolean(val_cf) != NULL)
1292 val = CFBooleanGetValue(val_cf); //When mDNSResponder-Debug-profile is Installed
1293 else
1294 val = mDNSfalse; //When mDNSResponder-Debug-profile is Uninstalled
1295 }
1296 else
1297 {
1298 LogMsg("GetmDNSManagedPrefKeyVal: mDNSManagedPrefs are NULL!");
1299 val = mDNSfalse;
1300 }
1301 if (val_cf)
1302 CFRelease(val_cf);
1303 return (val);
1304 }
1305
1306 mDNSexport mDNSBool GetmDNSManagedPref(CFStringRef key)
1307 {
1308 SCPreferencesRef managed = NULL;
1309 mDNSBool ret_value;
1310
1311 managed = mDNSManagedPrefsGet();
1312 ret_value = GetmDNSManagedPrefKeyVal(managed, key);
1313
1314 if (managed)
1315 CFRelease(managed);
1316 return (ret_value);
1317 }
1318 #endif //TARGET_OS_EMBEDDED
1319
1320 mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
1321 {
1322 struct ifaddrs *ifa;
1323 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
1324 if (ifa->ifa_addr->sa_family == AF_LINK)
1325 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
1326 { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
1327 return -1;
1328 }
1329
1330 mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex)
1331 {
1332 mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
1333 NetworkInterfaceInfoOSX *i;
1334
1335 // Don't get tricked by inactive interfaces
1336 for (i = m->p->InterfaceList; i; i = i->next)
1337 if (i->Registered && i->scope_id == scope_id) return(i);
1338
1339 return mDNSNULL;
1340 }
1341
1342 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
1343 {
1344 if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
1345 if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
1346 if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
1347
1348 NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
1349 if (!ifi)
1350 {
1351 // Not found. Make sure our interface list is up to date, then try again.
1352 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
1353 mDNSMacOSXNetworkChanged(m);
1354 ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
1355 }
1356
1357 if (!ifi) return(mDNSNULL);
1358
1359 return(ifi->ifinfo.InterfaceID);
1360 }
1361
1362
1363 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
1364 {
1365 NetworkInterfaceInfoOSX *i;
1366 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
1367 if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
1368 if (id == mDNSInterface_Any ) return(0);
1369
1370 mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
1371
1372 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
1373 for (i = m->p->InterfaceList; i; i = i->next)
1374 if (i->scope_id == scope_id) return(i->scope_id);
1375
1376 // If we are supposed to suppress network change, return "id" back
1377 if (suppressNetworkChange) return scope_id;
1378
1379 // Not found. Make sure our interface list is up to date, then try again.
1380 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
1381 mDNSMacOSXNetworkChanged(m);
1382 for (i = m->p->InterfaceList; i; i = i->next)
1383 if (i->scope_id == scope_id) return(i->scope_id);
1384
1385 return(0);
1386 }
1387
1388 #if APPLE_OSX_mDNSResponder
1389 mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...)
1390 {
1391 if (iOSVers)
1392 return; // No ASL on iOS
1393
1394 static char buffer[512];
1395 aslmsg asl_msg = asl_new(ASL_TYPE_MSG);
1396
1397 if (!asl_msg) { LogMsg("mDNSASLLog: asl_new failed"); return; }
1398 if (uuid)
1399 {
1400 char uuidStr[37];
1401 uuid_unparse(*uuid, uuidStr);
1402 asl_set (asl_msg, "com.apple.message.uuid", uuidStr);
1403 }
1404
1405 static char domainBase[] = "com.apple.mDNSResponder.%s";
1406 mDNS_snprintf (buffer, sizeof(buffer), domainBase, subdomain);
1407 asl_set (asl_msg, "com.apple.message.domain", buffer);
1408
1409 if (result) asl_set(asl_msg, "com.apple.message.result", result);
1410 if (signature) asl_set(asl_msg, "com.apple.message.signature", signature);
1411
1412 va_list ptr;
1413 va_start(ptr,fmt);
1414 mDNS_vsnprintf(buffer, sizeof(buffer), fmt, ptr);
1415 va_end(ptr);
1416
1417 int old_filter = asl_set_filter(NULL,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
1418 asl_log(NULL, asl_msg, ASL_LEVEL_DEBUG, "%s", buffer);
1419 asl_set_filter(NULL, old_filter);
1420 asl_free(asl_msg);
1421 }
1422
1423
1424 mDNSlocal void mDNSLogDNSSECStatistics(mDNS *const m)
1425 {
1426 char buffer[16];
1427
1428 aslmsg aslmsg = asl_new(ASL_TYPE_MSG);
1429
1430 // If we failed to allocate an aslmsg structure, keep accumulating
1431 // the statistics and try again at the next log interval.
1432 if (!aslmsg)
1433 {
1434 LogMsg("mDNSLogDNSSECStatistics: asl_new() failed!");
1435 return;
1436 }
1437
1438 asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.DNSSECstatistics");
1439
1440 if (m->rrcache_totalused_unicast)
1441 {
1442 mDNS_snprintf(buffer, sizeof(buffer), "%u", (mDNSu32) ((unsigned long)(m->DNSSECStats.TotalMemUsed * 100))/m->rrcache_totalused_unicast);
1443 }
1444 else
1445 {
1446 LogMsg("mDNSLogDNSSECStatistics: unicast is zero");
1447 buffer[0] = 0;
1448 }
1449 asl_set(aslmsg,"com.apple.message.MemUsage", buffer);
1450
1451 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency0);
1452 asl_set(aslmsg,"com.apple.message.Latency0", buffer);
1453 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency10);
1454 asl_set(aslmsg,"com.apple.message.Latency10", buffer);
1455 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency20);
1456 asl_set(aslmsg,"com.apple.message.Latency20", buffer);
1457 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency50);
1458 asl_set(aslmsg,"com.apple.message.Latency50", buffer);
1459 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency100);
1460 asl_set(aslmsg,"com.apple.message.Latency100", buffer);
1461
1462 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets0);
1463 asl_set(aslmsg,"com.apple.message.ExtraPackets0", buffer);
1464 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets3);
1465 asl_set(aslmsg,"com.apple.message.ExtraPackets3", buffer);
1466 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets7);
1467 asl_set(aslmsg,"com.apple.message.ExtraPackets7", buffer);
1468 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets10);
1469 asl_set(aslmsg,"com.apple.message.ExtraPackets10", buffer);
1470
1471 // Ignore IndeterminateStatus as we don't log them
1472 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.SecureStatus);
1473 asl_set(aslmsg,"com.apple.message.SecureStatus", buffer);
1474 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.InsecureStatus);
1475 asl_set(aslmsg,"com.apple.message.InsecureStatus", buffer);
1476 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.BogusStatus);
1477 asl_set(aslmsg,"com.apple.message.BogusStatus", buffer);
1478 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NoResponseStatus);
1479 asl_set(aslmsg,"com.apple.message.NoResponseStatus", buffer);
1480
1481 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NumProbesSent);
1482 asl_set(aslmsg,"com.apple.message.NumProbesSent", buffer);
1483 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize0);
1484 asl_set(aslmsg,"com.apple.message.MsgSize0", buffer);
1485 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize1);
1486 asl_set(aslmsg,"com.apple.message.MsgSize1", buffer);
1487 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize2);
1488 asl_set(aslmsg,"com.apple.message.MsgSize2", buffer);
1489
1490 asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, "");
1491 asl_free(aslmsg);
1492 }
1493
1494 // Calculate packets per hour given total packet count and interval in seconds.
1495 // Cast one term of multiplication to (long) to use 64-bit arithmetic
1496 // and avoid a potential 32-bit overflow prior to the division.
1497 #define ONE_HOUR 3600
1498 #define PACKET_RATE(PACKETS, INTERVAL) (int)(((long) (PACKETS) * ONE_HOUR)/(INTERVAL))
1499
1500 // Put packet rate data in discrete buckets.
1501 mDNSlocal int mDNSBucketData(int inputData, int interval)
1502 {
1503 if (!interval)
1504 {
1505 LogMsg("mDNSBucketData: interval is zero!");
1506 return 0;
1507 }
1508
1509 int ratePerHour = PACKET_RATE(inputData, interval);
1510 int bucket;
1511
1512 if (ratePerHour == 0)
1513 bucket = 0;
1514 else if (ratePerHour <= 10)
1515 bucket = 10;
1516 else if (ratePerHour <= 100)
1517 bucket = 100;
1518 else if (ratePerHour <= 1000)
1519 bucket = 1000;
1520 else if (ratePerHour <= 5000)
1521 bucket = 5000;
1522 else if (ratePerHour <= 10000)
1523 bucket = 10000;
1524 else if (ratePerHour <= 50000)
1525 bucket = 50000;
1526 else if (ratePerHour <= 100000)
1527 bucket = 100000;
1528 else if (ratePerHour <= 250000)
1529 bucket = 250000;
1530 else if (ratePerHour <= 500000)
1531 bucket = 500000;
1532 else
1533 bucket = 1000000;
1534
1535 return bucket;
1536 }
1537
1538 mDNSlocal void mDNSLogBonjourStatistics(mDNS *const m)
1539 {
1540 static mDNSs32 last_PktNum, last_MPktNum;
1541 static mDNSs32 last_UnicastPacketsSent, last_MulticastPacketsSent;
1542 static mDNSs32 last_RemoteSubnet;
1543
1544 mDNSs32 interval;
1545 char buffer[16];
1546 mDNSs32 inMulticast = m->MPktNum - last_MPktNum;
1547 mDNSs32 inUnicast = m->PktNum - last_PktNum - inMulticast;
1548 mDNSs32 outUnicast = m->UnicastPacketsSent - last_UnicastPacketsSent;
1549 mDNSs32 outMulticast = m->MulticastPacketsSent - last_MulticastPacketsSent;
1550 mDNSs32 remoteSubnet = m->RemoteSubnet - last_RemoteSubnet;
1551
1552
1553 // save starting values for new interval
1554 last_PktNum = m->PktNum;
1555 last_MPktNum = m->MPktNum;
1556 last_UnicastPacketsSent = m->UnicastPacketsSent;
1557 last_MulticastPacketsSent = m->MulticastPacketsSent;
1558 last_RemoteSubnet = m->RemoteSubnet;
1559
1560 // Need a non-zero active time interval.
1561 if (!m->ActiveStatTime)
1562 return;
1563
1564 // Round interval time to nearest hour boundary. Less then 30 minutes rounds to zero.
1565 interval = (m->ActiveStatTime + ONE_HOUR/2)/ONE_HOUR;
1566
1567 // Use a minimum of 30 minutes of awake time to calculate average packet rates.
1568 // The rounded awake interval should not be greater than the rounded reporting
1569 // interval.
1570 if ((interval == 0) || (interval > (kDefaultNextStatsticsLogTime + ONE_HOUR/2)/ONE_HOUR))
1571 return;
1572
1573 aslmsg aslmsg = asl_new(ASL_TYPE_MSG);
1574
1575 if (!aslmsg)
1576 {
1577 LogMsg("mDNSLogBonjourStatistics: asl_new() failed!");
1578 return;
1579 }
1580 // log in MessageTracer format
1581 asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.statistics");
1582
1583 snprintf(buffer, sizeof(buffer), "%d", interval);
1584 asl_set(aslmsg,"com.apple.message.interval", buffer);
1585
1586 // log the packet rates as packets per hour
1587 snprintf(buffer, sizeof(buffer), "%d",
1588 mDNSBucketData(inUnicast, m->ActiveStatTime));
1589 asl_set(aslmsg,"com.apple.message.UnicastIn", buffer);
1590
1591 snprintf(buffer, sizeof(buffer), "%d",
1592 mDNSBucketData(inMulticast, m->ActiveStatTime));
1593 asl_set(aslmsg,"com.apple.message.MulticastIn", buffer);
1594
1595 snprintf(buffer, sizeof(buffer), "%d",
1596 mDNSBucketData(outUnicast, m->ActiveStatTime));
1597 asl_set(aslmsg,"com.apple.message.UnicastOut", buffer);
1598
1599 snprintf(buffer, sizeof(buffer), "%d",
1600 mDNSBucketData(outMulticast, m->ActiveStatTime));
1601 asl_set(aslmsg,"com.apple.message.MulticastOut", buffer);
1602
1603 snprintf(buffer, sizeof(buffer), "%d",
1604 mDNSBucketData(remoteSubnet, m->ActiveStatTime));
1605 asl_set(aslmsg,"com.apple.message.RemoteSubnet", buffer);
1606
1607 asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, "");
1608
1609 asl_free(aslmsg);
1610 }
1611
1612 // Log multicast and unicast traffic statistics to MessageTracer on OSX
1613 mDNSexport void mDNSLogStatistics(mDNS *const m)
1614 {
1615 // MessageTracer only available on OSX
1616 if (iOSVers)
1617 return;
1618
1619 mDNSs32 currentUTC = mDNSPlatformUTC();
1620
1621 // log runtime statistics
1622 if ((currentUTC - m->NextStatLogTime) >= 0)
1623 {
1624 m->NextStatLogTime = currentUTC + kDefaultNextStatsticsLogTime;
1625 // If StatStartTime is zero, it hasn't been reinitialized yet
1626 // in the wakeup code path.
1627 if (m->StatStartTime)
1628 {
1629 m->ActiveStatTime += currentUTC - m->StatStartTime;
1630 }
1631
1632 // Only log statistics if we have recorded some active time during
1633 // this statistics interval.
1634 if (m->ActiveStatTime)
1635 {
1636 mDNSLogBonjourStatistics(m);
1637 mDNSLogDNSSECStatistics(m);
1638 }
1639
1640 // Start a new statistics gathering interval.
1641 m->StatStartTime = currentUTC;
1642 m->ActiveStatTime = 0;
1643 }
1644 }
1645
1646 #endif // APPLE_OSX_mDNSResponder
1647
1648 #if COMPILER_LIKES_PRAGMA_MARK
1649 #pragma mark -
1650 #pragma mark - UDP & TCP send & receive
1651 #endif
1652
1653 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
1654 {
1655 mDNSBool result = mDNSfalse;
1656 SCNetworkConnectionFlags flags;
1657 CFDataRef remote_addr;
1658 CFMutableDictionaryRef options;
1659 SCNetworkReachabilityRef ReachRef = NULL;
1660
1661 options = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1662 remote_addr = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len);
1663 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, remote_addr);
1664 CFDictionarySetValue(options, kSCNetworkReachabilityOptionServerBypass, kCFBooleanTrue);
1665 ReachRef = SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault, options);
1666 CFRelease(options);
1667 CFRelease(remote_addr);
1668
1669 if (!ReachRef)
1670 {
1671 LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions");
1672 goto end;
1673 }
1674 if (!SCNetworkReachabilityGetFlags(ReachRef, &flags))
1675 {
1676 LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags");
1677 goto end;
1678 }
1679 result = flags & kSCNetworkFlagsConnectionRequired;
1680
1681 end:
1682 if (ReachRef)
1683 CFRelease(ReachRef);
1684 return result;
1685 }
1686
1687 // Set traffic class for socket
1688 mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass)
1689 {
1690 int traffic_class;
1691
1692 if (useBackgroundTrafficClass)
1693 traffic_class = SO_TC_BK_SYS;
1694 else
1695 traffic_class = SO_TC_CTL;
1696
1697 (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class));
1698 }
1699
1700 mDNSexport void mDNSPlatformSetuDNSSocktOpt(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q)
1701 {
1702 if (src)
1703 {
1704 int s;
1705
1706 if (dst->type == mDNSAddrType_IPv4)
1707 s = src->ss.sktv4;
1708 else
1709 s = src->ss.sktv6;
1710
1711 if (q->pid)
1712 {
1713 if (setsockopt(s, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1)
1714 LogInfo("mDNSPlatformSetuDNSSocktOpt: Delegate PID failed %s for PID %d", strerror(errno), q->pid);
1715 }
1716 else
1717 {
1718 if (setsockopt(s, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1)
1719 LogInfo("mDNSPlatformSetuDNSSocktOpt: Delegate UUID failed %s", strerror(errno));
1720 }
1721
1722 #if defined(SO_NOWAKEFROMSLEEP)
1723 int nowake = 1;
1724 if (setsockopt(s, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
1725 LogInfo("mDNSPlatformSetuDNSSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
1726 #endif
1727
1728 if (q->DenyOnCellInterface || q->DenyOnExpInterface)
1729 {
1730 #if defined(SO_RESTRICT_DENY_CELLULAR)
1731 if (q->DenyOnCellInterface)
1732 {
1733 int restrictions = 0;
1734 restrictions = SO_RESTRICT_DENY_CELLULAR;
1735 if (setsockopt(s, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1)
1736 LogInfo("mDNSPlatformSetuDNSSocktOpt: SO_RESTRICT_DENY_CELLULAR failed %s", strerror(errno));
1737 }
1738 #endif
1739 #if defined(SO_RESTRICT_DENY_EXPENSIVE)
1740 if (q->DenyOnExpInterface)
1741 {
1742 int restrictions = 0;
1743 restrictions = SO_RESTRICT_DENY_EXPENSIVE;
1744 if (setsockopt(s, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1)
1745 LogInfo("mDNSPlatformSetuDNSSocktOpt: SO_RESTRICT_DENY_EXPENSIVE failed %s", strerror(errno));
1746 }
1747 #endif
1748 }
1749
1750 }
1751 }
1752
1753 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
1754 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
1755 // OR send via our primary v4 unicast socket
1756 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
1757 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
1758 mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
1759 mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
1760 {
1761 NetworkInterfaceInfoOSX *info = mDNSNULL;
1762 struct sockaddr_storage to;
1763 int s = -1, err;
1764 mStatus result = mStatus_NoError;
1765
1766 if (InterfaceID)
1767 {
1768 info = IfindexToInterfaceInfoOSX(m, InterfaceID);
1769 if (info == NULL)
1770 {
1771 // We may not have registered interfaces with the "core" as we may not have
1772 // seen any interface notifications yet. This typically happens during wakeup
1773 // where we might try to send DNS requests (non-SuppressUnusable questions internal
1774 // to mDNSResponder) before we receive network notifications.
1775 LogInfo("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
1776 return mStatus_BadParamErr;
1777 }
1778 }
1779
1780 char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
1781
1782 if (dst->type == mDNSAddrType_IPv4)
1783 {
1784 struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
1785 sin_to->sin_len = sizeof(*sin_to);
1786 sin_to->sin_family = AF_INET;
1787 sin_to->sin_port = dstPort.NotAnInteger;
1788 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1789 s = (src ? src->ss : m->p->permanentsockets).sktv4;
1790
1791 if (info) // Specify outgoing interface
1792 {
1793 if (!mDNSAddrIsDNSMulticast(dst))
1794 {
1795 #ifdef IP_BOUND_IF
1796 if (info->scope_id == 0)
1797 LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
1798 else
1799 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1800 #else
1801 {
1802 static int displayed = 0;
1803 if (displayed < 1000)
1804 {
1805 displayed++;
1806 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
1807 }
1808 }
1809 #endif
1810 }
1811 else
1812 #ifdef IP_MULTICAST_IFINDEX
1813 {
1814 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IFINDEX, &info->scope_id, sizeof(info->scope_id));
1815 // We get an error when we compile on a machine that supports this option and run the binary on
1816 // a different machine that does not support it
1817 if (err < 0)
1818 {
1819 if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno);
1820 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
1821 if (err < 0 && !m->p->NetworkChanged)
1822 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
1823 }
1824 }
1825 #else
1826 {
1827 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
1828 if (err < 0 && !m->p->NetworkChanged)
1829 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
1830
1831 }
1832 #endif
1833 }
1834 }
1835
1836 else if (dst->type == mDNSAddrType_IPv6)
1837 {
1838 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
1839 sin6_to->sin6_len = sizeof(*sin6_to);
1840 sin6_to->sin6_family = AF_INET6;
1841 sin6_to->sin6_port = dstPort.NotAnInteger;
1842 sin6_to->sin6_flowinfo = 0;
1843 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
1844 sin6_to->sin6_scope_id = info ? info->scope_id : 0;
1845 s = (src ? src->ss : m->p->permanentsockets).sktv6;
1846 if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
1847 {
1848 err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
1849 if (err < 0)
1850 {
1851 char name[IFNAMSIZ];
1852 if (if_indextoname(info->scope_id, name) != NULL)
1853 LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno));
1854 else
1855 LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id);
1856 }
1857 }
1858 }
1859
1860 else
1861 {
1862 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1863 #if ForceAlerts
1864 *(long*)0 = 0;
1865 #endif
1866 return mStatus_BadParamErr;
1867 }
1868
1869 if (s >= 0)
1870 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1871 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
1872 else
1873 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1874 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
1875
1876 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1877 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1878 if (s < 0) return(mStatus_Invalid);
1879
1880 // switch to background traffic class for this message if requested
1881 if (useBackgroundTrafficClass)
1882 setTrafficClass(s, useBackgroundTrafficClass);
1883
1884 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
1885
1886 // set traffic class back to default value
1887 if (useBackgroundTrafficClass)
1888 setTrafficClass(s, mDNSfalse);
1889
1890 if (err < 0)
1891 {
1892 static int MessageCount = 0;
1893 LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1894 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
1895 if (!mDNSAddressIsAllDNSLinkGroup(dst))
1896 if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
1897 // Don't report EHOSTUNREACH in the first three minutes after boot
1898 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1899 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1900 if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
1901 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1902 if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr);
1903 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
1904 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1905 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
1906 else
1907 {
1908 MessageCount++;
1909 if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs
1910 LogMsg("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
1911 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
1912 else // If logging is enabled, remove the cap and log aggressively
1913 LogInfo("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
1914 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
1915 }
1916
1917 result = mStatus_UnknownErr;
1918 }
1919
1920 #ifdef IP_BOUND_IF
1921 if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
1922 {
1923 static const mDNSu32 ifindex = 0;
1924 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
1925 }
1926 #endif
1927
1928 return(result);
1929 }
1930
1931 mDNSexport ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
1932 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
1933 {
1934 static unsigned int numLogMessages = 0;
1935 struct iovec databuffers = { (char *)buffer, max };
1936 struct msghdr msg;
1937 ssize_t n;
1938 struct cmsghdr *cmPtr;
1939 char ancillary[1024];
1940
1941 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1942
1943 // Set up the message
1944 msg.msg_name = (caddr_t)from;
1945 msg.msg_namelen = *fromlen;
1946 msg.msg_iov = &databuffers;
1947 msg.msg_iovlen = 1;
1948 msg.msg_control = (caddr_t)&ancillary;
1949 msg.msg_controllen = sizeof(ancillary);
1950 msg.msg_flags = 0;
1951
1952 // Receive the data
1953 n = recvmsg(s, &msg, 0);
1954 if (n<0)
1955 {
1956 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
1957 return(-1);
1958 }
1959 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
1960 {
1961 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d",
1962 s, n, msg.msg_controllen, sizeof(struct cmsghdr), errno);
1963 return(-1);
1964 }
1965 if (msg.msg_flags & MSG_CTRUNC)
1966 {
1967 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
1968 return(-1);
1969 }
1970
1971 *fromlen = msg.msg_namelen;
1972
1973 // Parse each option out of the ancillary data.
1974 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
1975 {
1976 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1977 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
1978 {
1979 dstaddr->type = mDNSAddrType_IPv4;
1980 dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
1981 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
1982 }
1983 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
1984 {
1985 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
1986 if (sdl->sdl_nlen < IF_NAMESIZE)
1987 {
1988 mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
1989 ifname[sdl->sdl_nlen] = 0;
1990 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1991 }
1992 }
1993 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
1994 *ttl = *(u_char*)CMSG_DATA(cmPtr);
1995 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
1996 {
1997 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
1998 dstaddr->type = mDNSAddrType_IPv6;
1999 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
2000 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
2001 }
2002 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
2003 *ttl = *(int*)CMSG_DATA(cmPtr);
2004 }
2005
2006 return(n);
2007 }
2008
2009 mDNSlocal mDNSInterfaceID FindMyInterface(mDNS *const m, const mDNSAddr *addr)
2010 {
2011 NetworkInterfaceInfo *intf;
2012
2013 if (addr->type == mDNSAddrType_IPv4)
2014 {
2015 for (intf = m->HostInterfaces; intf; intf = intf->next)
2016 {
2017 if (intf->ip.type == addr->type && intf->McastTxRx)
2018 {
2019 if ((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) == 0)
2020 {
2021 return(intf->InterfaceID);
2022 }
2023 }
2024 }
2025 }
2026
2027 if (addr->type == mDNSAddrType_IPv6)
2028 {
2029 for (intf = m->HostInterfaces; intf; intf = intf->next)
2030 {
2031 if (intf->ip.type == addr->type && intf->McastTxRx)
2032 {
2033 if (((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) == 0) &&
2034 ((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) == 0) &&
2035 ((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) == 0) &&
2036 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) == 0)))
2037 {
2038 return(intf->InterfaceID);
2039 }
2040 }
2041 }
2042 }
2043 return(mDNSInterface_Any);
2044 }
2045
2046 mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src)
2047 {
2048 // We should have a DNSMessage header followed by the question and an answer
2049 // which also includes a CNAME (that's when this function is called). To keep it
2050 // simple, we expect at least the size of DNSMessage header(12) and size of "A"
2051 // record (14 bytes).
2052 char buffer[26];
2053 int ret;
2054
2055 (void) m;
2056
2057 if (!src)
2058 return mDNSfalse;
2059
2060 ret = recv(src->ss.sktv4, buffer, sizeof(buffer), MSG_PEEK);
2061 if (ret > 0)
2062 return mDNStrue;
2063 else
2064 return mDNSfalse;
2065 }
2066
2067 mDNSexport void myKQSocketCallBack(int s1, short filter, void *context)
2068 {
2069 KQSocketSet *const ss = (KQSocketSet *)context;
2070 mDNS *const m = ss->m;
2071 int err = 0, count = 0, closed = 0;
2072
2073 if (filter != EVFILT_READ)
2074 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
2075
2076 if (s1 != ss->sktv4 && s1 != ss->sktv6)
2077 {
2078 LogMsg("myKQSocketCallBack: native socket %d", s1);
2079 LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6);
2080 }
2081
2082 while (!closed)
2083 {
2084 mDNSAddr senderAddr, destAddr;
2085 mDNSIPPort senderPort;
2086 struct sockaddr_storage from;
2087 size_t fromlen = sizeof(from);
2088 char packetifname[IF_NAMESIZE] = "";
2089 mDNSu8 ttl;
2090 err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
2091 if (err < 0) break;
2092
2093 if ((destAddr.type == mDNSAddrType_IPv4 && (destAddr.ip.v4.b[0] & 0xF0) == 0xE0) ||
2094 (destAddr.type == mDNSAddrType_IPv6 && (destAddr.ip.v6.b[0] == 0xFF))) m->p->num_mcasts++;
2095
2096 count++;
2097 if (from.ss_family == AF_INET)
2098 {
2099 struct sockaddr_in *s = (struct sockaddr_in*)&from;
2100 senderAddr.type = mDNSAddrType_IPv4;
2101 senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
2102 senderPort.NotAnInteger = s->sin_port;
2103 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
2104 }
2105 else if (from.ss_family == AF_INET6)
2106 {
2107 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
2108 senderAddr.type = mDNSAddrType_IPv6;
2109 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
2110 senderPort.NotAnInteger = sin6->sin6_port;
2111 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
2112 }
2113 else
2114 {
2115 LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
2116 return;
2117 }
2118
2119 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
2120 mDNSInterfaceID InterfaceID = mDNSNULL;
2121 NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
2122 while (intf)
2123 {
2124 if (intf->Exists && !strcmp(intf->ifinfo.ifname, packetifname))
2125 break;
2126 intf = intf->next;
2127 }
2128
2129 // When going to sleep we deregister all our interfaces, but if the machine
2130 // takes a few seconds to sleep we may continue to receive multicasts
2131 // during that time, which would confuse mDNSCoreReceive, because as far
2132 // as it's concerned, we should have no active interfaces any more.
2133 // Hence we ignore multicasts for which we can find no matching InterfaceID.
2134 if (intf)
2135 InterfaceID = intf->ifinfo.InterfaceID;
2136 else if (mDNSAddrIsDNSMulticast(&destAddr))
2137 continue;
2138
2139 if (!InterfaceID)
2140 {
2141 InterfaceID = FindMyInterface(m, &destAddr);
2142 }
2143
2144 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
2145 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
2146
2147 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
2148 // loop when that happens, or we may try to read from an invalid FD. We do this by
2149 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
2150 // if it closes the socketset.
2151 ss->closeFlag = &closed;
2152
2153 if (ss->proxy)
2154 {
2155 m->p->UDPProxyCallback(m, &m->p->UDPProxy, (unsigned char *)&m->imsg, (unsigned char*)&m->imsg + err, &senderAddr,
2156 senderPort, &destAddr, ss->port, InterfaceID, NULL);
2157 }
2158 else
2159 {
2160 mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
2161 }
2162
2163 // if we didn't close, we can safely dereference the socketset, and should to
2164 // reset the closeFlag, since it points to something on the stack
2165 if (!closed) ss->closeFlag = mDNSNULL;
2166 }
2167
2168 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
2169 {
2170 // Something is busted here.
2171 // kqueue says there is a packet, but myrecvfrom says there is not.
2172 // Try calling select() to get another opinion.
2173 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
2174 // All of this is racy, as data may have arrived after the call to select()
2175 static unsigned int numLogMessages = 0;
2176 int save_errno = errno;
2177 int so_error = -1;
2178 int so_nread = -1;
2179 int fionread = -1;
2180 socklen_t solen = sizeof(int);
2181 fd_set readfds;
2182 struct timeval timeout;
2183 int selectresult;
2184 FD_ZERO(&readfds);
2185 FD_SET(s1, &readfds);
2186 timeout.tv_sec = 0;
2187 timeout.tv_usec = 0;
2188 selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
2189 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
2190 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
2191 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
2192 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
2193 if (ioctl(s1, FIONREAD, &fionread) == -1)
2194 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
2195 if (numLogMessages++ < 100)
2196 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
2197 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
2198 if (numLogMessages > 5)
2199 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
2200 "Congratulations, you've reproduced an elusive bug.\r"
2201 "Please contact the current assignee of <rdar://problem/3375328>.\r"
2202 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2203 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2204
2205 sleep(1); // After logging this error, rate limit so we don't flood syslog
2206 }
2207 }
2208
2209 mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
2210 {
2211 mDNSBool c = !sock->connected;
2212 sock->connected = mDNStrue;
2213 sock->callback(sock, sock->context, c, sock->err);
2214 // Note: the callback may call CloseConnection here, which frees the context structure!
2215 }
2216
2217 #ifndef NO_SECURITYFRAMEWORK
2218
2219 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
2220 {
2221 int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
2222 if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
2223 if (ret >= 0) { *dataLength = ret; return(noErr); }
2224 *dataLength = 0;
2225 if (errno == EAGAIN ) return(errSSLWouldBlock);
2226 if (errno == ENOENT ) return(errSSLClosedGraceful);
2227 if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
2228 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
2229 return(errSSLClosedAbort);
2230 }
2231
2232 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
2233 {
2234 int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
2235 if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
2236 if (ret > 0) { *dataLength = ret; return(noErr); }
2237 *dataLength = 0;
2238 if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
2239 if ( errno == EAGAIN ) return(errSSLWouldBlock);
2240 if ( errno == ECONNRESET) return(errSSLClosedAbort);
2241 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
2242 return(errSSLClosedAbort);
2243 }
2244
2245 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConnectionType ctype)
2246 {
2247 char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
2248
2249 sock->tlsContext = SSLCreateContext(kCFAllocatorDefault, pside, ctype);
2250 if (!sock->tlsContext)
2251 {
2252 LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
2253 return(mStatus_UnknownErr);
2254 }
2255
2256 mStatus err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
2257 if (err)
2258 {
2259 LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err);
2260 goto fail;
2261 }
2262
2263 err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
2264 if (err)
2265 {
2266 LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err);
2267 goto fail;
2268 }
2269
2270 // Instead of listing all the acceptable ciphers, we just disable the bad ciphers. It does not disable
2271 // all the bad ciphers like RC4_MD5, but it assumes that the servers don't offer them.
2272 err = SSLSetAllowAnonymousCiphers(sock->tlsContext, 0);
2273 if (err)
2274 {
2275 LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err);
2276 goto fail;
2277 }
2278
2279 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
2280 // (error not in OSStatus space) is okay.
2281 if (!sock->hostname.c[0])
2282 {
2283 LogMsg("ERROR: tlsSetupSock: hostname NULL");
2284 err = -1;
2285 goto fail;
2286 }
2287
2288 ConvertDomainNameToCString(&sock->hostname, domname_cstr);
2289 err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
2290 if (err)
2291 {
2292 LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err);
2293 goto fail;
2294 }
2295
2296 return(err);
2297
2298 fail:
2299 if (sock->tlsContext)
2300 CFRelease(sock->tlsContext);
2301 return(err);
2302 }
2303
2304 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2305 mDNSlocal void doSSLHandshake(TCPSocket *sock)
2306 {
2307 mStatus err = SSLHandshake(sock->tlsContext);
2308
2309 //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
2310 //defined, KQueueLock is a noop. Hence we need to serialize here
2311 //
2312 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
2313 //We need the rest of the logic also. Otherwise, we can enable the READ
2314 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
2315 //ConnFailed which means we are going to free the tcpInfo. While it
2316 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
2317 //and potentially call doTCPCallback with error which can close the fd and free the
2318 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
2319 //is already freed.
2320
2321 dispatch_async(dispatch_get_main_queue(), ^{
2322
2323 LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
2324
2325 if (sock->handshake == handshake_to_be_closed)
2326 {
2327 LogInfo("SSLHandshake completed after close");
2328 mDNSPlatformTCPCloseConnection(sock);
2329 }
2330 else
2331 {
2332 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
2333 else LogMsg("doSSLHandshake: sock->fd is -1");
2334
2335 if (err == errSSLWouldBlock)
2336 sock->handshake = handshake_required;
2337 else
2338 {
2339 if (err)
2340 {
2341 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
2342 CFRelease(sock->tlsContext);
2343 sock->tlsContext = NULL;
2344 }
2345
2346 sock->err = err ? mStatus_ConnFailed : 0;
2347 sock->handshake = handshake_completed;
2348
2349 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
2350 doTcpSocketCallback(sock);
2351 }
2352 }
2353
2354 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
2355 return;
2356 });
2357 }
2358 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2359 mDNSlocal void *doSSLHandshake(TCPSocket *sock)
2360 {
2361 // Warning: Touching sock without the kqueue lock!
2362 // We're protected because sock->handshake == handshake_in_progress
2363 mDNS * const m = sock->m; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
2364 mStatus err = SSLHandshake(sock->tlsContext);
2365
2366 KQueueLock(m);
2367 debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
2368
2369 if (sock->handshake == handshake_to_be_closed)
2370 {
2371 LogInfo("SSLHandshake completed after close");
2372 mDNSPlatformTCPCloseConnection(sock);
2373 }
2374 else
2375 {
2376 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
2377 else LogMsg("doSSLHandshake: sock->fd is -1");
2378
2379 if (err == errSSLWouldBlock)
2380 sock->handshake = handshake_required;
2381 else
2382 {
2383 if (err)
2384 {
2385 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
2386 CFRelease(sock->tlsContext);
2387 sock->tlsContext = NULL;
2388 }
2389
2390 sock->err = err ? mStatus_ConnFailed : 0;
2391 sock->handshake = handshake_completed;
2392
2393 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
2394 doTcpSocketCallback(sock);
2395 }
2396 }
2397
2398 debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
2399 KQueueUnlock(m, "doSSLHandshake");
2400 return NULL;
2401 }
2402 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2403
2404 mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
2405 {
2406 debugf("spawnSSLHandshake %p: entry", sock);
2407
2408 if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
2409 sock->handshake = handshake_in_progress;
2410 KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
2411
2412 // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
2413 // to limit the number of threads used for SSLHandshake
2414 dispatch_async(SSLqueue, ^{doSSLHandshake(sock);});
2415
2416 debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
2417 }
2418
2419 #endif /* NO_SECURITYFRAMEWORK */
2420
2421 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
2422 {
2423 TCPSocket *sock = context;
2424 sock->err = mStatus_NoError;
2425
2426 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
2427 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
2428 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
2429 if (filter == EVFILT_WRITE)
2430 KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
2431
2432 if (sock->flags & kTCPSocketFlags_UseTLS)
2433 {
2434 #ifndef NO_SECURITYFRAMEWORK
2435 if (!sock->setup)
2436 {
2437 sock->setup = mDNStrue;
2438 sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
2439 if (sock->err)
2440 {
2441 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
2442 return;
2443 }
2444 }
2445 if (sock->handshake == handshake_required)
2446 {
2447 spawnSSLHandshake(sock);
2448 return;
2449 }
2450 else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
2451 {
2452 return;
2453 }
2454 else if (sock->handshake != handshake_completed)
2455 {
2456 if (!sock->err)
2457 sock->err = mStatus_UnknownErr;
2458 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
2459 }
2460 #else /* NO_SECURITYFRAMEWORK */
2461 sock->err = mStatus_UnsupportedErr;
2462 #endif /* NO_SECURITYFRAMEWORK */
2463 }
2464
2465 doTcpSocketCallback(sock);
2466 }
2467
2468 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2469 mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef)
2470 {
2471 dispatch_queue_t queue = dispatch_get_main_queue();
2472 dispatch_source_t source;
2473 if (flags == EV_DELETE)
2474 {
2475 if (filter == EVFILT_READ)
2476 {
2477 dispatch_source_cancel(entryRef->readSource);
2478 dispatch_release(entryRef->readSource);
2479 entryRef->readSource = mDNSNULL;
2480 debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource);
2481 }
2482 else if (filter == EVFILT_WRITE)
2483 {
2484 dispatch_source_cancel(entryRef->writeSource);
2485 dispatch_release(entryRef->writeSource);
2486 entryRef->writeSource = mDNSNULL;
2487 debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource);
2488 }
2489 else
2490 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
2491 return 0;
2492 }
2493 if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
2494
2495 if (filter == EVFILT_READ)
2496 {
2497 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
2498 }
2499 else if (filter == EVFILT_WRITE)
2500 {
2501 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
2502 }
2503 else
2504 {
2505 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
2506 return -1;
2507 }
2508 if (!source) return -1;
2509 dispatch_source_set_event_handler(source, ^{
2510
2511 mDNSs32 stime = mDNSPlatformRawTime();
2512 entryRef->KQcallback(fd, filter, entryRef->KQcontext);
2513 mDNSs32 etime = mDNSPlatformRawTime();
2514 if (etime - stime >= WatchDogReportingThreshold)
2515 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime);
2516
2517 // Trigger the event delivery to the application. Even though we trigger the
2518 // event completion after handling every event source, these all will hopefully
2519 // get merged
2520 TriggerEventCompletion();
2521
2522 });
2523 dispatch_source_set_cancel_handler(source, ^{
2524 if (entryRef->fdClosed)
2525 {
2526 //LogMsg("CancelHandler: closing fd %d", fd);
2527 close(fd);
2528 }
2529 });
2530 dispatch_resume(source);
2531 if (filter == EVFILT_READ)
2532 entryRef->readSource = source;
2533 else
2534 entryRef->writeSource = source;
2535
2536 return 0;
2537 }
2538
2539 mDNSexport void KQueueLock(mDNS *const m)
2540 {
2541 (void)m; //unused
2542 }
2543 mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
2544 {
2545 (void)m; //unused
2546 (void)task; //unused
2547 }
2548 #else
2549 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
2550 {
2551 struct kevent new_event;
2552 EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
2553 return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
2554 }
2555
2556 mDNSexport void KQueueLock(mDNS *const m)
2557 {
2558 pthread_mutex_lock(&m->p->BigMutex);
2559 m->p->BigMutexStartTime = mDNSPlatformRawTime();
2560 }
2561
2562 mDNSexport void KQueueUnlock(mDNS *const m, const char* task)
2563 {
2564 mDNSs32 end = mDNSPlatformRawTime();
2565 (void)task;
2566 if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
2567 LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
2568
2569 pthread_mutex_unlock(&m->p->BigMutex);
2570
2571 char wake = 1;
2572 if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
2573 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
2574 }
2575 #endif
2576
2577 mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
2578 {
2579 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2580 (void) fd; //unused
2581 if (kq->readSource)
2582 {
2583 dispatch_source_cancel(kq->readSource);
2584 kq->readSource = mDNSNULL;
2585 }
2586 if (kq->writeSource)
2587 {
2588 dispatch_source_cancel(kq->writeSource);
2589 kq->writeSource = mDNSNULL;
2590 }
2591 // Close happens in the cancellation handler
2592 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
2593 kq->fdClosed = mDNStrue;
2594 #else
2595 (void)kq; //unused
2596 close(fd);
2597 #endif
2598 }
2599
2600 mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
2601 {
2602 KQSocketSet *cp = &sock->ss;
2603 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
2604 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
2605 const int on = 1; // "on" for setsockopt
2606 mStatus err;
2607
2608 int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
2609 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
2610
2611 // for TCP sockets, the traffic class is set once and not changed
2612 setTrafficClass(skt, useBackgroundTrafficClass);
2613
2614 if (sa_family == AF_INET)
2615 {
2616 // Bind it
2617 struct sockaddr_in addr;
2618 mDNSPlatformMemZero(&addr, sizeof(addr));
2619 addr.sin_family = AF_INET;
2620 addr.sin_port = port->NotAnInteger;
2621 err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
2622 if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); return err; }
2623
2624 // Receive interface identifiers
2625 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
2626 if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); return err; }
2627
2628 mDNSPlatformMemZero(&addr, sizeof(addr));
2629 socklen_t len = sizeof(addr);
2630 err = getsockname(skt, (struct sockaddr*) &addr, &len);
2631 if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); return err; }
2632
2633 port->NotAnInteger = addr.sin_port;
2634 }
2635 else
2636 {
2637 // Bind it
2638 struct sockaddr_in6 addr6;
2639 mDNSPlatformMemZero(&addr6, sizeof(addr6));
2640 addr6.sin6_family = AF_INET6;
2641 addr6.sin6_port = port->NotAnInteger;
2642 err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
2643 if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); return err; }
2644
2645 // We want to receive destination addresses and receive interface identifiers
2646 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
2647 if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); return err; }
2648
2649 mDNSPlatformMemZero(&addr6, sizeof(addr6));
2650 socklen_t len = sizeof(addr6);
2651 err = getsockname(skt, (struct sockaddr *) &addr6, &len);
2652 if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); return err; }
2653
2654 port->NotAnInteger = addr6.sin6_port;
2655
2656 }
2657 *s = skt;
2658 k->KQcallback = tcpKQSocketCallback;
2659 k->KQcontext = sock;
2660 k->KQtask = "mDNSPlatformTCPSocket";
2661 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2662 k->readSource = mDNSNULL;
2663 k->writeSource = mDNSNULL;
2664 k->fdClosed = mDNSfalse;
2665 #endif
2666 return mStatus_NoError;
2667 }
2668
2669 mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
2670 {
2671 mStatus err;
2672 (void) m;
2673
2674 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
2675 if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
2676
2677 mDNSPlatformMemZero(sock, sizeof(TCPSocket));
2678
2679 sock->ss.m = m;
2680 sock->ss.sktv4 = -1;
2681 sock->ss.sktv6 = -1;
2682 err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
2683
2684 if (!err)
2685 {
2686 err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass);
2687 if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
2688 }
2689 if (err)
2690 {
2691 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
2692 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
2693 return(mDNSNULL);
2694 }
2695 // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
2696 sock->fd = sock->ss.sktv4;
2697 sock->callback = mDNSNULL;
2698 sock->flags = flags;
2699 sock->context = mDNSNULL;
2700 sock->setup = mDNSfalse;
2701 sock->connected = mDNSfalse;
2702 sock->handshake = handshake_required;
2703 sock->m = m;
2704 sock->err = mStatus_NoError;
2705
2706 return sock;
2707 }
2708
2709 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
2710 {
2711 KQSocketSet *cp = &sock->ss;
2712 int *s = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
2713 KQueueEntry *k = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
2714 mStatus err = mStatus_NoError;
2715 struct sockaddr_storage ss;
2716
2717 sock->callback = callback;
2718 sock->context = context;
2719 sock->setup = mDNSfalse;
2720 sock->connected = mDNSfalse;
2721 sock->handshake = handshake_required;
2722 sock->err = mStatus_NoError;
2723
2724 if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
2725
2726 if (dst->type == mDNSAddrType_IPv4)
2727 {
2728 struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
2729 mDNSPlatformMemZero(saddr, sizeof(*saddr));
2730 saddr->sin_family = AF_INET;
2731 saddr->sin_port = dstport.NotAnInteger;
2732 saddr->sin_len = sizeof(*saddr);
2733 saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
2734 }
2735 else
2736 {
2737 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss;
2738 mDNSPlatformMemZero(saddr6, sizeof(*saddr6));
2739 saddr6->sin6_family = AF_INET6;
2740 saddr6->sin6_port = dstport.NotAnInteger;
2741 saddr6->sin6_len = sizeof(*saddr6);
2742 saddr6->sin6_addr = *(struct in6_addr *)&dst->ip.v6;
2743 }
2744
2745 // Watch for connect complete (write is ready)
2746 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
2747 if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
2748 {
2749 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
2750 return errno;
2751 }
2752
2753 // Watch for incoming data
2754 if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
2755 {
2756 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
2757 return errno;
2758 }
2759
2760 if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
2761 {
2762 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
2763 return mStatus_UnknownErr;
2764 }
2765
2766 // We bind to the interface and all subsequent packets including the SYN will be sent out
2767 // on this interface
2768 //
2769 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
2770 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
2771 if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
2772 {
2773 NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
2774 if (dst->type == mDNSAddrType_IPv4)
2775 {
2776 #ifdef IP_BOUND_IF
2777 if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
2778 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
2779 #else
2780 (void)InterfaceID; // Unused
2781 (void)info; // Unused
2782 #endif
2783 }
2784 else
2785 {
2786 #ifdef IPV6_BOUND_IF
2787 if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
2788 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
2789 #else
2790 (void)InterfaceID; // Unused
2791 (void)info; // Unused
2792 #endif
2793 }
2794 }
2795
2796 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
2797 // from which we can infer the destination address family. Hence we need to remember that here.
2798 // Instead of remembering the address family, we remember the right fd.
2799 sock->fd = *s;
2800 sock->kqEntry = k;
2801 // initiate connection wth peer
2802 if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
2803 {
2804 if (errno == EINPROGRESS) return mStatus_ConnPending;
2805 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
2806 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
2807 else
2808 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
2809 return mStatus_ConnFailed;
2810 }
2811
2812 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
2813 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
2814 return err;
2815 }
2816
2817 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
2818 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
2819 {
2820 mStatus err = mStatus_NoError;
2821
2822 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
2823 if (!sock) return(mDNSNULL);
2824
2825 mDNSPlatformMemZero(sock, sizeof(*sock));
2826 sock->fd = fd;
2827 sock->flags = flags;
2828
2829 if (flags & kTCPSocketFlags_UseTLS)
2830 {
2831 #ifndef NO_SECURITYFRAMEWORK
2832 if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
2833
2834 err = tlsSetupSock(sock, kSSLServerSide, kSSLStreamType);
2835 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
2836
2837 err = SSLSetCertificate(sock->tlsContext, ServerCerts);
2838 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
2839 #else
2840 err = mStatus_UnsupportedErr;
2841 #endif /* NO_SECURITYFRAMEWORK */
2842 }
2843 #ifndef NO_SECURITYFRAMEWORK
2844 exit:
2845 #endif
2846
2847 if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
2848 return(sock);
2849 }
2850
2851 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
2852 {
2853 mDNSu16 port;
2854
2855 port = -1;
2856 if (sock)
2857 {
2858 port = sock->ss.port.NotAnInteger;
2859 }
2860 return port;
2861 }
2862
2863 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
2864 {
2865 if (ss->sktv4 != -1)
2866 {
2867 mDNSPlatformCloseFD(&ss->kqsv4, ss->sktv4);
2868 ss->sktv4 = -1;
2869 }
2870 if (ss->sktv6 != -1)
2871 {
2872 mDNSPlatformCloseFD(&ss->kqsv6, ss->sktv6);
2873 ss->sktv6 = -1;
2874 }
2875 if (ss->closeFlag) *ss->closeFlag = 1;
2876 }
2877
2878 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
2879 {
2880 if (sock)
2881 {
2882 #ifndef NO_SECURITYFRAMEWORK
2883 if (sock->tlsContext)
2884 {
2885 if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
2886 {
2887 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
2888 // When we come back from SSLHandshake, we will notice that a close was here and
2889 // call this function again which will do the cleanup then.
2890 sock->handshake = handshake_to_be_closed;
2891 return;
2892 }
2893
2894 SSLClose(sock->tlsContext);
2895 CFRelease(sock->tlsContext);
2896 sock->tlsContext = NULL;
2897 }
2898 #endif /* NO_SECURITYFRAMEWORK */
2899 if (sock->ss.sktv4 != -1)
2900 shutdown(sock->ss.sktv4, 2);
2901 if (sock->ss.sktv6 != -1)
2902 shutdown(sock->ss.sktv6, 2);
2903 CloseSocketSet(&sock->ss);
2904 sock->fd = -1;
2905
2906 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
2907 }
2908 }
2909
2910 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
2911 {
2912 ssize_t nread = 0;
2913 *closed = mDNSfalse;
2914
2915 if (sock->flags & kTCPSocketFlags_UseTLS)
2916 {
2917 #ifndef NO_SECURITYFRAMEWORK
2918 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
2919 else if (sock->handshake == handshake_in_progress) return 0;
2920 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
2921
2922 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
2923 mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t *)&nread);
2924 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
2925 if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
2926 else if (err && err != errSSLWouldBlock)
2927 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
2928 #else
2929 nread = -1;
2930 *closed = mDNStrue;
2931 #endif /* NO_SECURITYFRAMEWORK */
2932 }
2933 else
2934 {
2935 static int CLOSEDcount = 0;
2936 static int EAGAINcount = 0;
2937 nread = recv(sock->fd, buf, buflen, 0);
2938
2939 if (nread > 0)
2940 {
2941 CLOSEDcount = 0;
2942 EAGAINcount = 0;
2943 } // On success, clear our error counters
2944 else if (nread == 0)
2945 {
2946 *closed = mDNStrue;
2947 if ((++CLOSEDcount % 1000) == 0)
2948 {
2949 LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount);
2950 assert(CLOSEDcount < 1000);
2951 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
2952 // crash mDNSResponder using assert() and restart fresh. See advantages below:
2953 // 1.Better User Experience
2954 // 2.CrashLogs frequency can be monitored
2955 // 3.StackTrace can be used for more info
2956 }
2957 }
2958 // else nread is negative -- see what kind of error we got
2959 else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
2960 else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
2961 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
2962 {
2963 nread = 0;
2964 if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
2965 }
2966 }
2967
2968 return nread;
2969 }
2970
2971 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
2972 {
2973 int nsent;
2974
2975 if (sock->flags & kTCPSocketFlags_UseTLS)
2976 {
2977 #ifndef NO_SECURITYFRAMEWORK
2978 size_t processed;
2979 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
2980 if (sock->handshake == handshake_in_progress) return 0;
2981 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
2982
2983 mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
2984
2985 if (!err) nsent = (int) processed;
2986 else if (err == errSSLWouldBlock) nsent = 0;
2987 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
2988 #else
2989 nsent = -1;
2990 #endif /* NO_SECURITYFRAMEWORK */
2991 }
2992 else
2993 {
2994 nsent = send(sock->fd, msg, len, 0);
2995 if (nsent < 0)
2996 {
2997 if (errno == EAGAIN) nsent = 0;
2998 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
2999 }
3000 }
3001
3002 return nsent;
3003 }
3004
3005 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
3006 {
3007 return sock->fd;
3008 }
3009
3010 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
3011 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
3012 mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
3013 {
3014 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
3015 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
3016 const int on = 1;
3017 const int twofivefive = 255;
3018 mStatus err = mStatus_NoError;
3019 char *errstr = mDNSNULL;
3020 const int mtu = 0;
3021
3022 cp->closeFlag = mDNSNULL;
3023
3024 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
3025 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
3026
3027 // set default traffic class
3028 setTrafficClass(skt, mDNSfalse);
3029
3030 #ifdef SO_RECV_ANYIF
3031 // Enable inbound packets on IFEF_AWDL interface.
3032 // Only done for multicast sockets, since we don't expect unicast socket operations
3033 // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
3034 if (mDNSSameIPPort(port, MulticastDNSPort))
3035 {
3036 err = setsockopt(skt, SOL_SOCKET, SO_RECV_ANYIF, &on, sizeof(on));
3037 if (err < 0) { errstr = "setsockopt - SO_RECV_ANYIF"; goto fail; }
3038 }
3039 #endif // SO_RECV_ANYIF
3040
3041 // ... with a shared UDP port, if it's for multicast receiving
3042 if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort))
3043 {
3044 err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
3045 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
3046 }
3047
3048 if (sa_family == AF_INET)
3049 {
3050 // We want to receive destination addresses
3051 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
3052 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
3053
3054 // We want to receive interface identifiers
3055 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
3056 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
3057
3058 // We want to receive packet TTL value so we can check it
3059 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
3060 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
3061
3062 // Send unicast packets with TTL 255
3063 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
3064 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
3065
3066 // And multicast packets with TTL 255 too
3067 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
3068 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
3069
3070 // And start listening for packets
3071 struct sockaddr_in listening_sockaddr;
3072 listening_sockaddr.sin_family = AF_INET;
3073 listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
3074 listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0;
3075 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
3076 if (err) { errstr = "bind"; goto fail; }
3077 if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
3078 }
3079 else if (sa_family == AF_INET6)
3080 {
3081 // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
3082 if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort;return mStatus_NoError; }
3083
3084 // We want to receive destination addresses and receive interface identifiers
3085 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
3086 if (err < 0) { errstr = "setsockopt - IPV6_RECVPKTINFO"; goto fail; }
3087
3088 // We want to receive packet hop count value so we can check it
3089 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
3090 if (err < 0) { errstr = "setsockopt - IPV6_RECVHOPLIMIT"; goto fail; }
3091
3092 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
3093 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
3094 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
3095 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
3096
3097 // Send unicast packets with TTL 255
3098 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
3099 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
3100
3101 // And multicast packets with TTL 255 too
3102 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
3103 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
3104
3105 // Want to receive our own packets
3106 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
3107 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
3108
3109 // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
3110 err = setsockopt(skt, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &mtu, sizeof(mtu));
3111 if (err < 0) // Since it is an optimization if we fail just log the err, no need to close the skt
3112 LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
3113 skt, err, errno, strerror(errno));
3114
3115 // And start listening for packets
3116 struct sockaddr_in6 listening_sockaddr6;
3117 mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
3118 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
3119 listening_sockaddr6.sin6_family = AF_INET6;
3120 listening_sockaddr6.sin6_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
3121 listening_sockaddr6.sin6_flowinfo = 0;
3122 listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
3123 listening_sockaddr6.sin6_scope_id = 0;
3124 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
3125 if (err) { errstr = "bind"; goto fail; }
3126 if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
3127 }
3128
3129 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
3130 fcntl(skt, F_SETFD, 1); // set close-on-exec
3131 *s = skt;
3132 k->KQcallback = myKQSocketCallBack;
3133 k->KQcontext = cp;
3134 k->KQtask = "UDP packet reception";
3135 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3136 k->readSource = mDNSNULL;
3137 k->writeSource = mDNSNULL;
3138 k->fdClosed = mDNSfalse;
3139 #endif
3140 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
3141
3142 return(err);
3143
3144 fail:
3145 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
3146 if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
3147 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
3148
3149 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
3150 if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
3151 {
3152 err = EADDRINUSE;
3153 if (mDNSSameIPPort(port, MulticastDNSPort))
3154 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
3155 "Congratulations, you've reproduced an elusive bug.\r"
3156 "Please contact the current assignee of <rdar://problem/3814904>.\r"
3157 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
3158 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
3159 }
3160
3161 mDNSPlatformCloseFD(k, skt);
3162 return(err);
3163 }
3164
3165 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
3166 {
3167 mStatus err;
3168 mDNSIPPort port = requestedport;
3169 mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
3170 int i = 10000; // Try at most 10000 times to get a unique random port
3171 UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
3172 if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
3173 mDNSPlatformMemZero(p, sizeof(UDPSocket));
3174 p->ss.port = zeroIPPort;
3175 p->ss.m = m;
3176 p->ss.sktv4 = -1;
3177 p->ss.sktv6 = -1;
3178 p->ss.proxy = mDNSfalse;
3179
3180 do
3181 {
3182 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
3183 if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
3184 err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
3185 if (!err)
3186 {
3187 err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
3188 if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
3189 }
3190 i--;
3191 } while (err == EADDRINUSE && randomizePort && i);
3192
3193 if (err)
3194 {
3195 // In customer builds we don't want to log failures with port 5351, because this is a known issue
3196 // of failing to bind to this port when Internet Sharing has already bound to it
3197 // We also don't want to log about port 5350, due to a known bug when some other
3198 // process is bound to it.
3199 if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
3200 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
3201 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
3202 freeL("UDPSocket", p);
3203 return(mDNSNULL);
3204 }
3205 return(p);
3206 }
3207
3208 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
3209 {
3210 CloseSocketSet(&sock->ss);
3211 freeL("UDPSocket", sock);
3212 }
3213
3214 #if COMPILER_LIKES_PRAGMA_MARK
3215 #pragma mark -
3216 #pragma mark - BPF Raw packet sending/receiving
3217 #endif
3218
3219 #if APPLE_OSX_mDNSResponder
3220
3221 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
3222 {
3223 if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
3224 NetworkInterfaceInfoOSX *info;
3225
3226 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
3227 if (info == NULL)
3228 {
3229 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
3230 return;
3231 }
3232 if (info->BPF_fd < 0)
3233 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
3234 else
3235 {
3236 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
3237 if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
3238 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
3239 }
3240 }
3241
3242 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
3243 {
3244 if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
3245 NetworkInterfaceInfoOSX *info;
3246 info = IfindexToInterfaceInfoOSX(m, InterfaceID);
3247 if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; }
3248 // Manually inject an entry into our local ARP cache.
3249 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
3250 if (!mDNS_AddressIsLocalSubnet(m, InterfaceID, tpa, mDNSNULL))
3251 LogSPS("Don't need address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
3252 else
3253 {
3254 int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b);
3255 if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
3256 else LogSPS("Set local address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
3257 }
3258 }
3259
3260 mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
3261 {
3262 LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
3263 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3264 // close will happen in the cancel handler
3265 dispatch_source_cancel(i->BPF_source);
3266 #else
3267
3268 // Note: MUST NOT close() the underlying native BSD sockets.
3269 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
3270 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
3271 CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
3272 CFRelease(i->BPF_rls);
3273 CFSocketInvalidate(i->BPF_cfs);
3274 CFRelease(i->BPF_cfs);
3275 #endif
3276 i->BPF_fd = -1;
3277 if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
3278 }
3279
3280 mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
3281 {
3282 KQueueLock(info->m);
3283
3284 // 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
3285 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
3286 if (info->BPF_fd < 0) goto exit;
3287
3288 ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
3289 const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
3290 const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
3291 debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
3292
3293 if (n<0)
3294 {
3295 /* <rdar://problem/10287386>
3296 * sometimes there can be a race condition btw when the bpf socket
3297 * gets data and the callback get scheduled and when we call BIOCSETF (which
3298 * clears the socket). this can cause the read to hang for a really long time
3299 * and effectively prevent us from responding to requests for long periods of time.
3300 * to prevent this make the socket non blocking and just bail if we dont get anything
3301 */
3302 if (errno == EAGAIN)
3303 {
3304 LogMsg("bpf_callback got EAGAIN bailing");
3305 goto exit;
3306 }
3307 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
3308 CloseBPF(info);
3309 goto exit;
3310 }
3311
3312 while (ptr < end)
3313 {
3314 const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr;
3315 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
3316 info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen,
3317 ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
3318 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
3319 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
3320 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
3321 mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
3322 ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
3323 }
3324 exit:
3325 KQueueUnlock(info->m, "bpf_callback");
3326 }
3327 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3328 mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
3329 {
3330 bpf_callback_common(info);
3331 }
3332 #else
3333 mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
3334 {
3335 (void)cfs;
3336 (void)CallBackType;
3337 (void)address;
3338 (void)data;
3339 bpf_callback_common((NetworkInterfaceInfoOSX *)context);
3340 }
3341 #endif
3342
3343 mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
3344 {
3345 LogMsg("mDNSPlatformSendKeepalive called\n");
3346 mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win);
3347 }
3348
3349 mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void)
3350 {
3351 SCDynamicStoreRef store = NULL;
3352 CFStringRef entityname = NULL;
3353
3354 if ((store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:ClearSPSMACAddress"), NULL, NULL)))
3355 {
3356 if ((entityname = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyAddress")))
3357 {
3358 if (SCDynamicStoreRemoveValue(store, entityname) == false)
3359 LogMsg("mDNSPlatformClearSPSMACAddr: Unable to remove key");
3360 }
3361 }
3362
3363 if (entityname) CFRelease(entityname);
3364 if (store) CFRelease(store);
3365 return KERN_SUCCESS;
3366 }
3367
3368 mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
3369 {
3370 int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
3371 LogSPS("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname);
3372 mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname);
3373 return KERN_SUCCESS;
3374 }
3375
3376 mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr)
3377 {
3378 int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
3379
3380 mDNSGetRemoteMAC(m, family, raddr->ip.v6.b);
3381 return KERN_SUCCESS;
3382 }
3383
3384 mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
3385 {
3386 mDNSs32 intfid;
3387 mDNSs32 error = 0;
3388 int family = (laddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
3389
3390 error = mDNSRetrieveTCPInfo(family, laddr->ip.v6.b, lport->NotAnInteger, raddr->ip.v6.b, rport->NotAnInteger, (uint32_t *)&(mti->seq), (uint32_t *)&(mti->ack), (uint16_t *)&(mti->window), (int32_t*)&intfid);
3391 if (error != KERN_SUCCESS)
3392 {
3393 LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error);
3394 return error;
3395 }
3396 mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(m, intfid);
3397 return error;
3398 }
3399
3400 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
3401
3402 mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *p4, int *p6)
3403 {
3404 int numv4 = 0, numv6 = 0;
3405 AuthRecord *rr;
3406
3407 for (rr = m->ResourceRecords; rr; rr=rr->next)
3408 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
3409 {
3410 if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
3411 numv4++;
3412 }
3413
3414 for (rr = m->ResourceRecords; rr; rr=rr->next)
3415 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
3416 {
3417 if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
3418 numv6++;
3419 }
3420
3421 if (p4) *p4 = numv4;
3422 if (p6) *p6 = numv6;
3423 return(numv4 + numv6);
3424 }
3425
3426 mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
3427 {
3428 NetworkInterfaceInfoOSX *x;
3429
3430 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
3431 for (x = m->p->InterfaceList; x; x = x->next) if (x->ifinfo.InterfaceID == InterfaceID) break;
3432
3433 if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
3434
3435 #define MAX_BPF_ADDRS 250
3436 int numv4 = 0, numv6 = 0;
3437
3438 if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS)
3439 {
3440 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
3441 if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
3442 numv6 = MAX_BPF_ADDRS - numv4;
3443 }
3444
3445 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
3446
3447 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
3448 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
3449 static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
3450 {
3451 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13)
3452
3453 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
3454 BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP
3455
3456 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
3457
3458 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
3459 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
3460 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
3461 BPF_STMT(BPF_RET + BPF_K, 86), // 7 Return 86-byte ND
3462
3463 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
3464 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
3465 };
3466
3467 struct bpf_insn *pc = &filter[9];
3468 struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0"
3469 struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks
3470 struct bpf_insn *ret4 = fail + 1;
3471 struct bpf_insn *ret6 = ret4 + 4;
3472
3473 static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing
3474
3475 static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
3476
3477 static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20)
3478 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)
3479 static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length
3480 static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
3481
3482 static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
3483
3484 BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail
3485 BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check
3486
3487 // BPF Byte-Order Note
3488 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
3489 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
3490 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
3491 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
3492 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
3493 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
3494 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
3495 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
3496 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
3497 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
3498
3499 // IPSEC capture size notes:
3500 // 8 bytes UDP header
3501 // 4 bytes Non-ESP Marker
3502 // 28 bytes IKE Header
3503 // --
3504 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
3505
3506 AuthRecord *rr;
3507 for (rr = m->ResourceRecords; rr; rr=rr->next)
3508 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
3509 {
3510 mDNSv4Addr a = rr->AddressProxy.ip.v4;
3511 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
3512 BPF_SetOffset(pc, jt, ret4);
3513 pc->jf = 0;
3514 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];
3515 pc++;
3516 }
3517 *pc++ = rf;
3518
3519 if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
3520 *pc++ = g6; // chk6 points here
3521
3522 // First cancel any previous ND group memberships we had, then create a fresh socket
3523 if (x->BPF_mcfd >= 0) close(x->BPF_mcfd);
3524 x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0);
3525
3526 for (rr = m->ResourceRecords; rr; rr=rr->next)
3527 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
3528 {
3529 const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
3530 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
3531 BPF_SetOffset(pc, jt, ret6);
3532 pc->jf = 0;
3533 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];
3534 pc++;
3535
3536 struct ipv6_mreq i6mr;
3537 i6mr.ipv6mr_interface = x->scope_id;
3538 i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix;
3539 i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD];
3540 i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE];
3541 i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF];
3542
3543 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
3544 mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
3545 if (err < 0 && (errno != EADDRNOTAVAIL))
3546 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
3547
3548 err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
3549 if (err < 0 && (errno != EADDRINUSE)) // Joining same group twice can give "Address already in use" error -- no need to report that
3550 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
3551
3552 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
3553 }
3554
3555 if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
3556 *pc++ = rf; // fail points here
3557
3558 if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
3559 *pc++ = r4a; // ret4 points here
3560 *pc++ = r4b;
3561 *pc++ = r4c;
3562 *pc++ = r4d;
3563
3564 if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
3565 *pc++ = r6a; // ret6 points here
3566
3567 struct bpf_program prog = { pc - filter, filter };
3568
3569 #if 0
3570 // For debugging BPF filter program
3571 unsigned int q;
3572 for (q=0; q<prog.bf_len; q++)
3573 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);
3574 #endif
3575
3576 if (!numv4 && !numv6)
3577 {
3578 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
3579 if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
3580 // Schedule check to see if we can close this BPF_fd now
3581 if (!m->p->NetworkChanged) m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
3582 // prog.bf_len = 0; This seems to panic the kernel
3583 if (x->BPF_fd < 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
3584 }
3585
3586 if (ioctl(x->BPF_fd, BIOCSETFNR, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
3587 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog.bf_len);
3588 }
3589
3590 mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd)
3591 {
3592 mDNS_Lock(m);
3593
3594 NetworkInterfaceInfoOSX *i;
3595 for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
3596 if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
3597 else
3598 {
3599 LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd);
3600
3601 struct bpf_version v;
3602 if (ioctl(fd, BIOCVERSION, &v) < 0)
3603 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3604 else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
3605 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
3606 fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
3607
3608 if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
3609 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3610
3611 if (i->BPF_len > sizeof(m->imsg))
3612 {
3613 i->BPF_len = sizeof(m->imsg);
3614 if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
3615 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3616 else
3617 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd, i->ifinfo.ifname, i->BPF_len);
3618 }
3619
3620 static const u_int opt_one = 1;
3621 if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0)
3622 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3623
3624 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
3625 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3626
3627 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
3628 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3629
3630 /* <rdar://problem/10287386>
3631 * make socket non blocking see comments in bpf_callback_common for more info
3632 */
3633 if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
3634 {
3635 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3636 }
3637
3638 struct ifreq ifr;
3639 mDNSPlatformMemZero(&ifr, sizeof(ifr));
3640 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3641 if (ioctl(fd, BIOCSETIF, &ifr) < 0)
3642 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
3643 else
3644 {
3645 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3646 i->BPF_fd = fd;
3647 i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());
3648 if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
3649 dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);});
3650 dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);});
3651 dispatch_resume(i->BPF_source);
3652 #else
3653 CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
3654 i->BPF_fd = fd;
3655 i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
3656 i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
3657 CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
3658 #endif
3659 mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID);
3660 }
3661 }
3662
3663 mDNS_Unlock(m);
3664 }
3665
3666 #endif // APPLE_OSX_mDNSResponder
3667
3668 #if COMPILER_LIKES_PRAGMA_MARK
3669 #pragma mark -
3670 #pragma mark - Key Management
3671 #endif
3672
3673 #ifndef NO_SECURITYFRAMEWORK
3674 mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity)
3675 {
3676 CFMutableArrayRef certChain = NULL;
3677 if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); }
3678 SecCertificateRef cert;
3679 OSStatus err = SecIdentityCopyCertificate(identity, &cert);
3680 if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
3681 else
3682 {
3683 SecPolicySearchRef searchRef;
3684 err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
3685 if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err);
3686 else
3687 {
3688 SecPolicyRef policy;
3689 err = SecPolicySearchCopyNext(searchRef, &policy);
3690 if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
3691 else
3692 {
3693 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
3694 if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL");
3695 else
3696 {
3697 SecTrustRef trust;
3698 err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
3699 if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
3700 else
3701 {
3702 err = SecTrustEvaluate(trust, NULL);
3703 if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err);
3704 else
3705 {
3706 CFArrayRef rawCertChain;
3707 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
3708 err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
3709 if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err);
3710 else
3711 {
3712 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
3713 if (!certChain) LogMsg("getCertChain: certChain is NULL");
3714 else
3715 {
3716 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
3717 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
3718 CFArraySetValueAtIndex(certChain, 0, identity);
3719 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
3720 if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
3721 }
3722 CFRelease(rawCertChain);
3723 // Do not free statusChain:
3724 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
3725 // certChain: Call the CFRelease function to release this object when you are finished with it.
3726 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
3727 }
3728 }
3729 CFRelease(trust);
3730 }
3731 CFRelease(wrappedCert);
3732 }
3733 CFRelease(policy);
3734 }
3735 CFRelease(searchRef);
3736 }
3737 CFRelease(cert);
3738 }
3739 return certChain;
3740 }
3741 #endif /* NO_SECURITYFRAMEWORK */
3742
3743 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
3744 {
3745 #ifdef NO_SECURITYFRAMEWORK
3746 return mStatus_UnsupportedErr;
3747 #else
3748 SecIdentityRef identity = nil;
3749 SecIdentitySearchRef srchRef = nil;
3750 OSStatus err;
3751
3752 // search for "any" identity matching specified key use
3753 // In this app, we expect there to be exactly one
3754 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
3755 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
3756
3757 err = SecIdentitySearchCopyNext(srchRef, &identity);
3758 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
3759
3760 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
3761 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
3762
3763 // Found one. Call getCertChain to create the correct certificate chain.
3764 ServerCerts = GetCertChain(identity);
3765 if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; }
3766
3767 return mStatus_NoError;
3768 #endif /* NO_SECURITYFRAMEWORK */
3769 }
3770
3771 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
3772 {
3773 #ifndef NO_SECURITYFRAMEWORK
3774 if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
3775 #endif /* NO_SECURITYFRAMEWORK */
3776 }
3777
3778 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
3779 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
3780 {
3781 CFStringEncoding encoding = kCFStringEncodingUTF8;
3782 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
3783 if (cfs)
3784 {
3785 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3786 CFRelease(cfs);
3787 }
3788 }
3789
3790 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
3791 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
3792 {
3793 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
3794 if (cfs)
3795 {
3796 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3797 CFRelease(cfs);
3798 }
3799 }
3800
3801 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
3802 {
3803 mDNSs32 val;
3804 CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
3805 if (!state) return mDNSfalse;
3806 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
3807 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
3808 return val ? mDNStrue : mDNSfalse;
3809 }
3810
3811 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
3812 {
3813 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
3814
3815 if (sa->sa_family == AF_INET)
3816 {
3817 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
3818 ip->type = mDNSAddrType_IPv4;
3819 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
3820 return(mStatus_NoError);
3821 }
3822
3823 if (sa->sa_family == AF_INET6)
3824 {
3825 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
3826 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
3827 // value into the second word of the IPv6 link-local address, so they can just
3828 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
3829 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
3830 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
3831 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
3832 ip->type = mDNSAddrType_IPv6;
3833 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
3834 return(mStatus_NoError);
3835 }
3836
3837 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
3838 return(mStatus_Invalid);
3839 }
3840
3841 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
3842 {
3843 mDNSEthAddr eth = zeroEthAddr;
3844 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
3845 if (!store)
3846 LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
3847 else
3848 {
3849 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
3850 if (entityname)
3851 {
3852 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
3853 if (dict)
3854 {
3855 CFRange range = { 0, 6 }; // Offset, length
3856 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
3857 if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
3858 CFRelease(dict);
3859 }
3860 CFRelease(entityname);
3861 }
3862 CFRelease(store);
3863 }
3864 return(eth);
3865 }
3866
3867 mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
3868 {
3869 struct ifaddrs *ifa;
3870 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
3871 if (ifa->ifa_addr->sa_family == AF_LINK)
3872 {
3873 const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
3874 if (sdl->sdl_index == ifindex)
3875 { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
3876 }
3877 *eth = zeroEthAddr;
3878 return -1;
3879 }
3880
3881 #ifndef SIOCGIFWAKEFLAGS
3882 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
3883 #endif
3884
3885 #ifndef IF_WAKE_ON_MAGIC_PACKET
3886 #define IF_WAKE_ON_MAGIC_PACKET 0x01
3887 #endif
3888
3889 #ifndef ifr_wake_flags
3890 #define ifr_wake_flags ifr_ifru.ifru_intval
3891 #endif
3892
3893 mDNSlocal mDNSBool CheckInterfaceSupport(NetworkInterfaceInfo *const intf, const char *key)
3894 {
3895 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
3896 if (!service)
3897 {
3898 LogSPS("CheckInterfaceSupport: No service for interface %s", intf->ifname);
3899 return mDNSfalse;
3900 }
3901
3902 io_name_t n1, n2;
3903 IOObjectGetClass(service, n1);
3904 io_object_t parent;
3905 mDNSBool ret = mDNSfalse;
3906 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
3907 if (kr == KERN_SUCCESS)
3908 {
3909 CFStringRef keystr = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
3910 IOObjectGetClass(parent, n2);
3911 LogSPS("CheckInterfaceSupport: Interface %s service %s parent %s", intf->ifname, n1, n2);
3912 const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, keystr, kCFAllocatorDefault, mDNSNULL);
3913 if (!ref)
3914 {
3915 LogSPS("CheckInterfaceSupport: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
3916 ret = mDNSfalse;
3917 }
3918 else
3919 {
3920 ret = mDNStrue;
3921 CFRelease(ref);
3922 }
3923 IOObjectRelease(parent);
3924 CFRelease(keystr);
3925 }
3926 else
3927 {
3928 LogSPS("CheckInterfaceSupport: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
3929 ret = mDNSfalse;
3930 }
3931 IOObjectRelease(service);
3932 return ret;
3933 }
3934
3935
3936 mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
3937 {
3938 return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
3939 }
3940
3941 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
3942 {
3943 if (!MulticastInterface(i) ) return(mDNSfalse); // We only use Sleep Proxy Service on multicast-capable interfaces
3944 if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse); // except loopback
3945
3946 // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
3947 // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
3948 // when the power source is not AC Power.
3949 if (InterfaceSupportsKeepAlive(&i->ifinfo))
3950 {
3951 LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i->ifinfo.ifname);
3952 return mDNStrue;
3953 }
3954
3955 int s = socket(AF_INET, SOCK_DGRAM, 0);
3956 if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); }
3957
3958 struct ifreq ifr;
3959 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3960 if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
3961 {
3962 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
3963 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
3964 // error code is being returned from the kernel, we need to use the kernel version.
3965 #define KERNEL_EOPNOTSUPP 102
3966 if (errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
3967 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno));
3968 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
3969 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
3970 ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
3971 }
3972
3973 close(s);
3974
3975 // 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
3976
3977 LogSPS("%-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
3978
3979 return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
3980 }
3981
3982 mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
3983 {
3984 int sockFD;
3985 struct ifreq ifr;
3986
3987 sockFD = socket(AF_INET, SOCK_DGRAM, 0);
3988 if (sockFD < 0)
3989 {
3990 LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno, strerror(errno));
3991 return 0;
3992 }
3993
3994 ifr.ifr_addr.sa_family = AF_INET;
3995 strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
3996
3997 if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
3998 {
3999 LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno));
4000 ifr.ifr_eflags = 0;
4001 }
4002 LogInfo("getExtendedFlags: %s ifr_eflags = 0x%x", ifa_name, ifr.ifr_eflags);
4003
4004 close(sockFD);
4005 return ifr.ifr_eflags;
4006 }
4007
4008 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
4009 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
4010 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
4011 // (e.g. sa_family not AF_INET or AF_INET6)
4012 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
4013 {
4014 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
4015 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
4016 u_int64_t eflags = getExtendedFlags(ifa->ifa_name);
4017
4018 mDNSAddr ip, mask;
4019 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
4020 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
4021
4022 NetworkInterfaceInfoOSX **p;
4023 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
4024 if (scope_id == (*p)->scope_id &&
4025 mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
4026 mDNSSameEthAddress(&bssid, &(*p)->BSSID))
4027 {
4028 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);
4029 // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
4030 // When interfaces are created with same MAC address, kernel resurrects the old interface.
4031 // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
4032 // we get the corresponding name for the interface index on which the packet was received and check against
4033 // the InterfaceList for a matching name. So, keep the name in sync
4034 strlcpy((*p)->ifinfo.ifname, ifa->ifa_name, sizeof((*p)->ifinfo.ifname));
4035 (*p)->Exists = mDNStrue;
4036 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
4037 if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
4038
4039 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
4040 // we may need to start or stop or sleep proxy browse operation
4041 const mDNSBool NetWake = NetWakeInterface(*p);
4042 if ((*p)->ifinfo.NetWake != NetWake)
4043 {
4044 (*p)->ifinfo.NetWake = NetWake;
4045 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
4046 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
4047 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
4048 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
4049 if ((*p)->Registered)
4050 {
4051 mDNS_Lock(m);
4052 if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo);
4053 else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
4054 mDNS_Unlock(m);
4055 }
4056 }
4057 // Reset the flag if it has changed this time.
4058 (*p)->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
4059
4060 return(*p);
4061 }
4062
4063 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
4064 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
4065 if (!i) return(mDNSNULL);
4066 mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
4067 i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
4068 i->ifinfo.ip = ip;
4069 i->ifinfo.mask = mask;
4070 strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
4071 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
4072 // We can be configured to disable multicast advertisement, but we want to to support
4073 // local-only services, which need a loopback address record.
4074 i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
4075 i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
4076 i->ifinfo.Loopback = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse;
4077 i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
4078 i->ifinfo.DirectLink = (eflags & IFEF_DIRECTLINK) ? mDNStrue: mDNSfalse;
4079
4080 i->next = mDNSNULL;
4081 i->m = m;
4082 i->Exists = mDNStrue;
4083 i->Flashing = mDNSfalse;
4084 i->Occulting = mDNSfalse;
4085 i->D2DInterface = (eflags & IFEF_LOCALNET_PRIVATE) ? mDNStrue: mDNSfalse;
4086 if (eflags & IFEF_AWDL)
4087 {
4088 AWDLInterfaceID = i->ifinfo.InterfaceID;
4089 LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
4090 }
4091 i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
4092 i->LastSeen = utc;
4093 i->ifa_flags = ifa->ifa_flags;
4094 i->scope_id = scope_id;
4095 i->BSSID = bssid;
4096 i->sa_family = ifa->ifa_addr->sa_family;
4097 i->BPF_fd = -1;
4098 i->BPF_mcfd = -1;
4099 i->BPF_len = 0;
4100 i->Registered = mDNSNULL;
4101
4102 // Do this AFTER i->BSSID has been set up
4103 i->ifinfo.NetWake = NetWakeInterface(i);
4104 GetMAC(&i->ifinfo.MAC, scope_id);
4105 if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
4106 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
4107
4108 *p = i;
4109 return(i);
4110 }
4111
4112 #if APPLE_OSX_mDNSResponder
4113
4114 #if COMPILER_LIKES_PRAGMA_MARK
4115 #pragma mark -
4116 #pragma mark - AutoTunnel
4117 #endif
4118
4119 #define kRacoonPort 4500
4120
4121 static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
4122
4123 #ifndef NO_SECURITYFRAMEWORK
4124
4125 static CFMutableDictionaryRef domainStatusDict = NULL;
4126
4127 mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
4128 {
4129 if (q->LongLived)
4130 {
4131 if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
4132 return mStatus_NoSuchRecord;
4133 else if (q->state == LLQ_Poll)
4134 return mStatus_PollingMode;
4135 else if (q->state != LLQ_Established && !q->DuplicateOf)
4136 return mStatus_TransientErr;
4137 }
4138
4139 return mStatus_NoError;
4140 }
4141
4142 mDNSlocal mStatus UpdateLLQStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
4143 {
4144 mStatus status = mStatus_NoError;
4145 DNSQuestion* q, *worst_q = mDNSNULL;
4146 for (q = m->Questions; q; q=q->next)
4147 if (q->AuthInfo == info)
4148 {
4149 mStatus newStatus = CheckQuestionForStatus(q);
4150 if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
4151 else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; }
4152 else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
4153 }
4154
4155 if (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success");
4156 else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
4157 else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
4158 else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
4159 return status;
4160 }
4161
4162 mDNSlocal mStatus UpdateRRStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
4163 {
4164 AuthRecord *r;
4165
4166 if (info->deltime) return mStatus_NoError;
4167 for (r = m->ResourceRecords; r; r = r->next)
4168 {
4169 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
4170 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
4171 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
4172 // has already checked
4173 const domainname *n = r->resrec.name;
4174 while (n->c[0])
4175 {
4176 DomainAuthInfo *ptr;
4177 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
4178 if (SameDomainName(&ptr->domain, n))
4179 {
4180 if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime))
4181 {
4182 mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
4183 return r->updateError;
4184 }
4185 }
4186 n = (const domainname *)(n->c + 1 + n->c[0]);
4187 }
4188 }
4189 return mStatus_NoError;
4190 }
4191
4192 #endif // ndef NO_SECURITYFRAMEWORK
4193
4194 // MUST be called with lock held
4195 mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
4196 {
4197 #ifdef NO_SECURITYFRAMEWORK
4198 (void) m;
4199 (void)info;
4200 #else
4201 // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
4202 // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
4203 const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL;
4204 const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL;
4205 char buffer[1024];
4206 mDNSu32 buflen = 0;
4207 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4208 CFStringRef domain = NULL;
4209 CFStringRef tmp = NULL;
4210 CFNumberRef num = NULL;
4211 mStatus status = mStatus_NoError;
4212 mStatus llqStatus = mStatus_NoError;
4213 char llqBuffer[1024];
4214
4215 mDNS_CheckLock(m);
4216
4217 if (!domainStatusDict)
4218 {
4219 domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4220 if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
4221 }
4222
4223 if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
4224
4225 buflen = mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c);
4226 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4227 if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
4228
4229 if (info->deltime)
4230 {
4231 if (CFDictionaryContainsKey(domainStatusDict, domain))
4232 {
4233 CFDictionaryRemoveValue(domainStatusDict, domain);
4234 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
4235 }
4236 CFRelease(domain);
4237 CFRelease(dict);
4238
4239 return;
4240 }
4241
4242 mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
4243 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4244 if (!tmp)
4245 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
4246 else
4247 {
4248 CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
4249 CFRelease(tmp);
4250 }
4251
4252 if (llq)
4253 {
4254 mDNSu32 port = mDNSVal16(llq->ExternalPort);
4255
4256 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
4257 if (!num)
4258 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
4259 else
4260 {
4261 CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
4262 CFRelease(num);
4263 }
4264
4265 if (llq->Result)
4266 {
4267 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
4268 if (!num)
4269 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
4270 else
4271 {
4272 CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
4273 CFRelease(num);
4274 }
4275 }
4276 }
4277
4278 if (tun)
4279 {
4280 mDNSu32 port = mDNSVal16(tun->ExternalPort);
4281
4282 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
4283 if (!num)
4284 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
4285 else
4286 {
4287 CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
4288 CFRelease(num);
4289 }
4290
4291 mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress);
4292 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4293 if (!tmp)
4294 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
4295 else
4296 {
4297 CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
4298 CFRelease(tmp);
4299 }
4300
4301 if (tun->Result)
4302 {
4303 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
4304 if (!num)
4305 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
4306 else
4307 {
4308 CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
4309 CFRelease(num);
4310 }
4311 }
4312 }
4313 if (tun || llq)
4314 {
4315 mDNSu32 code = m->LastNATMapResultCode;
4316
4317 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
4318 if (!num)
4319 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
4320 else
4321 {
4322 CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
4323 CFRelease(num);
4324 }
4325 }
4326
4327 mDNS_snprintf(buffer, sizeof(buffer), "Success");
4328 llqStatus = UpdateLLQStatus(m, llqBuffer, sizeof(llqBuffer), info);
4329 status = UpdateRRStatus(m, buffer, sizeof(buffer), info);
4330
4331 // If we have a bad signature error updating a RR, it overrides any error as it needs to be
4332 // reported so that it can be fixed automatically (or the user needs to be notified)
4333 if (status != mStatus_NoError)
4334 {
4335 LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer);
4336 }
4337 else if (m->Router.type == mDNSAddrType_None)
4338 {
4339 status = mStatus_NoRouter;
4340 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
4341 }
4342 else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
4343 {
4344 status = mStatus_NoRouter;
4345 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
4346 }
4347 else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress))
4348 {
4349 status = mStatus_ServiceNotRunning;
4350 mDNS_snprintf(buffer, sizeof(buffer), "No inner address");
4351 }
4352 else if (!llq && !tun)
4353 {
4354 status = mStatus_NotInitializedErr;
4355 mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
4356 }
4357 else if (llqStatus == mStatus_NoSuchRecord)
4358 {
4359 status = llqStatus;
4360 mDNS_snprintf(buffer, sizeof(buffer), llqBuffer);
4361 }
4362 else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
4363 {
4364 status = mStatus_DoubleNAT;
4365 mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address");
4366 }
4367 else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) ||
4368 (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
4369 (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
4370 {
4371 status = mStatus_NATPortMappingDisabled;
4372 mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router");
4373 }
4374 else if ((llq && llq->Result) || (tun && tun->Result))
4375 {
4376 status = mStatus_NATTraversal;
4377 mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
4378 }
4379 else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
4380 {
4381 status = mStatus_NATTraversal;
4382 mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
4383 }
4384 else
4385 {
4386 status = llqStatus;
4387 mDNS_snprintf(buffer, sizeof(buffer), llqBuffer);
4388 LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer);
4389 }
4390
4391 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
4392 if (!num)
4393 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
4394 else
4395 {
4396 CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
4397 CFRelease(num);
4398 }
4399
4400 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4401 if (!tmp)
4402 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
4403 else
4404 {
4405 CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
4406 CFRelease(tmp);
4407 }
4408
4409 if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
4410 !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
4411 {
4412 CFDictionarySetValue(domainStatusDict, domain, dict);
4413 if (!m->ShutdownTime)
4414 {
4415 static char statusBuf[16];
4416 mDNS_snprintf(statusBuf, sizeof(statusBuf), "%d", (int)status);
4417 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.domainstatus", status ? "failure" : "success", statusBuf, "");
4418 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
4419 }
4420 }
4421
4422 CFRelease(domain);
4423 CFRelease(dict);
4424
4425 debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
4426 #endif // def NO_SECURITYFRAMEWORK
4427 }
4428
4429 // MUST be called with lock held
4430 mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
4431 {
4432 #ifdef NO_SECURITYFRAMEWORK
4433 (void) m;
4434 #else
4435 mDNS_CheckLock(m);
4436 DomainAuthInfo* info;
4437 for (info = m->AuthInfoList; info; info = info->next)
4438 if (info->AutoTunnel && !info->deltime)
4439 UpdateAutoTunnelDomainStatus(m, info);
4440 #endif // def NO_SECURITYFRAMEWORK
4441 }
4442
4443 mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we need racoon to accept incoming connections
4444 {
4445 DomainAuthInfo *info;
4446
4447 for (info = m->AuthInfoList; info; info = info->next)
4448 if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
4449 break;
4450
4451 if (info != AnonymousRacoonConfig)
4452 {
4453 AnonymousRacoonConfig = info;
4454 // Create or revert configuration file, and start (or SIGHUP) Racoon
4455 (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, AnonymousRacoonConfig ? btmmprefix : mDNSNULL, AnonymousRacoonConfig ? &AnonymousRacoonConfig->domain : mDNSNULL);
4456 }
4457 }
4458
4459 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
4460
4461 // Caller must hold the lock
4462 mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record)
4463 {
4464 mDNS_CheckLock(m);
4465
4466 LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c);
4467
4468 if (record->resrec.RecordType > kDNSRecordTypeDeregistering)
4469 {
4470 mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal);
4471 if (err)
4472 {
4473 record->resrec.RecordType = kDNSRecordTypeUnregistered;
4474 LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c);
4475 return mDNSfalse;
4476 }
4477 else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
4478 }
4479 else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType);
4480
4481 return mDNStrue;
4482 }
4483
4484 // Caller must hold the lock
4485 mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
4486 {
4487 if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord))
4488 {
4489 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
4490 m->NextSRVUpdate = NonZeroTime(m->timenow);
4491 }
4492 }
4493
4494 // Caller must hold the lock
4495 mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
4496 {
4497 mStatus err;
4498 mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result;
4499
4500 mDNS_CheckLock(m);
4501
4502 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem))
4503 {
4504 LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
4505 info->domain.c, info->AutoTunnelServiceStarted, info->deltime, &info->AutoTunnelInnerAddress, m->SleepState);
4506 DeregisterAutoTunnelHostRecord(m, info);
4507 }
4508 else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
4509 {
4510 mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
4511 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4512 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
4513 AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
4514 AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
4515 info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = info->AutoTunnelInnerAddress;
4516 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
4517
4518 err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
4519 if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c);
4520 else
4521 {
4522 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
4523 m->NextSRVUpdate = NonZeroTime(m->timenow);
4524 LogInfo("UpdateAutoTunnelHostRecord registering %##s", info->AutoTunnelHostRecord.namestorage.c);
4525 }
4526 }
4527 else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType);
4528 }
4529
4530 // Caller must hold the lock
4531 mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4532 {
4533 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
4534
4535 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget);
4536 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService);
4537 UpdateAutoTunnelHostRecord(m, info);
4538 }
4539
4540 // Caller must hold the lock
4541 mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4542 {
4543 mDNS_CheckLock(m);
4544
4545 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)
4546 {
4547 LogInfo("UpdateAutoTunnelServiceRecords: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) ExtPort(%d) NATResult(%d)", info->domain.c, info->AutoTunnelServiceStarted, info->deltime, mDNSVal16(m->AutoTunnelNAT.ExternalPort), m->AutoTunnelNAT.Result);
4548 DeregisterAutoTunnelServiceRecords(m, info);
4549 }
4550 else
4551 {
4552 if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
4553 {
4554 // 1. Set up our address record for the external tunnel address
4555 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
4556 mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL,
4557 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4558 AssignDomainName (&info->AutoTunnelTarget.namestorage, (const domainname*) "\x0B" "_autotunnel");
4559 AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->hostlabel);
4560 AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
4561 info->AutoTunnelTarget.resrec.rdata->u.ipv4 = m->AutoTunnelNAT.ExternalAddress;
4562 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
4563
4564 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelTarget);
4565 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelTarget.namestorage.c);
4566 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelTarget.namestorage.c);
4567 }
4568 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType);
4569
4570 if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
4571 {
4572 // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
4573 mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL,
4574 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4575 AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4576 AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
4577 AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
4578 info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
4579 info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
4580 info->AutoTunnelService.resrec.rdata->u.srv.port = m->AutoTunnelNAT.ExternalPort;
4581 AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
4582 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
4583
4584 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelService);
4585 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelService.namestorage.c);
4586 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelService.namestorage.c);
4587 }
4588 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType);
4589
4590 UpdateAutoTunnelHostRecord(m, info);
4591
4592 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
4593 info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(m->AutoTunnelNAT.IntPort),
4594 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4595
4596 }
4597 }
4598
4599 // Caller must hold the lock
4600 mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4601 {
4602 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo);
4603 }
4604
4605 // Caller must hold the lock
4606 mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4607 {
4608 mDNS_CheckLock(m);
4609
4610 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime)
4611 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4612 else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
4613 {
4614 mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4615 ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
4616
4617 info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data);
4618 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
4619
4620 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
4621 if (err) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
4622 else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info->AutoTunnelDeviceInfo.namestorage.c);
4623 }
4624 else
4625 LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType);
4626 }
4627
4628 // Caller must hold the lock
4629 mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4630 {
4631 LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
4632
4633 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
4634 UpdateAutoTunnelHostRecord(m, info);
4635 UpdateAutoTunnelDomainStatus(m, info);
4636 }
4637
4638 // Caller must hold the lock
4639 mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4640 {
4641 mDNS_CheckLock(m);
4642
4643 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr) || m->SleepState != SleepState_Awake)
4644 DeregisterAutoTunnel6Record(m, info);
4645 else if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
4646 {
4647 mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
4648 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4649 AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
4650 AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
4651 AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
4652 info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr;
4653 info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
4654
4655 mStatus err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
4656 if (err) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err, info->AutoTunnel6Record.namestorage.c);
4657 else LogInfo("UpdateAutoTunnel6Record registering %##s", info->AutoTunnel6Record.namestorage.c);
4658
4659 UpdateAutoTunnelHostRecord(m, info);
4660
4661 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
4662 info->AutoTunnel6Record.namestorage.c, &m->AutoTunnelRelayAddr,
4663 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4664
4665 }
4666 else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType);
4667 }
4668
4669 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
4670 {
4671 DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
4672 if (result == mStatus_MemFree)
4673 {
4674 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
4675
4676 mDNS_Lock(m);
4677
4678 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
4679 if (rr == &info->AutoTunnelHostRecord)
4680 {
4681 rr->namestorage.c[0] = 0;
4682 m->NextSRVUpdate = NonZeroTime(m->timenow);
4683 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4684 }
4685 if (m->ShutdownTime)
4686 {
4687 LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
4688 mDNS_Unlock(m);
4689 return;
4690 }
4691 if (rr == &info->AutoTunnelHostRecord)
4692 {
4693 LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
4694 UpdateAutoTunnelHostRecord(m,info);
4695 }
4696 else if (rr == &info->AutoTunnelDeviceInfo)
4697 {
4698 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
4699 UpdateAutoTunnelDeviceInfoRecord(m,info);
4700 }
4701 else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
4702 {
4703 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
4704 UpdateAutoTunnelServiceRecords(m,info);
4705 }
4706 else if (rr == &info->AutoTunnel6Record)
4707 {
4708 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
4709 UpdateAutoTunnel6Record(m,info);
4710 }
4711
4712 mDNS_Unlock(m);
4713 }
4714 }
4715
4716 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
4717 {
4718 DomainAuthInfo *info;
4719
4720 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
4721 n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort));
4722
4723 mDNS_Lock(m);
4724
4725 m->NextSRVUpdate = NonZeroTime(m->timenow);
4726 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4727
4728 for (info = m->AuthInfoList; info; info = info->next)
4729 if (info->AutoTunnel)
4730 UpdateAutoTunnelServiceRecords(m, info);
4731
4732 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
4733
4734 UpdateAutoTunnelDomainStatuses(m);
4735
4736 mDNS_Unlock(m);
4737 }
4738
4739 mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
4740 {
4741 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
4742
4743 mDNS_Lock(m);
4744 // We forcibly deregister the records that are based on the hostname.
4745 // When deregistration of each completes, the MemFree callback will make the
4746 // appropriate Update* call to use the new name to reregister.
4747 DeregisterAutoTunnelHostRecord(m, info);
4748 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4749 DeregisterAutoTunnelServiceRecords(m, info);
4750 DeregisterAutoTunnel6Record(m, info);
4751 m->NextSRVUpdate = NonZeroTime(m->timenow);
4752 mDNS_Unlock(m);
4753 }
4754
4755 // Must be called with the lock held
4756 mDNSexport void StartServerTunnel(mDNS *const m, DomainAuthInfo *const info)
4757 {
4758 if (info->deltime) return;
4759
4760 if (info->AutoTunnelServiceStarted)
4761 {
4762 // On wake from sleep, this function will be called when determining SRV targets,
4763 // and needs to re-register the host record for the target to be set correctly
4764 UpdateAutoTunnelHostRecord(m, info);
4765 return;
4766 }
4767
4768 info->AutoTunnelServiceStarted = mDNStrue;
4769
4770 // Now that we have a service in this domain, we need to try to register the
4771 // AutoTunnel records, because the relay connection & NAT-T may have already been
4772 // started for another domain. If the relay connection is not up or the NAT-T has not
4773 // yet succeeded, the Update* functions are smart enough to not register the records.
4774 // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
4775 // decide whether to register the AutoTunnel records in the calls below.
4776 UpdateAutoTunnelServiceRecords(m, info);
4777 UpdateAutoTunnel6Record(m, info);
4778 UpdateAutoTunnelDeviceInfoRecord(m, info);
4779 UpdateAutoTunnelHostRecord(m, info);
4780
4781 // If the global AutoTunnel NAT-T is not yet started, start it.
4782 if (!m->AutoTunnelNAT.clientContext)
4783 {
4784 m->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
4785 m->AutoTunnelNAT.clientContext = (void*)1; // Means AutoTunnelNAT Traversal is active;
4786 m->AutoTunnelNAT.Protocol = NATOp_MapUDP;
4787 m->AutoTunnelNAT.IntPort = IPSECPort;
4788 m->AutoTunnelNAT.RequestedPort = IPSECPort;
4789 m->AutoTunnelNAT.NATLease = 0;
4790 mStatus err = mDNS_StartNATOperation_internal(m, &m->AutoTunnelNAT);
4791 if (err) LogMsg("StartServerTunnel: error %d starting NAT mapping", err);
4792 }
4793 }
4794
4795 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
4796 {
4797 mDNSv6Addr loc_outer6;
4798 mDNSv6Addr rmt_outer6;
4799
4800 // When we are tunneling over IPv6 Relay address, the port number is zero
4801 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4802 {
4803 loc_outer6 = tun->loc_outer6;
4804 rmt_outer6 = tun->rmt_outer6;
4805 }
4806 else
4807 {
4808 loc_outer6 = zerov6Addr;
4809 loc_outer6.b[0] = tun->loc_outer.b[0];
4810 loc_outer6.b[1] = tun->loc_outer.b[1];
4811 loc_outer6.b[2] = tun->loc_outer.b[2];
4812 loc_outer6.b[3] = tun->loc_outer.b[3];
4813
4814 rmt_outer6 = zerov6Addr;
4815 rmt_outer6.b[0] = tun->rmt_outer.b[0];
4816 rmt_outer6.b[1] = tun->rmt_outer.b[1];
4817 rmt_outer6.b[2] = tun->rmt_outer.b[2];
4818 rmt_outer6.b[3] = tun->rmt_outer.b[3];
4819 }
4820
4821 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), btmmprefix, SkipLeadingLabels(&tun->dstname, 1)));
4822 }
4823
4824 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
4825 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
4826
4827 mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype)
4828 {
4829 DNSQuestion *q = m->Questions;
4830 while (q)
4831 {
4832 if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
4833 {
4834 LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4835 mDNSQuestionCallback *tmp = q->QuestionCallback;
4836 q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
4837 mDNS_StopQuery(m, q);
4838 mDNS_StartQuery(m, q);
4839 q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
4840 if (!success) q->NoAnswer = NoAnswer_Fail;
4841 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
4842 // In general we have to assume that the question list might have changed in arbitrary ways.
4843 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
4844 // already in use. The safest solution is just to go back to the start of the list and start again.
4845 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
4846 // just one suspended question, so it's really a 2n algorithm.
4847 q = m->Questions;
4848 }
4849 else
4850 q = q->next;
4851 }
4852 }
4853
4854 mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
4855 {
4856 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
4857 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
4858 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
4859 // 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.
4860 // 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.
4861 ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA);
4862 ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A);
4863 }
4864
4865 mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
4866 {
4867 ClientTunnel **p = &m->TunnelClients;
4868 while (*p != tun && *p) p = &(*p)->next;
4869 if (*p) *p = tun->next;
4870 ReissueBlockedQuestions(m, &tun->dstname, success);
4871 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
4872 freeL("ClientTunnel", tun);
4873 }
4874
4875 mDNSlocal mDNSBool TunnelClientDeleteMatching(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
4876 {
4877 ClientTunnel **p;
4878 mDNSBool needSetKeys = mDNStrue;
4879
4880 p = &tun->next;
4881 while (*p)
4882 {
4883 // Is this a tunnel to the same host that we are trying to setup now?
4884 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4885 else
4886 {
4887 ClientTunnel *old = *p;
4888 if (v6Tunnel)
4889 {
4890 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4891 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4892 if (old->q.ThisQInterval >= 0)
4893 {
4894 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4895 mDNS_StopQuery(m, &old->q);
4896 }
4897 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4898 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4899 !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
4900 !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
4901 {
4902 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4903 // the other parameters of the tunnel are different
4904 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4905 AutoTunnelSetKeys(old, mDNSfalse);
4906 }
4907 else
4908 {
4909 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4910 // as "tun" and "old" are identical
4911 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
4912 &old->rmt_inner);
4913 needSetKeys = mDNSfalse;
4914 }
4915 }
4916 else
4917 {
4918 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4919 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4920 if (old->q.ThisQInterval >= 0)
4921 {
4922 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4923 mDNS_StopQuery(m, &old->q);
4924 }
4925 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4926 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4927 !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
4928 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
4929 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
4930 {
4931 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4932 // the other parameters of the tunnel are different
4933 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4934 AutoTunnelSetKeys(old, mDNSfalse);
4935 }
4936 else
4937 {
4938 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4939 // as "tun" and "old" are identical
4940 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
4941 &old->rmt_inner);
4942 needSetKeys = mDNSfalse;
4943 }
4944 }
4945
4946 *p = old->next;
4947 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
4948 freeL("ClientTunnel", old);
4949 }
4950 }
4951 return needSetKeys;
4952 }
4953
4954 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
4955 // tunnel will be deleted
4956 mDNSlocal void TunnelClientDeleteAny(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
4957 {
4958 ClientTunnel **p;
4959
4960 p = &tun->next;
4961 while (*p)
4962 {
4963 // If there is more than one client tunnel to the same host, delete all of them.
4964 // We do this by just checking against the EUI64 rather than the full address
4965 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4966 else
4967 {
4968 ClientTunnel *old = *p;
4969 if (v6Tunnel)
4970 {
4971 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4972 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4973 }
4974 else
4975 {
4976 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4977 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4978 }
4979 if (old->q.ThisQInterval >= 0)
4980 {
4981 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4982 mDNS_StopQuery(m, &old->q);
4983 }
4984 else
4985 {
4986 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4987 AutoTunnelSetKeys(old, mDNSfalse);
4988 }
4989 *p = old->next;
4990 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
4991 freeL("ClientTunnel", old);
4992 }
4993 }
4994 }
4995
4996 mDNSlocal void TunnelClientFinish(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer)
4997 {
4998 mDNSBool needSetKeys = mDNStrue;
4999 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
5000 mDNSBool v6Tunnel = mDNSfalse;
5001 DomainAuthInfo *info;
5002
5003 // If the port is zero, then we have a relay address of the peer
5004 if (mDNSIPPortIsZero(tun->rmt_outer_port))
5005 v6Tunnel = mDNStrue;
5006
5007 if (v6Tunnel)
5008 {
5009 LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
5010 tun->rmt_outer6 = answer->rdata->u.ipv6;
5011 tun->loc_outer6 = m->AutoTunnelRelayAddr;
5012 }
5013 else
5014 {
5015 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
5016 tun->rmt_outer = answer->rdata->u.ipv4;
5017 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
5018 tmpDst.ip.v4 = tun->rmt_outer;
5019 mDNSAddr tmpSrc = zeroAddr;
5020 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
5021 if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
5022 else tun->loc_outer = m->AdvertisedV4.ip.v4;
5023 }
5024
5025 question->ThisQInterval = -1; // So we know this tunnel setup has completed
5026
5027 info = GetAuthInfoForName(m, &tun->dstname);
5028 if (!info)
5029 {
5030 LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
5031 ReissueBlockedQuestions(m, &tun->dstname, mDNSfalse);
5032 return;
5033 }
5034
5035 tun->loc_inner = info->AutoTunnelInnerAddress;
5036
5037 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
5038 // look for existing tunnels to see whether they have the same information for our peer.
5039 // If not, delete them and need to create a new tunnel. If they are same, just use the
5040 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
5041 TunnelClientDeleteAny(m, tun, !v6Tunnel);
5042 needSetKeys = TunnelClientDeleteMatching(m, tun, v6Tunnel);
5043
5044 if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
5045 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
5046
5047 mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
5048 static char msgbuf[32];
5049 mDNS_snprintf(msgbuf, sizeof(msgbuf), "Tunnel setup - %d", result);
5050 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", result ? "failure" : "success", msgbuf, "");
5051 // Kick off any questions that were held pending this tunnel setup
5052 ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
5053 }
5054
5055 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
5056 {
5057 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
5058 DomainAuthInfo *info;
5059
5060 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
5061
5062 if (!AddRecord) return;
5063 mDNS_StopQuery(m, question);
5064
5065 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
5066 // The code below will look for _autotunnel._udp SRV record followed by A record
5067 if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
5068 {
5069 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5070 static char msgbuf[16];
5071 mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s lookup", DNSTypeName(question->qtype));
5072 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", "failure", msgbuf, "");
5073 UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
5074 return;
5075 }
5076
5077 switch (tun->tc_state)
5078 {
5079 case TC_STATE_AAAA_PEER:
5080 if (question->qtype != kDNSType_AAAA)
5081 {
5082 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
5083 }
5084 info = GetAuthInfoForName(m, &tun->dstname);
5085 if (!info)
5086 {
5087 LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
5088 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
5089 return;
5090 }
5091 if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
5092 {
5093 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
5094 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
5095 return;
5096 }
5097 if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
5098 {
5099 LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6);
5100 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
5101 return;
5102 }
5103 tun->rmt_inner = answer->rdata->u.ipv6;
5104 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
5105 if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
5106 {
5107 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
5108 tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
5109 question->qtype = kDNSType_AAAA;
5110 AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
5111 }
5112 else
5113 {
5114 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
5115 tun->tc_state = TC_STATE_SRV_PEER;
5116 question->qtype = kDNSType_SRV;
5117 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
5118 }
5119 AppendDomainName(&question->qname, &tun->dstname);
5120 mDNS_StartQuery(m, &tun->q);
5121 return;
5122 case TC_STATE_AAAA_PEER_RELAY:
5123 if (question->qtype != kDNSType_AAAA)
5124 {
5125 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
5126 }
5127 // If it failed, look for the SRV record.
5128 if (!answer->rdlength)
5129 {
5130 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
5131 tun->tc_state = TC_STATE_SRV_PEER;
5132 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
5133 AppendDomainName(&question->qname, &tun->dstname);
5134 question->qtype = kDNSType_SRV;
5135 mDNS_StartQuery(m, &tun->q);
5136 return;
5137 }
5138 TunnelClientFinish(m, question, answer);
5139 return;
5140 case TC_STATE_SRV_PEER:
5141 if (question->qtype != kDNSType_SRV)
5142 {
5143 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
5144 }
5145 LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
5146 tun->tc_state = TC_STATE_ADDR_PEER;
5147 AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
5148 tun->rmt_outer_port = answer->rdata->u.srv.port;
5149 question->qtype = kDNSType_A;
5150 mDNS_StartQuery(m, &tun->q);
5151 return;
5152 case TC_STATE_ADDR_PEER:
5153 if (question->qtype != kDNSType_A)
5154 {
5155 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
5156 }
5157 TunnelClientFinish(m, question, answer);
5158 return;
5159 default:
5160 LogMsg("AutoTunnelCallback: Unknown question %p", question);
5161 }
5162 }
5163
5164 // Must be called with the lock held
5165 mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
5166 {
5167 ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
5168 if (!p) return;
5169 AssignDomainName(&p->dstname, &q->qname);
5170 p->MarkedForDeletion = mDNSfalse;
5171 p->loc_inner = zerov6Addr;
5172 p->loc_outer = zerov4Addr;
5173 p->loc_outer6 = zerov6Addr;
5174 p->rmt_inner = zerov6Addr;
5175 p->rmt_outer = zerov4Addr;
5176 p->rmt_outer6 = zerov6Addr;
5177 p->rmt_outer_port = zeroIPPort;
5178 p->tc_state = TC_STATE_AAAA_PEER;
5179 p->next = m->TunnelClients;
5180 m->TunnelClients = p; // We intentionally build list in reverse order
5181
5182 p->q.InterfaceID = mDNSInterface_Any;
5183 p->q.flags = 0;
5184 p->q.Target = zeroAddr;
5185 AssignDomainName(&p->q.qname, &q->qname);
5186 p->q.qtype = kDNSType_AAAA;
5187 p->q.qclass = kDNSClass_IN;
5188 p->q.LongLived = mDNSfalse;
5189 p->q.ExpectUnique = mDNStrue;
5190 p->q.ForceMCast = mDNSfalse;
5191 p->q.ReturnIntermed = mDNStrue;
5192 p->q.SuppressUnusable = mDNSfalse;
5193 p->q.DenyOnCellInterface = mDNSfalse;
5194 p->q.DenyOnExpInterface = mDNSfalse;
5195 p->q.SearchListIndex = 0;
5196 p->q.AppendSearchDomains = 0;
5197 p->q.RetryWithSearchDomains = mDNSfalse;
5198 p->q.TimeoutQuestion = 0;
5199 p->q.WakeOnResolve = 0;
5200 p->q.UseBackgroundTrafficClass = mDNSfalse;
5201 p->q.ValidationRequired = 0;
5202 p->q.ValidatingResponse = 0;
5203 p->q.ProxyQuestion = 0;
5204 p->q.qnameOrig = mDNSNULL;
5205 p->q.AnonInfo = mDNSNULL;
5206 p->q.pid = mDNSPlatformGetPID();
5207 p->q.QuestionCallback = AutoTunnelCallback;
5208 p->q.QuestionContext = p;
5209
5210 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
5211 mDNS_StartQuery_internal(m, &p->q);
5212 }
5213
5214 #endif // APPLE_OSX_mDNSResponder
5215
5216 #if COMPILER_LIKES_PRAGMA_MARK
5217 #pragma mark -
5218 #pragma mark - Power State & Configuration Change Management
5219 #endif
5220
5221 mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
5222 {
5223 mDNSBool foundav4 = mDNSfalse;
5224 mDNSBool foundav6 = mDNSfalse;
5225 struct ifaddrs *ifa = myGetIfAddrs(1);
5226 struct ifaddrs *v4Loopback = NULL;
5227 struct ifaddrs *v6Loopback = NULL;
5228 char defaultname[64];
5229 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
5230 if (InfoSocket < 3 && errno != EAFNOSUPPORT)
5231 LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
5232
5233 if (m->SleepState == SleepState_Sleeping) ifa = NULL;
5234
5235 while (ifa)
5236 {
5237 #if LIST_ALL_INTERFACES
5238 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
5239 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
5240 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5241 else if (ifa->ifa_addr->sa_family == AF_LINK)
5242 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
5243 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5244 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
5245 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
5246 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5247 if (!(ifa->ifa_flags & IFF_UP))
5248 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
5249 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5250 if (!(ifa->ifa_flags & IFF_MULTICAST))
5251 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
5252 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5253 if (ifa->ifa_flags & IFF_POINTOPOINT)
5254 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
5255 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5256 if (ifa->ifa_flags & IFF_LOOPBACK)
5257 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
5258 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5259 #endif
5260
5261 if (ifa->ifa_addr->sa_family == AF_LINK)
5262 {
5263 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
5264 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
5265 mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
5266 }
5267
5268 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
5269 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
5270 {
5271 if (!ifa->ifa_netmask)
5272 {
5273 mDNSAddr ip;
5274 SetupAddr(&ip, ifa->ifa_addr);
5275 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
5276 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
5277 }
5278 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
5279 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5280 else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0)
5281 {
5282 mDNSAddr ip;
5283 SetupAddr(&ip, ifa->ifa_addr);
5284 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
5285 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
5286 }
5287 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
5288 else if ((int)if_nametoindex(ifa->ifa_name) <= 0)
5289 {
5290 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
5291 }
5292 else
5293 {
5294 // Make sure ifa_netmask->sa_family is set correctly
5295 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5296 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
5297 int ifru_flags6 = 0;
5298
5299 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
5300 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
5301 {
5302 struct in6_ifreq ifr6;
5303 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
5304 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
5305 ifr6.ifr_addr = *sin6;
5306 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
5307 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
5308 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
5309 }
5310
5311 if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
5312 {
5313 if (ifa->ifa_flags & IFF_LOOPBACK)
5314 {
5315 if (ifa->ifa_addr->sa_family == AF_INET)
5316 v4Loopback = ifa;
5317 else if (sin6->sin6_addr.s6_addr[0] != 0xFD)
5318 v6Loopback = ifa;
5319 }
5320 else
5321 {
5322 NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
5323 if (i && MulticastInterface(i) && i->ifinfo.Advertise)
5324 {
5325 if (ifa->ifa_addr->sa_family == AF_INET)
5326 foundav4 = mDNStrue;
5327 else
5328 foundav6 = mDNStrue;
5329 }
5330 }
5331 }
5332 }
5333 }
5334 ifa = ifa->ifa_next;
5335 }
5336
5337 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
5338 if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
5339 if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
5340
5341 // Now the list is complete, set the McastTxRx setting for each interface.
5342 NetworkInterfaceInfoOSX *i;
5343 for (i = m->p->InterfaceList; i; i = i->next)
5344 if (i->Exists)
5345 {
5346 mDNSBool txrx = MulticastInterface(i);
5347 if (i->ifinfo.McastTxRx != txrx)
5348 {
5349 i->ifinfo.McastTxRx = txrx;
5350 i->Exists = 2; // State change; need to deregister and reregister this interface
5351 }
5352 }
5353
5354 if (InfoSocket >= 0)
5355 close(InfoSocket);
5356
5357 mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
5358 m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
5359
5360 // Set up the nice label
5361 domainlabel nicelabel;
5362 nicelabel.c[0] = 0;
5363 GetUserSpecifiedFriendlyComputerName(&nicelabel);
5364 if (nicelabel.c[0] == 0)
5365 {
5366 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
5367 MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
5368 }
5369
5370 // Set up the RFC 1034-compliant label
5371 domainlabel hostlabel;
5372 hostlabel.c[0] = 0;
5373 GetUserSpecifiedLocalHostName(&hostlabel);
5374 if (hostlabel.c[0] == 0)
5375 {
5376 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
5377 MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
5378 }
5379
5380 mDNSBool namechange = mDNSfalse;
5381
5382 // We use a case-sensitive comparison here because even though changing the capitalization
5383 // of the name alone is not significant to DNS, it's still a change from the user's point of view
5384 if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
5385 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
5386 else
5387 {
5388 if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
5389 LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
5390 m->p->usernicelabel = m->nicelabel = nicelabel;
5391 namechange = mDNStrue;
5392 }
5393
5394 if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
5395 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
5396 else
5397 {
5398 if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
5399 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
5400 m->p->userhostlabel = m->hostlabel = hostlabel;
5401 mDNS_SetFQDN(m);
5402 namechange = mDNStrue;
5403 }
5404
5405 #if APPLE_OSX_mDNSResponder
5406 if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
5407 {
5408 DomainAuthInfo *info;
5409 for (info = m->AuthInfoList; info; info = info->next)
5410 if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
5411 }
5412 #endif // APPLE_OSX_mDNSResponder
5413
5414 return(mStatus_NoError);
5415 }
5416
5417 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
5418 // Returns -1 if all the one-bits are not contiguous
5419 mDNSlocal int CountMaskBits(mDNSAddr *mask)
5420 {
5421 int i = 0, bits = 0;
5422 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
5423 while (i < bytes)
5424 {
5425 mDNSu8 b = mask->ip.v6.b[i++];
5426 while (b & 0x80) { bits++; b <<= 1; }
5427 if (b) return(-1);
5428 }
5429 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
5430 return(bits);
5431 }
5432
5433 // returns count of non-link local V4 addresses registered
5434 mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
5435 {
5436 NetworkInterfaceInfoOSX *i;
5437 int count = 0;
5438 for (i = m->p->InterfaceList; i; i = i->next)
5439 if (i->Exists)
5440 {
5441 NetworkInterfaceInfo *const n = &i->ifinfo;
5442 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC);
5443 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
5444
5445 if (i->Registered && i->Registered != primary) // Sanity check
5446 {
5447 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
5448 i->Registered = mDNSNULL;
5449 }
5450
5451 if (!i->Registered)
5452 {
5453 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5454 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5455 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it
5456 //
5457
5458 i->Registered = primary;
5459
5460 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
5461 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
5462 // 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.
5463 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
5464
5465 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
5466 // everytime it creates a new interface. We think it is a duplicate and hence consider it
5467 // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
5468 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
5469 // logs a warning message to system.log noting frequent interface transitions.
5470 // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
5471 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
5472 {
5473 LogInfo("SetupActiveInterfaces: %s interface registering %s %s", i->ifinfo.ifname,
5474 i->Flashing ? " (Flashing)" : "",
5475 i->Occulting ? " (Occulting)" : "");
5476 mDNS_RegisterInterface(m, n, 0);
5477 }
5478 else
5479 {
5480 mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
5481 }
5482
5483 if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
5484 LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5485 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary, &n->ip, CountMaskBits(&n->mask),
5486 i->Flashing ? " (Flashing)" : "",
5487 i->Occulting ? " (Occulting)" : "",
5488 n->InterfaceActive ? " (Primary)" : "");
5489
5490 if (!n->McastTxRx)
5491 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);
5492 else
5493 {
5494 if (i->sa_family == AF_INET)
5495 {
5496 struct ip_mreq imr;
5497 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
5498 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
5499 imr.imr_interface = primary->ifa_v4addr;
5500
5501 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
5502 // before trying to join the group, to clear out stale kernel state which may be lingering.
5503 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
5504 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
5505 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
5506 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
5507 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
5508 // because by the time we get the configuration change notification, the interface is already gone,
5509 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
5510 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
5511 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET) == i)
5512 {
5513 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);
5514 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
5515 if (err < 0 && (errno != EADDRNOTAVAIL))
5516 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
5517 }
5518
5519 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
5520 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
5521 // Joining same group twice can give "Address already in use" error -- no need to report that
5522 if (err < 0 && (errno != EADDRINUSE))
5523 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
5524 }
5525 if (i->sa_family == AF_INET6)
5526 {
5527 struct ipv6_mreq i6mr;
5528 i6mr.ipv6mr_interface = primary->scope_id;
5529 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
5530
5531 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET6) == i)
5532 {
5533 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);
5534 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
5535 if (err < 0 && (errno != EADDRNOTAVAIL))
5536 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5537 }
5538
5539 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5540 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
5541 // Joining same group twice can give "Address already in use" error -- no need to report that
5542 if (err < 0 && (errno != EADDRINUSE))
5543 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5544 }
5545 }
5546 }
5547 }
5548
5549 return count;
5550 }
5551
5552 mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
5553 {
5554 NetworkInterfaceInfoOSX *i;
5555 for (i = m->p->InterfaceList; i; i = i->next)
5556 {
5557 if (i->Exists) i->LastSeen = utc;
5558 i->Exists = mDNSfalse;
5559 }
5560 }
5561
5562 // returns count of non-link local V4 addresses deregistered
5563 mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
5564 {
5565 // First pass:
5566 // If an interface is going away, then deregister this from the mDNSCore.
5567 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
5568 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
5569 // it refers to has gone away we'll crash.
5570 NetworkInterfaceInfoOSX *i;
5571 int count = 0;
5572 for (i = m->p->InterfaceList; i; i = i->next)
5573 {
5574 // If this interface is no longer active, or its InterfaceID is changing, deregister it
5575 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC);
5576 if (i->Registered)
5577 if (i->Exists == 0 || i->Exists == 2 || i->Registered != primary)
5578 {
5579 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
5580 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5581 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary,
5582 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
5583 i->Flashing ? " (Flashing)" : "",
5584 i->Occulting ? " (Occulting)" : "",
5585 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5586
5587 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
5588 // everytime it creates a new interface. We think it is a duplicate and hence consider it
5589 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
5590 // stale data returned to the application even after the interface is removed. The application
5591 // then starts to send data but the new interface is not yet created.
5592 // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
5593 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
5594 {
5595 LogInfo("ClearInactiveInterfaces: %s interface deregistering %s %s", i->ifinfo.ifname,
5596 i->Flashing ? " (Flashing)" : "",
5597 i->Occulting ? " (Occulting)" : "");
5598 mDNS_DeregisterInterface(m, &i->ifinfo, 0);
5599 }
5600 else
5601 {
5602 mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
5603 }
5604 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
5605 i->Registered = mDNSNULL;
5606 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5607 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5608 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
5609
5610 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
5611 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
5612 }
5613 }
5614
5615 // Second pass:
5616 // Now that everything that's going to deregister has done so, we can clean up and free the memory
5617 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
5618 while (*p)
5619 {
5620 i = *p;
5621 // If no longer active, delete interface from list and free memory
5622 if (!i->Exists)
5623 {
5624 if (i->LastSeen == utc) i->LastSeen = utc - 1;
5625 mDNSBool delete = (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0) && (utc - i->LastSeen >= 60);
5626 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
5627 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
5628 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
5629 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5630 #if APPLE_OSX_mDNSResponder
5631 if (i->BPF_fd >= 0) CloseBPF(i);
5632 #endif // APPLE_OSX_mDNSResponder
5633 if (delete)
5634 {
5635 *p = i->next;
5636 freeL("NetworkInterfaceInfoOSX", i);
5637 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
5638 }
5639 }
5640 p = &i->next;
5641 }
5642 return count;
5643 }
5644
5645 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
5646 {
5647 DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
5648 if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
5649 else
5650 {
5651 dnle->next = mDNSNULL;
5652 dnle->uid = uid;
5653 AssignDomainName(&dnle->name, name);
5654 **List = dnle;
5655 *List = &dnle->next;
5656 }
5657 }
5658
5659 mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
5660 {
5661 dns_resolver_t *a = *(dns_resolver_t**)aa;
5662 dns_resolver_t *b = *(dns_resolver_t**)bb;
5663
5664 return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
5665 }
5666
5667 mDNSlocal void UpdateSearchDomainHash(mDNS *const m, MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID)
5668 {
5669 char *buf = ".";
5670 mDNSu32 scopeid = 0;
5671 char ifid_buf[16];
5672
5673 if (domain)
5674 buf = domain;
5675 //
5676 // Hash the search domain name followed by the InterfaceID.
5677 // As we have scoped search domains, we also included InterfaceID. If either of them change,
5678 // we will detect it. Even if the order of them change, we will detect it.
5679 //
5680 // Note: We have to handle a few of these tricky cases.
5681 //
5682 // 1) Current: com, apple.com Changing to: comapple.com
5683 // 2) Current: a.com,b.com Changing to a.comb.com
5684 // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
5685 // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
5686 //
5687 // There are more variants of the above. The key thing is if we include the null in each case
5688 // at the end of name and the InterfaceID, it will prevent a new name (which can't include
5689 // NULL as part of the name) to be mistakenly thought of as a old name.
5690
5691 scopeid = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
5692 // mDNS_snprintf always null terminates
5693 if (mDNS_snprintf(ifid_buf, sizeof(ifid_buf), "%u", scopeid) >= sizeof(ifid_buf))
5694 LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid);
5695
5696 LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf, ifid_buf);
5697 MD5_Update(sdc, buf, strlen(buf) + 1);
5698 MD5_Update(sdc, ifid_buf, strlen(ifid_buf) + 1);
5699 }
5700
5701 mDNSlocal void FinalizeSearchDomainHash(mDNS *const m, MD5_CTX *sdc)
5702 {
5703 mDNSu8 md5_hash[MD5_LEN];
5704
5705 MD5_Final(md5_hash, sdc);
5706
5707 if (memcmp(md5_hash, m->SearchDomainsHash, MD5_LEN))
5708 {
5709 // If the hash is different, either the search domains have changed or
5710 // the ordering between them has changed. Restart the questions that
5711 // would be affected by this.
5712 LogInfo("FinalizeSearchDomains: The hash is different");
5713 memcpy(m->SearchDomainsHash, md5_hash, MD5_LEN);
5714 RetrySearchDomainQuestions(m);
5715 }
5716 else { LogInfo("FinalizeSearchDomains: The hash is same"); }
5717 }
5718
5719 mDNSexport const char *DNSScopeToString(mDNSu32 scope)
5720 {
5721 switch (scope)
5722 {
5723 case kScopeNone:
5724 return "Unscoped";
5725 case kScopeInterfaceID:
5726 return "InterfaceScoped";
5727 case kScopeServiceID:
5728 return "ServiceScoped";
5729 default:
5730 return "Unknown";
5731 }
5732 }
5733
5734 mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNSInterfaceID interface, mDNSu32 scope, MD5_CTX *sdc)
5735 {
5736 const char *scopeString = DNSScopeToString(scope);
5737 int j;
5738
5739 if (scope != kScopeNone)
5740 {
5741 LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for Interface %p", scopeString, interface);
5742 return;
5743 }
5744 for (j = 0; j < resolver->n_search; j++)
5745 {
5746 LogInfo("ConfigSearchDomains: (%s) configuring search list %s", scopeString, resolver->search[j]);
5747 UpdateSearchDomainHash(m, sdc, resolver->search[j], NULL);
5748 mDNS_AddSearchDomain_CString(resolver->search[j], NULL);
5749 }
5750 }
5751
5752 mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNS *const m, mDNSu32 ifindex)
5753 {
5754 NetworkInterfaceInfoOSX *ni;
5755 mDNSInterfaceID interface;
5756
5757 for (ni = m->p->InterfaceList; ni; ni = ni->next)
5758 {
5759 if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex)
5760 break;
5761 }
5762 if (ni != NULL)
5763 {
5764 interface = ni->ifinfo.InterfaceID;
5765 }
5766 else
5767 {
5768 // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
5769 // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
5770 // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
5771 // As the caller is going to ack the configuration always, we have to add all the DNS servers
5772 // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
5773
5774 LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex);
5775
5776 // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
5777 interface = (mDNSInterfaceID)(unsigned long)ifindex;
5778 }
5779 return interface;
5780 }
5781
5782 mDNSlocal void ConfigNonUnicastResolver(mDNS *const m, dns_resolver_t *r)
5783 {
5784 char *opt = r->options;
5785 domainname d;
5786
5787 if (opt && !strncmp(opt, "mdns", strlen(opt)))
5788 {
5789 if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5790 {
5791 LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain);
5792 return;
5793 }
5794 mDNS_AddMcastResolver(m, &d, mDNSInterface_Any, r->timeout);
5795 }
5796 }
5797
5798 mDNSlocal void ConfigDNSServers(mDNS *const m, dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID)
5799 {
5800 int n;
5801 domainname d;
5802 int serviceID = 0;
5803 mDNSBool cellIntf = mDNSfalse;
5804 mDNSBool scopedDNS = mDNSfalse;
5805 mDNSBool reqA, reqAAAA;
5806
5807 if (!r->domain || !*r->domain)
5808 {
5809 d.c[0] = 0;
5810 }
5811 else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5812 {
5813 LogMsg("ConfigDNSServers: bad domain %s", r->domain);
5814 return;
5815 }
5816 // Parse the resolver specific attributes that affects all the DNS servers.
5817 if (scope == kScopeInterfaceID)
5818 {
5819 scopedDNS = mDNStrue;
5820 }
5821 else if (scope == kScopeServiceID)
5822 {
5823 serviceID = r->service_identifier;
5824 }
5825
5826 #if TARGET_OS_IPHONE
5827 cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
5828 #endif
5829 reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse);
5830 reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
5831
5832 for (n = 0; n < r->n_nameserver; n++)
5833 {
5834 mDNSAddr saddr;
5835 DNSServer *s;
5836
5837 if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6)
5838 continue;
5839
5840 if (SetupAddr(&saddr, r->nameserver[n]))
5841 {
5842 LogMsg("ConfigDNSServers: Bad address");
5843 continue;
5844 }
5845
5846 // The timeout value is for all the DNS servers in a given resolver, hence we pass
5847 // the timeout value only for the first DNSServer. If we don't have a value in the
5848 // resolver, then use the core's default value
5849 //
5850 // Note: this assumes that when the core picks a list of DNSServers for a question,
5851 // it takes the sum of all the timeout values for all DNS servers. By doing this, it
5852 // tries all the DNS servers in a specified timeout
5853 s = mDNS_AddDNSServer(m, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope,
5854 (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, resGroupID, reqA, reqAAAA, mDNStrue);
5855 if (s)
5856 {
5857 LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c);
5858 }
5859 }
5860 }
5861
5862 // ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
5863 // Service scope resolvers. This is indicated by the scope argument.
5864 //
5865 // "resolver" has entries that should only be used for unscoped questions.
5866 //
5867 // "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
5868 // interface index (q->InterfaceID)
5869 //
5870 // "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
5871 // a service identifier (q->ServiceID)
5872 //
5873 mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc, mDNSu16 resGroupID)
5874 {
5875 int i;
5876 dns_resolver_t **resolver;
5877 int nresolvers;
5878 const char *scopeString = DNSScopeToString(scope);
5879 mDNSInterfaceID interface;
5880
5881 switch (scope)
5882 {
5883 case kScopeNone:
5884 resolver = config->resolver;
5885 nresolvers = config->n_resolver;
5886 break;
5887 case kScopeInterfaceID:
5888 resolver = config->scoped_resolver;
5889 nresolvers = config->n_scoped_resolver;
5890 break;
5891 case kScopeServiceID:
5892 resolver = config->service_specific_resolver;
5893 nresolvers = config->n_service_specific_resolver;
5894 break;
5895 default:
5896 return;
5897 }
5898 qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
5899
5900 for (i = 0; i < nresolvers; i++)
5901 {
5902 dns_resolver_t *r = resolver[i];
5903
5904 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString, i, r->domain, r->n_nameserver);
5905
5906 interface = mDNSInterface_Any;
5907
5908 // Parse the interface index
5909 if (r->if_index != 0)
5910 {
5911 interface = ConfigParseInterfaceID(m, r->if_index);
5912 }
5913
5914 if (setsearch)
5915 {
5916 ConfigSearchDomains(m, resolver[i], interface, scope, sdc);
5917 // Parse other scoped resolvers for search lists
5918 if (!setservers)
5919 continue;
5920 }
5921
5922 if (r->port == 5353 || r->n_nameserver == 0)
5923 {
5924 ConfigNonUnicastResolver(m, r);
5925 }
5926 else
5927 {
5928 // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the
5929 // scoped resolver are not used by other non-scoped or scoped resolvers.
5930 if (scope != kScopeNone)
5931 resGroupID++;
5932
5933 ConfigDNSServers(m, r, interface, scope, resGroupID);
5934 }
5935 }
5936 }
5937
5938 #if APPLE_OSX_mDNSResponder
5939 mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
5940 {
5941 if (QuerySuppressed(q))
5942 {
5943 debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5944 return mDNSfalse;
5945 }
5946 if (mDNSOpaque16IsZero(q->TargetQID))
5947 {
5948 debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5949 return mDNSfalse;
5950 }
5951 // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
5952 // for trigger.
5953 if (q->LOAddressAnswers)
5954 {
5955 debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5956 return mDNSfalse;
5957 }
5958 return mDNStrue;
5959 }
5960 #endif
5961
5962 // This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
5963 // We set our state appropriately so that if we start receiving answers, trigger the
5964 // upper layer to retry DNS questions.
5965 #if APPLE_OSX_mDNSResponder
5966 mDNSexport void mDNSPlatformUpdateDNSStatus(mDNS *const m, DNSQuestion *q)
5967 {
5968 if (!QuestionValidForDNSTrigger(q))
5969 return;
5970
5971 // Ignore applications that start and stop queries for no reason before we ever talk
5972 // to any DNS server.
5973 if (!q->triedAllServersOnce)
5974 {
5975 LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q->qname.c, DNSTypeName(q->qtype));
5976 return;
5977 }
5978 if (q->qtype == kDNSType_A)
5979 m->p->v4answers = 0;
5980 if (q->qtype == kDNSType_AAAA)
5981 m->p->v6answers = 0;
5982 if (!m->p->v4answers || !m->p->v6answers)
5983 {
5984 LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, quesiton %##s (%s)", m->p->v4answers, m->p->v6answers, q->qname.c,
5985 DNSTypeName(q->qtype));
5986 }
5987 }
5988 #endif
5989
5990 mDNSlocal void AckConfigd(mDNS *const m, dns_config_t *config)
5991 {
5992 mDNS_CheckLock(m);
5993
5994 // Acking the configuration triggers configd to reissue the reachability queries
5995 m->p->DNSTrigger = NonZeroTime(m->timenow);
5996 _dns_configuration_ack(config, "com.apple.mDNSResponder");
5997 }
5998
5999 // If v4q is non-NULL, it means we have received some answers for "A" type questions
6000 // If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
6001 #if APPLE_OSX_mDNSResponder
6002 mDNSexport void mDNSPlatformTriggerDNSRetry(mDNS *const m, DNSQuestion *v4q, DNSQuestion *v6q)
6003 {
6004 mDNSBool trigger = mDNSfalse;
6005 mDNSs32 timenow;
6006
6007 // Don't send triggers too often.
6008 // If we have started delivering answers to questions, we should send a trigger
6009 // if the time permits. If we are delivering answers, we should set the state
6010 // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know
6011 // whether the answers that are being delivered currently is for configd or some
6012 // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
6013 // then we won't deliver the trigger later when it is okay to send one as the
6014 // "answers" are already set to 1. Hence, don't affect the state of v4answers and
6015 // v6answers if we are not delivering triggers.
6016 mDNS_Lock(m);
6017 timenow = m->timenow;
6018 if (m->p->DNSTrigger && (timenow - m->p->DNSTrigger) < DNS_TRIGGER_INTERVAL)
6019 {
6020 if (!m->p->v4answers || !m->p->v6answers)
6021 {
6022 debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
6023 (timenow - m->p->DNSTrigger), m->p->v4answers, m->p->v6answers);
6024 }
6025 mDNS_Unlock(m);
6026 return;
6027 }
6028 mDNS_Unlock(m);
6029 if (v4q != NULL && QuestionValidForDNSTrigger(v4q))
6030 {
6031 int old = m->p->v4answers;
6032
6033 m->p->v4answers = 1;
6034
6035 // If there are IPv4 answers now and previously we did not have
6036 // any answers, trigger a DNS change so that reachability
6037 // can retry the queries again.
6038 if (!old)
6039 {
6040 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
6041 v4q->qname.c, DNSTypeName(v4q->qtype));
6042 trigger = mDNStrue;
6043 }
6044 }
6045 if (v6q != NULL && QuestionValidForDNSTrigger(v6q))
6046 {
6047 int old = m->p->v6answers;
6048
6049 m->p->v6answers = 1;
6050 // If there are IPv6 answers now and previously we did not have
6051 // any answers, trigger a DNS change so that reachability
6052 // can retry the queries again.
6053 if (!old)
6054 {
6055 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
6056 v6q->qname.c, DNSTypeName(v6q->qtype));
6057 trigger = mDNStrue;
6058 }
6059 }
6060 if (trigger)
6061 {
6062 dns_config_t *config = dns_configuration_copy();
6063 if (config)
6064 {
6065 mDNS_Lock(m);
6066 AckConfigd(m, config);
6067 mDNS_Unlock(m);
6068 dns_configuration_free(config);
6069 }
6070 else
6071 {
6072 LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
6073 }
6074 }
6075 }
6076
6077 mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
6078 {
6079 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
6080 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
6081 if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver &&
6082 config->resolver[0]->nameserver[0])
6083 {
6084 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
6085 }
6086 else
6087 {
6088 ActiveDirectoryPrimaryDomain.c[0] = 0;
6089 }
6090
6091 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
6092 ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
6093 if (config->n_resolver && config->resolver[0]->n_nameserver &&
6094 SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
6095 {
6096 SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
6097 }
6098 else
6099 {
6100 AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
6101 ActiveDirectoryPrimaryDomainLabelCount = 0;
6102 ActiveDirectoryPrimaryDomainServer = zeroAddr;
6103 }
6104 }
6105 #endif
6106
6107 mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
6108 {
6109 int i;
6110 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6111 domainname d;
6112
6113 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SetupDDNSDomains"), NULL, NULL);
6114 if (!store)
6115 {
6116 LogMsg("SetupDDNSDomains: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6117 }
6118 else
6119 {
6120 CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
6121 if (ddnsdict)
6122 {
6123 if (fqdn)
6124 {
6125 CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
6126 if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
6127 {
6128 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
6129 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
6130 if (fqdnDict && DictionaryIsEnabled(fqdnDict))
6131 {
6132 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
6133 if (name)
6134 {
6135 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
6136 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
6137 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
6138 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
6139 }
6140 }
6141 }
6142 }
6143
6144 if (RegDomains)
6145 {
6146 CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
6147 if (regArray && CFArrayGetCount(regArray) > 0)
6148 {
6149 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
6150 if (regDict && DictionaryIsEnabled(regDict))
6151 {
6152 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
6153 if (name)
6154 {
6155 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
6156 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
6157 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
6158 else
6159 {
6160 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
6161 AppendDNameListElem(&RegDomains, 0, &d);
6162 }
6163 }
6164 }
6165 }
6166 }
6167
6168 if (BrowseDomains)
6169 {
6170 CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
6171 if (browseArray)
6172 {
6173 for (i = 0; i < CFArrayGetCount(browseArray); i++)
6174 {
6175 CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
6176 if (browseDict && DictionaryIsEnabled(browseDict))
6177 {
6178 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
6179 if (name)
6180 {
6181 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
6182 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
6183 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
6184 else
6185 {
6186 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
6187 AppendDNameListElem(&BrowseDomains, 0, &d);
6188 }
6189 }
6190 }
6191 }
6192 }
6193 }
6194 CFRelease(ddnsdict);
6195 }
6196
6197 if (RegDomains)
6198 {
6199 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
6200 if (btmm)
6201 {
6202 CFIndex size = CFDictionaryGetCount(btmm);
6203 const void *key[size];
6204 const void *val[size];
6205 CFDictionaryGetKeysAndValues(btmm, key, val);
6206 for (i = 0; i < size; i++)
6207 {
6208 LogInfo("BackToMyMac %d", i);
6209 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6210 LogMsg("Can't read BackToMyMac %d key %s", i, buf);
6211 else
6212 {
6213 mDNSu32 uid = atoi(buf);
6214 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6215 LogMsg("Can't read BackToMyMac %d val %s", i, buf);
6216 else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
6217 {
6218 LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
6219 AppendDNameListElem(&RegDomains, uid, &d);
6220 }
6221 }
6222 }
6223 CFRelease(btmm);
6224 }
6225 }
6226 CFRelease(store);
6227 }
6228 }
6229
6230 // Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
6231 mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
6232 DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
6233 {
6234 MD5_CTX sdc; // search domain context
6235 static mDNSu16 resolverGroupID = 0;
6236
6237 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
6238 if (fqdn ) fqdn->c[0] = 0;
6239 if (RegDomains ) *RegDomains = NULL;
6240 if (BrowseDomains) *BrowseDomains = NULL;
6241
6242 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
6243 setservers ? " setservers" : "",
6244 setsearch ? " setsearch" : "",
6245 fqdn ? " fqdn" : "",
6246 RegDomains ? " RegDomains" : "",
6247 BrowseDomains ? " BrowseDomains" : "");
6248
6249 if (setsearch) MD5_Init(&sdc);
6250
6251 // Add the inferred address-based configuration discovery domains
6252 // (should really be in core code I think, not platform-specific)
6253 if (setsearch)
6254 {
6255 struct ifaddrs *ifa = mDNSNULL;
6256 struct sockaddr_in saddr;
6257 mDNSPlatformMemZero(&saddr, sizeof(saddr));
6258 saddr.sin_len = sizeof(saddr);
6259 saddr.sin_family = AF_INET;
6260 saddr.sin_port = 0;
6261 saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
6262
6263 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
6264 if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1);
6265
6266 while (ifa)
6267 {
6268 mDNSAddr a, n;
6269 char buf[64];
6270
6271 if (ifa->ifa_addr->sa_family == AF_INET &&
6272 ifa->ifa_netmask &&
6273 !(ifa->ifa_flags & IFF_LOOPBACK) &&
6274 !SetupAddr(&a, ifa->ifa_addr) &&
6275 !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
6276 {
6277 // 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
6278 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
6279 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; // Make sure ifa_netmask->sa_family is set correctly
6280 SetupAddr(&n, ifa->ifa_netmask);
6281 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
6282 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
6283 a.ip.v4.b[2] & n.ip.v4.b[2],
6284 a.ip.v4.b[1] & n.ip.v4.b[1],
6285 a.ip.v4.b[0] & n.ip.v4.b[0]);
6286 UpdateSearchDomainHash(m, &sdc, buf, NULL);
6287 mDNS_AddSearchDomain_CString(buf, mDNSNULL);
6288 }
6289 ifa = ifa->ifa_next;
6290 }
6291 }
6292
6293 #ifndef MDNS_NO_DNSINFO
6294 if (setservers || setsearch)
6295 {
6296 dns_config_t *config = dns_configuration_copy();
6297 if (!config)
6298 {
6299 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
6300 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
6301 // Apparently this is expected behaviour -- "not a bug".
6302 // Accordingly, we suppress syslog messages for the first three minutes after boot.
6303 // If we are still getting failures after three minutes, then we log them.
6304 if ((mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
6305 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
6306 }
6307 else
6308 {
6309 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu", config->n_resolver, config->generation);
6310 // SameDomainName check below is to fix <rdar://problem/18059009> Dynamic DNS hostname changes not noticed
6311 if (m->p->LastConfigGeneration == config->generation && (!fqdn || (SameDomainName(fqdn, &m->FQDN))))
6312 {
6313 LogInfo("mDNSPlatformSetDNSConfig: generation number %llu same, not processing", config->generation);
6314 dns_configuration_free(config);
6315 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6316 return mDNSfalse;
6317 }
6318 #if APPLE_OSX_mDNSResponder
6319 SetupActiveDirectoryDomain(config);
6320 #endif
6321
6322 // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry
6323 // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need
6324 // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between
6325 // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the
6326 // same resolverGroupID.
6327 //
6328 // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally.
6329 ConfigResolvers(m, config, kScopeNone, setsearch, setservers, &sdc, ++resolverGroupID);
6330 resolverGroupID += config->n_resolver;
6331
6332 ConfigResolvers(m, config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID);
6333 resolverGroupID += config->n_scoped_resolver;
6334
6335 ConfigResolvers(m, config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID);
6336
6337 // Acking provides a hint that we processed this current configuration and
6338 // we will use that from now on, assuming we don't get another one immediately
6339 // after we return from here.
6340 if (ackConfig)
6341 {
6342 // Note: We have to set the generation number here when we are acking.
6343 // For every DNS configuration change, we do the following:
6344 //
6345 // 1) Copy dns configuration, handle search domains change
6346 // 2) Copy dns configuration, handle dns server change
6347 //
6348 // If we update the generation number at step (1), we won't process the
6349 // DNS servers the second time because generation number would be the same.
6350 // As we ack only when we process dns servers, we set the generation number
6351 // during acking.
6352 m->p->LastConfigGeneration = config->generation;
6353 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers, setsearch);
6354 AckConfigd(m, config);
6355 }
6356 dns_configuration_free(config);
6357 if (setsearch) FinalizeSearchDomainHash(m, &sdc);
6358 setservers = mDNSfalse; // Done these now -- no need to fetch the same data from SCDynamicStore
6359 setsearch = mDNSfalse;
6360 }
6361 }
6362 #endif // MDNS_NO_DNSINFO
6363 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6364 return mDNStrue;
6365 }
6366
6367
6368 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
6369 {
6370 char buf[256];
6371 (void)m; // Unused
6372
6373 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
6374 if (!store)
6375 LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6376 else
6377 {
6378 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_IPv4);
6379 if (dict)
6380 {
6381 r->type = mDNSAddrType_IPv4;
6382 r->ip.v4 = zerov4Addr;
6383 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
6384 if (string)
6385 {
6386 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
6387 LogMsg("Could not convert router to CString");
6388 else
6389 {
6390 struct sockaddr_in saddr;
6391 saddr.sin_len = sizeof(saddr);
6392 saddr.sin_family = AF_INET;
6393 saddr.sin_port = 0;
6394 inet_aton(buf, &saddr.sin_addr);
6395
6396 *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
6397 }
6398 }
6399
6400 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
6401 if (string)
6402 {
6403 mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
6404 struct ifaddrs *ifa = myGetIfAddrs(1);
6405
6406 *v4 = *v6 = zeroAddr;
6407
6408 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; }
6409
6410 // find primary interface in list
6411 while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
6412 {
6413 mDNSAddr tmp6 = zeroAddr;
6414 if (!strcmp(buf, ifa->ifa_name))
6415 {
6416 if (ifa->ifa_addr->sa_family == AF_INET)
6417 {
6418 if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr);
6419 }
6420 else if (ifa->ifa_addr->sa_family == AF_INET6)
6421 {
6422 SetupAddr(&tmp6, ifa->ifa_addr);
6423 if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
6424 { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; }
6425 }
6426 }
6427 else
6428 {
6429 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
6430 if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
6431 {
6432 SetupAddr(&tmp6, ifa->ifa_addr);
6433 if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6;
6434 }
6435 }
6436 ifa = ifa->ifa_next;
6437 }
6438
6439 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
6440 // V4 to communicate w/ our DNS server
6441 }
6442
6443 exit:
6444 CFRelease(dict);
6445 }
6446 CFRelease(store);
6447 }
6448 return mStatus_NoError;
6449 }
6450
6451 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
6452 {
6453 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
6454 char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6455 ConvertDomainNameToCString(dname, uname);
6456
6457 char *p = uname;
6458 while (*p)
6459 {
6460 *p = tolower(*p);
6461 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
6462 p++;
6463 }
6464
6465 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
6466 // That single entity is a CFDictionary with name "HostNames".
6467 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
6468 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
6469 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
6470 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
6471 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
6472
6473 const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
6474 const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
6475 const CFStringRef StatusKeys[1] = { CFSTR("Status") };
6476 if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
6477 else
6478 {
6479 const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
6480 if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
6481 else
6482 {
6483 const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6484 if (HostVals[0])
6485 {
6486 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6487 if (StateVals[0])
6488 {
6489 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6490 if (StateDict)
6491 {
6492 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
6493 CFRelease(StateDict);
6494 }
6495 CFRelease(StateVals[0]);
6496 }
6497 CFRelease(HostVals[0]);
6498 }
6499 CFRelease(StatusVals[0]);
6500 }
6501 CFRelease(HostKeys[0]);
6502 }
6503 }
6504
6505 #if APPLE_OSX_mDNSResponder
6506 #if !NO_AWACS
6507
6508 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
6509 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
6510 // help catch it
6511 mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
6512 {
6513 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
6514 if (!store)
6515 {
6516 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6517 return mDNSfalse;
6518 }
6519 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
6520 if (btmm)
6521 {
6522 CFIndex size = CFDictionaryGetCount(btmm);
6523 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6524 const void *key[size];
6525 const void *val[size];
6526 domainname dom;
6527 int i;
6528 CFDictionaryGetKeysAndValues(btmm, key, val);
6529 for (i = 0; i < size; i++)
6530 {
6531 LogInfo("BackToMyMac %d", i);
6532 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6533 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
6534 else
6535 {
6536 mDNSu32 uid = atoi(buf);
6537 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6538 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
6539 else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
6540 {
6541 if (SameDomainName(&dom, d))
6542 {
6543 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
6544 CFRelease(btmm);
6545 CFRelease(store);
6546 return mDNStrue;
6547 }
6548 }
6549 }
6550 }
6551 CFRelease(btmm);
6552 }
6553 CFRelease(store);
6554 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
6555 return mDNSfalse;
6556 }
6557
6558 // Appends data to the buffer
6559 mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
6560 {
6561 int len;
6562
6563 len = strlcpy(buf + *currlen, data, bufsz - *currlen);
6564 if (len >= (bufsz - *currlen))
6565 {
6566 // if we have exceeded the space in buf, it has already been NULL terminated
6567 // and we have nothing more to do. Set currlen to the last byte so that the caller
6568 // knows to do the right thing
6569 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
6570 *currlen = bufsz - 1;
6571 return -1;
6572 }
6573 else { (*currlen) += len; }
6574
6575 buf[*currlen] = ',';
6576 if (*currlen >= bufsz)
6577 {
6578 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
6579 *currlen = bufsz - 1;
6580 buf[*currlen] = 0;
6581 return -1;
6582 }
6583 // if we have filled up the buffer exactly, then there is no more work to do
6584 if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
6585 (*currlen)++;
6586 return *currlen;
6587 }
6588
6589 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
6590 // BTMM domains, then bring down the connection to the relay.
6591 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6592 {
6593 DomainAuthInfo *BTMMDomain = mDNSNULL;
6594 DomainAuthInfo *FoundInList;
6595 static mDNSBool AWACSDConnected = mDNSfalse;
6596 char AllUsers[1024]; // maximum size of mach message
6597 char AllPass[1024]; // maximum size of mach message
6598 char username[MAX_DOMAIN_LABEL + 1];
6599 int currulen = 0;
6600 int currplen = 0;
6601
6602 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
6603 // we may not be able to send the dns queries over the relay connection which may be needed
6604 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
6605 // need to make sure that we send the disconnect before attempting the next connect as the
6606 // awacs connections are redirected based on usernames.
6607 //
6608 // For now we send a disconnect immediately. When we start sending dns queries over the relay
6609 // connection, we will need to fix this.
6610
6611 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6612 if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
6613 {
6614 // We need the passwd from the first domain.
6615 BTMMDomain = FoundInList;
6616 ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
6617 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
6618 if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
6619 if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
6620 }
6621
6622 if (BTMMDomain)
6623 {
6624 // In the normal case (where we neither exceed the buffer size nor write bytes that
6625 // fit exactly into the buffer), currulen/currplen should be a different size than
6626 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
6627
6628 if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
6629 if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
6630
6631 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
6632 AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
6633 AWACSDConnected = mDNStrue;
6634 }
6635 else
6636 {
6637 // Disconnect only if we connected previously
6638 if (AWACSDConnected)
6639 {
6640 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
6641 AWACS_Disconnect();
6642 AWACSDConnected = mDNSfalse;
6643 }
6644 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
6645 }
6646 }
6647 #else
6648 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6649 {
6650 (void) m; // Unused
6651 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
6652 }
6653 #endif // ! NO_AWACS
6654
6655 mDNSlocal void ProcessConndConfigChanges(mDNS *const m);
6656
6657 #endif // APPLE_OSX_mDNSResponder
6658
6659 // MUST be called holding the lock
6660 mDNSexport void SetDomainSecrets(mDNS *m)
6661 {
6662 #ifdef NO_SECURITYFRAMEWORK
6663 (void) m;
6664 LogMsg("Note: SetDomainSecrets: no keychain support");
6665 #else
6666 mDNSBool haveAutoTunnels = mDNSfalse;
6667
6668 LogInfo("SetDomainSecrets");
6669
6670 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
6671 // In the case where the user simultaneously removes their DDNS host name and the key
6672 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
6673 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
6674 // address records behind that we no longer have permission to delete.
6675 DomainAuthInfo *ptr;
6676 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
6677 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
6678
6679 #if APPLE_OSX_mDNSResponder
6680 {
6681 // Mark all TunnelClients for deletion
6682 ClientTunnel *client;
6683 for (client = m->TunnelClients; client; client = client->next)
6684 {
6685 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
6686 client->MarkedForDeletion = mDNStrue;
6687 }
6688 }
6689 #endif // APPLE_OSX_mDNSResponder
6690
6691 // String Array used to write list of private domains to Dynamic Store
6692 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6693 if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
6694 CFIndex i;
6695 CFDataRef data = NULL;
6696 const int itemsPerEntry = 4; // domain name, key name, key value, Name value
6697 CFArrayRef secrets = NULL;
6698 int err = mDNSKeychainGetSecrets(&secrets);
6699 if (err || !secrets)
6700 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
6701 else
6702 {
6703 CFIndex ArrayCount = CFArrayGetCount(secrets);
6704 // Iterate through the secrets
6705 for (i = 0; i < ArrayCount; ++i)
6706 {
6707 mDNSBool AutoTunnel;
6708 int j, offset;
6709 CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
6710 if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
6711 { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i, itemsPerEntry); continue; }
6712 for (j = 0; j < CFArrayGetCount(entry); ++j)
6713 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
6714 { LogMsg("SetDomainSecrets: malformed entry item %d", j); continue; }
6715
6716 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
6717
6718 // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
6719 // Get DNS domain this key is for (kmDNSKcWhere)
6720 char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(btmmprefix)];
6721 data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere);
6722 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6723 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
6724 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6725 stringbuf[CFDataGetLength(data)] = '\0';
6726
6727 AutoTunnel = mDNSfalse;
6728 offset = 0;
6729 if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
6730 offset = strlen(dnsprefix);
6731 else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix)))
6732 {
6733 AutoTunnel = mDNStrue;
6734 offset = strlen(btmmprefix);
6735 }
6736 domainname domain;
6737 if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
6738
6739 // Get key name (kmDNSKcAccount)
6740 data = CFArrayGetValueAtIndex(entry, kmDNSKcAccount);
6741 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6742 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
6743 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
6744 stringbuf[CFDataGetLength(data)] = '\0';
6745
6746 domainname keyname;
6747 if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
6748
6749 // Get key data (kmDNSKcKey)
6750 data = CFArrayGetValueAtIndex(entry, kmDNSKcKey);
6751 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6752 {
6753 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data));
6754 continue;
6755 }
6756 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6757 stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
6758
6759 // Get the Name of the keychain entry (kmDNSKcName) host or host:port
6760 // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
6761 char hostbuf[MAX_ESCAPED_DOMAIN_NAME + 6]; // Max legal domainname as C-string, including terminating NUL
6762 data = CFArrayGetValueAtIndex(entry, kmDNSKcName);
6763 if (CFDataGetLength(data) >= (int)sizeof(hostbuf))
6764 {
6765 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data));
6766 continue;
6767 }
6768 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)hostbuf);
6769 hostbuf[CFDataGetLength(data)] = '\0';
6770
6771 domainname hostname;
6772 mDNSIPPort port;
6773 char *hptr;
6774 hptr = strchr(hostbuf, ':');
6775
6776 port.NotAnInteger = 0;
6777 if (hptr)
6778 {
6779 mDNSu8 *p;
6780 mDNSu16 val = 0;
6781
6782 *hptr++ = '\0';
6783 while(hptr && *hptr != 0)
6784 {
6785 if (*hptr < '0' || *hptr > '9')
6786 { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr, val); val = 0; break;}
6787 val = val * 10 + *hptr - '0';
6788 hptr++;
6789 }
6790 if (!val) continue;
6791 p = (mDNSu8 *)&val;
6792 port.NotAnInteger = p[0] << 8 | p[1];
6793 }
6794 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
6795 hptr = strchr(hostbuf, '@');
6796 if (hptr)
6797 hptr++;
6798 else
6799 hptr = hostbuf;
6800 if (!MakeDomainNameFromDNSNameString(&hostname, hptr)) { LogMsg("SetDomainSecrets: bad host name %s", hptr); continue; }
6801
6802 DomainAuthInfo *FoundInList;
6803 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6804 if (SameDomainName(&FoundInList->domain, &domain)) break;
6805
6806 #if APPLE_OSX_mDNSResponder
6807 if (FoundInList)
6808 {
6809 // If any client tunnel destination is in this domain, set deletion flag to false
6810 ClientTunnel *client;
6811 for (client = m->TunnelClients; client; client = client->next)
6812 if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
6813 {
6814 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
6815 client->MarkedForDeletion = mDNSfalse;
6816 }
6817 }
6818
6819 #endif // APPLE_OSX_mDNSResponder
6820
6821 // Uncomment the line below to view the keys as they're read out of the system keychain
6822 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
6823 //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]));
6824 LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain.c, &keyname.c, hostname.c, (port.b[0] << 8 | port.b[1]));
6825
6826 // If didn't find desired domain in the list, make a new entry
6827 ptr = FoundInList;
6828 if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
6829 if (!FoundInList)
6830 {
6831 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
6832 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
6833 }
6834
6835 //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
6836
6837 // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
6838 if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port, AutoTunnel) == mStatus_BadParamErr)
6839 {
6840 if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
6841 continue;
6842 }
6843
6844 ConvertDomainNameToCString(&domain, stringbuf);
6845 CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
6846 if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
6847 }
6848 CFRelease(secrets);
6849 }
6850
6851 if (!privateDnsArray || !CFEqual(privateDnsArray, sa))
6852 {
6853 if (privateDnsArray)
6854 CFRelease(privateDnsArray);
6855
6856 privateDnsArray = sa;
6857 CFRetain(privateDnsArray);
6858 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
6859 }
6860 CFRelease(sa);
6861
6862 #if APPLE_OSX_mDNSResponder
6863 {
6864 // clean up ClientTunnels
6865 ClientTunnel **pp = &m->TunnelClients;
6866 while (*pp)
6867 {
6868 if ((*pp)->MarkedForDeletion)
6869 {
6870 ClientTunnel *cur = *pp;
6871 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
6872 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
6873 AutoTunnelSetKeys(cur, mDNSfalse);
6874 *pp = cur->next;
6875 freeL("ClientTunnel", cur);
6876 }
6877 else
6878 pp = &(*pp)->next;
6879 }
6880
6881 mDNSBool needAutoTunnelNAT = mDNSfalse;
6882 DomainAuthInfo *info;
6883 for (info = m->AuthInfoList; info; info = info->next)
6884 {
6885 if (info->AutoTunnel)
6886 {
6887 UpdateAutoTunnelDeviceInfoRecord(m, info);
6888 UpdateAutoTunnelHostRecord(m, info);
6889 UpdateAutoTunnelServiceRecords(m, info);
6890 UpdateAutoTunnel6Record(m, info);
6891 if (info->deltime)
6892 {
6893 if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse;
6894 }
6895 else if (info->AutoTunnelServiceStarted)
6896 needAutoTunnelNAT = true;
6897
6898 UpdateAutoTunnelDomainStatus(m, info);
6899 }
6900 }
6901
6902 // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
6903 if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext)
6904 {
6905 // stop the NAT operation, reset port, cleanup state
6906 mDNS_StopNATOperation_internal(m, &m->AutoTunnelNAT);
6907 m->AutoTunnelNAT.ExternalAddress = zerov4Addr;
6908 m->AutoTunnelNAT.NewAddress = zerov4Addr;
6909 m->AutoTunnelNAT.ExternalPort = zeroIPPort;
6910 m->AutoTunnelNAT.RequestedPort = zeroIPPort;
6911 m->AutoTunnelNAT.Lifetime = 0;
6912 m->AutoTunnelNAT.Result = mStatus_NoError;
6913 m->AutoTunnelNAT.clientContext = mDNSNULL;
6914 }
6915
6916 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
6917 ProcessConndConfigChanges(m); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
6918 }
6919 #endif // APPLE_OSX_mDNSResponder
6920
6921 CheckSuppressUnusableQuestions(m);
6922
6923 #endif /* NO_SECURITYFRAMEWORK */
6924 }
6925
6926 mDNSlocal void SetLocalDomains(void)
6927 {
6928 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6929 if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
6930
6931 CFArrayAppendValue(sa, CFSTR("local"));
6932 CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
6933 CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
6934 CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
6935 CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
6936 CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
6937
6938 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
6939 CFRelease(sa);
6940 }
6941
6942 mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
6943 {
6944 #if USE_IOPMCOPYACTIVEPMPREFERENCES
6945 CFTypeRef blob = NULL;
6946 CFStringRef str = NULL;
6947 CFDictionaryRef odict = NULL;
6948 CFDictionaryRef idict = NULL;
6949 CFNumberRef number = NULL;
6950
6951 blob = IOPSCopyPowerSourcesInfo();
6952 if (!blob) { LogMsg("GetCurrentPMSetting: IOPSCopyPowerSourcesInfo failed!"); goto end; }
6953
6954 odict = IOPMCopyActivePMPreferences();
6955 if (!odict) { LogMsg("GetCurrentPMSetting: IOPMCopyActivePMPreferences failed!"); goto end; }
6956
6957 str = IOPSGetProvidingPowerSourceType(blob);
6958 if (!str) { LogMsg("GetCurrentPMSetting: IOPSGetProvidingPowerSourceType failed!"); goto end; }
6959
6960 idict = CFDictionaryGetValue(odict, str);
6961 if (!idict)
6962 {
6963 char buf[256];
6964 if (!CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
6965 LogMsg("GetCurrentPMSetting: CFDictionaryGetValue (%s) failed!", buf);
6966 goto end;
6967 }
6968
6969 number = CFDictionaryGetValue(idict, name);
6970 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
6971 *val = 0;
6972 end:
6973 if (blob) CFRelease(blob);
6974 if (odict) CFRelease(odict);
6975
6976 #else
6977
6978 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetCurrentPMSetting"), NULL, NULL);
6979 if (!store) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6980 else
6981 {
6982 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
6983 if (!dict) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
6984 else
6985 {
6986 CFNumberRef number = CFDictionaryGetValue(dict, name);
6987 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
6988 *val = 0;
6989 CFRelease(dict);
6990 }
6991 CFRelease(store);
6992 }
6993
6994 #endif
6995 }
6996
6997 #if APPLE_OSX_mDNSResponder
6998
6999 static CFMutableDictionaryRef spsStatusDict = NULL;
7000 static const CFStringRef kMetricRef = CFSTR("Metric");
7001
7002 mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
7003 {
7004 mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
7005 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
7006 if (!num)
7007 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
7008 else
7009 {
7010 CFDictionarySetValue(dict, key, num);
7011 CFRelease(num);
7012 }
7013 }
7014
7015 mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
7016 {
7017 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
7018 if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
7019
7020 char buffer[1024];
7021 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
7022 CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
7023 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
7024 CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
7025 CFRelease(spsname);
7026
7027 if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
7028 if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
7029 if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
7030 if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
7031
7032 mDNSu32 tmp = SPSMetric(ptr);
7033 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
7034 if (!num)
7035 LogMsg("SPSCreateDict: Could not create CFNumber");
7036 else
7037 {
7038 CFDictionarySetValue(dict, kMetricRef, num);
7039 CFRelease(num);
7040 }
7041
7042 if (ptr[0] >= 12)
7043 {
7044 memcpy(buffer, ptr + 13, ptr[0] - 12);
7045 buffer[ptr[0] - 12] = 0;
7046 spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
7047 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
7048 else
7049 {
7050 CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
7051 CFRelease(spsname);
7052 }
7053 }
7054
7055 return dict;
7056 }
7057
7058 mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
7059 {
7060 (void)context;
7061 return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
7062 (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
7063 NULL);
7064 }
7065
7066 mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
7067 {
7068 NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
7069 debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
7070
7071 mDNS_Lock(m);
7072 mDNS_UpdateAllowSleep(m);
7073 mDNS_Unlock(m);
7074
7075 if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names
7076
7077 if (!spsStatusDict)
7078 {
7079 spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
7080 if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
7081 }
7082
7083 CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
7084 if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
7085
7086 CFMutableArrayRef array = NULL;
7087
7088 if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
7089 {
7090 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7091 if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
7092 CFDictionarySetValue(spsStatusDict, ifname, array);
7093 CFRelease(array); // let go of our reference, now that the dict has one
7094 }
7095 else
7096 if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
7097
7098 if (!answer) // special call that means the question has been stopped (because the interface is going away)
7099 CFArrayRemoveAllValues(array);
7100 else
7101 {
7102 CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
7103 if (!dict) { CFRelease(ifname); return; }
7104
7105 if (AddRecord)
7106 {
7107 if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
7108 {
7109 int i=0;
7110 for (i=0; i<CFArrayGetCount(array); i++)
7111 if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
7112 break;
7113 CFArrayInsertValueAtIndex(array, i, dict);
7114 }
7115 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
7116 }
7117 else
7118 {
7119 CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
7120 if (i != -1) CFArrayRemoveValueAtIndex(array, i);
7121 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
7122 }
7123
7124 CFRelease(dict);
7125 }
7126
7127 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
7128
7129 CFRelease(ifname);
7130 }
7131
7132 mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
7133 {
7134 mDNSs32 val = -1;
7135 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
7136 if (!store)
7137 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
7138 else
7139 {
7140 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
7141 if (dict)
7142 {
7143 CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
7144 if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
7145 CFRelease(dict);
7146 }
7147 CFRelease(store);
7148 }
7149 return val;
7150 }
7151
7152 mDNSlocal void SetSPS(mDNS *const m)
7153 {
7154
7155 // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
7156 mDNSu8 sps = (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware : 0;
7157
7158 // For devices that are not running NAT, but are set to never sleep, we may choose to act
7159 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
7160 //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
7161
7162 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
7163
7164 // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
7165 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
7166 // We rate such a device as metric 70 ("Incidentally Available Hardware")
7167 if (SPMetricMarginalPower <= 60 && !sps) sps = mDNSSleepProxyMetric_IncidentalHardware;
7168
7169 // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
7170 // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
7171 if (sps && OfferSleepProxyService && OfferSleepProxyService < 100) sps = OfferSleepProxyService;
7172
7173 #ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI
7174 // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active.
7175 if (IsAppleTV())
7176 {
7177 NetworkInterfaceInfo *intf = mDNSNULL;
7178 mDNSEthAddr bssid = zeroEthAddr;
7179 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
7180 {
7181 bssid = GetBSSID(intf->ifname);
7182 if (!mDNSSameEthAddress(&bssid, &zeroEthAddr))
7183 {
7184 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
7185 sps = 0;
7186 break;
7187 }
7188 }
7189 }
7190 #endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI
7191
7192 mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
7193 }
7194
7195 // The definitions below should eventually come from some externally-supplied header file.
7196 // However, since these definitions can't really be changed without breaking binary compatibility,
7197 // they should never change, so in practice it should not be a big problem to have them defined here.
7198
7199 enum
7200 { // commands from the daemon to the driver
7201 cmd_mDNSOffloadRR = 21, // give the mdns update buffer to the driver
7202 };
7203
7204 typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr;
7205
7206 typedef struct
7207 { // cmd_mDNSOffloadRR structure
7208 uint32_t command; // set to OffloadRR
7209 uint32_t rrBufferSize; // number of bytes of RR records
7210 uint32_t numUDPPorts; // number of SRV UDP ports
7211 uint32_t numTCPPorts; // number of SRV TCP ports
7212 uint32_t numRRRecords; // number of RR records
7213 uint32_t compression; // rrRecords - compression is base for compressed strings
7214 FatPtr rrRecords; // address of array of pointers to the rr records
7215 FatPtr udpPorts; // address of udp port list (SRV)
7216 FatPtr tcpPorts; // address of tcp port list (SRV)
7217 } mDNSOffloadCmd;
7218
7219 #include <IOKit/IOKitLib.h>
7220 #include <dns_util.h>
7221
7222 mDNSlocal mDNSu16 GetPortArray(mDNS *const m, int trans, mDNSIPPort *portarray)
7223 {
7224 const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
7225 int count = 0;
7226 AuthRecord *rr;
7227 for (rr = m->ResourceRecords; rr; rr=rr->next)
7228 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c))
7229 {
7230 if (portarray) portarray[count] = rr->resrec.rdata->u.srv.port;
7231 count++;
7232 }
7233
7234 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
7235 if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext)
7236 {
7237 LogSPS("GetPortArray Back to My Mac at %d", count);
7238 if (portarray) portarray[count] = IPSECPort;
7239 count++;
7240 }
7241 return(count);
7242 }
7243
7244 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7245 mDNSlocal mDNSBool SupportsTCPKeepAlive()
7246 {
7247 IOReturn ret = kIOReturnSuccess;
7248 CFTypeRef obj = NULL;
7249 mDNSBool supports = mDNSfalse;
7250
7251 ret = IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj);
7252 if ((kIOReturnSuccess == ret) && (obj != NULL))
7253 {
7254 supports = (obj == kCFBooleanTrue)? mDNStrue : mDNSfalse;
7255 CFRelease(obj);
7256 }
7257 LogSPS("%s: The hardware %s TCP Keep Alive", __func__, (supports ? "supports" : "does not support"));
7258 return supports;
7259 }
7260
7261 mDNSlocal mDNSBool OnBattery(void)
7262 {
7263 CFTypeRef powerInfo = IOPSCopyPowerSourcesInfo();
7264 CFTypeRef powerSrc = IOPSGetProvidingPowerSourceType(powerInfo);
7265 mDNSBool result = mDNSfalse;
7266
7267 if (powerInfo != NULL)
7268 {
7269 result = CFEqual(CFSTR(kIOPSBatteryPowerValue), powerSrc);
7270 CFRelease(powerInfo);
7271 }
7272 LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
7273 return result;
7274 }
7275
7276 #endif // !TARGET_OS_EMBEDDED
7277
7278 #define TfrRecordToNIC(RR) \
7279 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
7280
7281 mDNSlocal mDNSu32 CountProxyRecords(mDNS *const m, uint32_t *const numbytes, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
7282 {
7283 *numbytes = 0;
7284 int count = 0;
7285
7286 AuthRecord *rr;
7287
7288 for (rr = m->ResourceRecords; rr; rr=rr->next)
7289 {
7290 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
7291 {
7292 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7293 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
7294 // Skip over all other records if we are registering TCP KeepAlive records only
7295 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
7296 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
7297 continue;
7298
7299 // Update the record before calculating the number of bytes required
7300 // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
7301 // attempt to update the record again.
7302 if (isKeepAliveRecord && (UpdateKeepaliveRData(m, rr, intf, mDNSfalse, mDNSNULL) != mStatus_NoError))
7303 LogSPS("CountProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m, rr));
7304 #else
7305 (void) TCPKAOnly; // unused
7306 (void) supportsTCPKA; // unused
7307 (void) intf; // unused
7308 #endif // APPLE_OSX_mDNSResponder
7309 if (TfrRecordToNIC(rr))
7310 {
7311 *numbytes += DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate;
7312 LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
7313 count, DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate, *numbytes, ARDisplayString(m,rr));
7314 count++;
7315 }
7316 }
7317 }
7318 return(count);
7319 }
7320
7321 mDNSlocal void GetProxyRecords(mDNS *const m, DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
7322 {
7323 mDNSu8 *p = msg->data;
7324 const mDNSu8 *const limit = p + *numbytes;
7325 InitializeDNSMessage(&msg->h, zeroID, zeroID);
7326
7327 int count = 0;
7328 AuthRecord *rr;
7329
7330 for (rr = m->ResourceRecords; rr; rr=rr->next)
7331 {
7332 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
7333 {
7334 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7335 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
7336
7337 // Skip over all other records if we are registering TCP KeepAlive records only
7338 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
7339 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
7340 continue;
7341 #else
7342 (void) TCPKAOnly; // unused
7343 (void) supportsTCPKA; // unused
7344 #endif // APPLE_OSX_mDNSResponder
7345
7346 if (TfrRecordToNIC(rr))
7347 {
7348 records[count].sixtyfourbits = zeroOpaque64;
7349 records[count].ptr = p;
7350 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
7351 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it
7352 p = PutResourceRecordTTLWithLimit(msg, p, &msg->h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
7353 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state
7354 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
7355 count, records[count].ptr, p, p - (mDNSu8 *)records[count].ptr, p - msg->data, ARDisplayString(m,rr));
7356 count++;
7357 }
7358 }
7359 }
7360 *numbytes = p - msg->data;
7361 }
7362
7363 // If compiling with old headers and libraries (pre 10.5) that don't include IOConnectCallStructMethod
7364 // then we declare a dummy version here so that the code at least compiles
7365 #ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
7366 static kern_return_t
7367 IOConnectCallStructMethod(
7368 mach_port_t connection, // In
7369 uint32_t selector, // In
7370 const void *inputStruct, // In
7371 size_t inputStructCnt, // In
7372 void *outputStruct, // Out
7373 size_t *outputStructCnt) // In/Out
7374 {
7375 (void)connection;
7376 (void)selector;
7377 (void)inputStruct;
7378 (void)inputStructCnt;
7379 (void)outputStruct;
7380 (void)outputStructCnt;
7381 LogMsg("Compiled without IOConnectCallStructMethod");
7382 return(KERN_FAILURE);
7383 }
7384 #endif
7385
7386 mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf)
7387 {
7388 if(!UseInternalSleepProxy)
7389 {
7390 LogSPS("SupportsInNICProxy: Internal Sleep Proxy is disabled");
7391 return mDNSfalse;
7392 }
7393 return CheckInterfaceSupport(intf, mDNS_IOREG_KEY);
7394 }
7395
7396 mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const intf) // Called with the lock held
7397 {
7398 mStatus result = mStatus_UnknownErr;
7399 mDNSBool TCPKAOnly = mDNSfalse;
7400 mDNSBool supportsTCPKA = mDNSfalse;
7401 mDNSBool onbattery = mDNSfalse;
7402 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
7403
7404 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7405 onbattery = OnBattery();
7406 // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
7407 supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive());
7408
7409 // Only TCP Keepalive records are to be offloaded if
7410 // - The system is on battery
7411 // - OR wake for network access is not set but powernap is enabled
7412 TCPKAOnly = supportsTCPKA && ((m->SystemWakeOnLANEnabled == mDNS_WakeOnBattery) || onbattery);
7413 #else
7414 (void) onbattery; // unused;
7415 #endif
7416 if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", intf->ifname); return(mStatus_UnknownErr); }
7417
7418 io_name_t n1, n2;
7419 IOObjectGetClass(service, n1);
7420 io_object_t parent;
7421 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
7422 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
7423 else
7424 {
7425 IOObjectGetClass(parent, n2);
7426 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf->ifname, n1, n2);
7427 const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
7428 if (!ref) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
7429 else
7430 {
7431 if (CFGetTypeID(ref) != CFStringGetTypeID() || !CFEqual(ref, CFSTR(mDNS_IOREG_VALUE)))
7432 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
7433 intf->ifname, n1, n2, CFStringGetCStringPtr(ref, mDNSNULL), mDNS_IOREG_VALUE);
7434 else if (!UseInternalSleepProxy)
7435 LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf->ifname);
7436 else
7437 {
7438 io_connect_t conObj;
7439 kr = IOServiceOpen(parent, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE, &conObj);
7440 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf->ifname, n1, n2, kr);
7441 else
7442 {
7443 mDNSOffloadCmd cmd;
7444 mDNSPlatformMemZero(&cmd, sizeof(cmd)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
7445 cmd.command = cmd_mDNSOffloadRR;
7446 cmd.numUDPPorts = GetPortArray(m, mDNSTransport_UDP, mDNSNULL);
7447 cmd.numTCPPorts = GetPortArray(m, mDNSTransport_TCP, mDNSNULL);
7448 cmd.numRRRecords = CountProxyRecords(m, &cmd.rrBufferSize, intf, TCPKAOnly, supportsTCPKA);
7449 cmd.compression = sizeof(DNSMessageHeader);
7450
7451 DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
7452 cmd.rrRecords.ptr = mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr));
7453 cmd.udpPorts.ptr = mallocL("mDNSOffloadCmd udpPorts", cmd.numUDPPorts * sizeof(mDNSIPPort));
7454 cmd.tcpPorts.ptr = mallocL("mDNSOffloadCmd tcpPorts", cmd.numTCPPorts * sizeof(mDNSIPPort));
7455
7456 LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
7457 msg, cmd.rrBufferSize,
7458 cmd.rrRecords.ptr, cmd.numRRRecords,
7459 cmd.udpPorts.ptr, cmd.numUDPPorts,
7460 cmd.tcpPorts.ptr, cmd.numTCPPorts);
7461
7462 if (!msg || !cmd.rrRecords.ptr || !cmd.udpPorts.ptr || !cmd.tcpPorts.ptr)
7463 LogMsg("ActivateLocalProxy: Failed to allocate memory: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
7464 msg, cmd.rrBufferSize,
7465 cmd.rrRecords.ptr, cmd.numRRRecords,
7466 cmd.udpPorts.ptr, cmd.numUDPPorts,
7467 cmd.tcpPorts.ptr, cmd.numTCPPorts);
7468 else
7469 {
7470 GetProxyRecords(m, msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA);
7471 GetPortArray(m, mDNSTransport_UDP, cmd.udpPorts.ptr);
7472 GetPortArray(m, mDNSTransport_TCP, cmd.tcpPorts.ptr);
7473 char outputData[2];
7474 size_t outputDataSize = sizeof(outputData);
7475 kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize);
7476 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr);
7477 if (kr == KERN_SUCCESS) result = mStatus_NoError;
7478 }
7479
7480 if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts.ptr);
7481 if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts.ptr);
7482 if (cmd.rrRecords.ptr) freeL("mDNSOffloadCmd rrRecords", cmd.rrRecords.ptr);
7483 if (msg) freeL("mDNSOffloadCmd msg", msg);
7484 IOServiceClose(conObj);
7485 }
7486 }
7487 CFRelease(ref);
7488 }
7489 IOObjectRelease(parent);
7490 }
7491 IOObjectRelease(service);
7492 return result;
7493 }
7494
7495 #endif // APPLE_OSX_mDNSResponder
7496
7497 mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
7498 {
7499 mDNSs32 val = 0;
7500 mDNSu8 ret = (mDNSu8)mDNS_NoWake;
7501
7502 if (DisableSleepProxyClient)
7503 {
7504 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7505 return mDNSfalse;
7506 }
7507
7508 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
7509
7510 ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
7511
7512 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7513 // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
7514 // Further policy decisions on whether to offload the records is handled during sleep processing.
7515 if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive())
7516 ret = (mDNSu8)mDNS_WakeOnBattery;
7517 #endif // APPLE_OSX_mDNSResponder
7518
7519 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret);
7520 return ret;
7521 }
7522
7523 mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
7524 {
7525 mDNSs32 val = 0;
7526 GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
7527 return val != 0 ? mDNStrue : mDNSfalse;
7528 }
7529
7530 #if APPLE_OSX_mDNSResponder
7531 // When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
7532 // gets deregistered, so that older peers are forced to connect over direct UDP instead of
7533 // the RR relay.
7534 //
7535 // When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
7536 // service records are deregistered, so they do not appear in peers' Finder sidebars.
7537 // We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
7538 // depend on their associated SRV record and therefore will be deregistered together in a
7539 // single update with the SRV record.
7540 //
7541 // Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
7542 // its presence shouldn't delay sleep.
7543 //
7544 // Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
7545 // relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
7546 //
7547 // Also note that returning false here will not delay sleep past the maximum of 10 seconds.
7548 mDNSexport mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr)
7549 {
7550 if (!AuthRecord_uDNS(rr)) return mDNStrue;
7551
7552 if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
7553 {
7554 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7555 return mDNSfalse;
7556 }
7557
7558 if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result))
7559 {
7560 if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone
7561 && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel"))
7562 {
7563 DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
7564 if (info && info->AutoTunnel)
7565 {
7566 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7567 return mDNSfalse;
7568 }
7569 }
7570 }
7571
7572 return mDNStrue;
7573 }
7574
7575 // Caller must hold the lock
7576 mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
7577 {
7578 DomainAuthInfo *info;
7579 // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
7580 // deregister the record, and the MemFree callback won't re-register.
7581 m->AutoTunnelRelayAddr = zerov6Addr;
7582 for (info = m->AuthInfoList; info; info = info->next)
7583 if (info->AutoTunnel)
7584 UpdateAutoTunnel6Record(m, info);
7585 }
7586
7587 mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname)
7588 {
7589 struct ifaddrs *ifa;
7590 struct ifaddrs *ifaddrs;
7591 mDNSAddr addr;
7592
7593 if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;}
7594
7595 if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;}
7596
7597 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
7598 {
7599 if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
7600 continue;
7601 if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
7602 continue;
7603 if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
7604 {
7605 LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
7606 continue;
7607 }
7608 if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6))
7609 {
7610 LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr);
7611 break;
7612 }
7613 }
7614 freeifaddrs(ifaddrs);
7615 return ifa != NULL;
7616 }
7617
7618 mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf)
7619 {
7620 mDNSv6Addr retVal;
7621 struct addrinfo hints;
7622 struct addrinfo *res0;
7623
7624 memset(&hints, 0, sizeof(hints));
7625 hints.ai_family = AF_INET6;
7626 hints.ai_flags = AI_NUMERICHOST;
7627
7628 int err = getaddrinfo(buf, NULL, &hints, &res0);
7629 if (err)
7630 return zerov6Addr;
7631
7632 retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr;
7633
7634 freeaddrinfo(res0);
7635
7636 return retVal;
7637 }
7638
7639 mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict()
7640 {
7641 SCDynamicStoreRef store = NULL;
7642 CFDictionaryRef connd = NULL;
7643 CFDictionaryRef BTMMDict = NULL;
7644
7645 store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:CopyConnectivityBackToMyMacDict"), NULL, NULL);
7646 if (!store)
7647 {
7648 LogMsg("CopyConnectivityBackToMyMacDict: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
7649 goto end;
7650 }
7651
7652 connd = SCDynamicStoreCopyValue(store, NetworkChangedKey_BTMMConnectivity);
7653 if (!connd)
7654 {
7655 LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
7656 goto end;
7657 }
7658
7659 BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
7660 if (!BTMMDict)
7661 {
7662 LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
7663 goto end;
7664 }
7665
7666 // Non-dictionary is treated as non-existent dictionary
7667 if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
7668 {
7669 BTMMDict = NULL;
7670 LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
7671 goto end;
7672 }
7673
7674 CFRetain(BTMMDict);
7675
7676 end:
7677 if (connd) CFRelease(connd);
7678 if (store) CFRelease(store);
7679
7680 return BTMMDict;
7681 }
7682
7683 #define MAX_IPV6_TEXTUAL 40
7684
7685 mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey)
7686 {
7687 mDNSv6Addr retVal = zerov6Addr;
7688 CFTypeRef string = NULL;
7689 char ifname[IFNAMSIZ];
7690 char address[MAX_IPV6_TEXTUAL];
7691
7692 if (!BTMMDict)
7693 return zerov6Addr;
7694
7695 if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string))
7696 {
7697 LogInfo("ParseBackToMyMacAddr: interface key does not exist");
7698 return zerov6Addr;
7699 }
7700
7701 if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8))
7702 {
7703 LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
7704 return zerov6Addr;
7705 }
7706
7707 if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string))
7708 {
7709 LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
7710 return zerov6Addr;
7711 }
7712
7713 if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8))
7714 {
7715 LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
7716 return zerov6Addr;
7717 }
7718
7719 retVal = IPv6AddressFromString(address);
7720 LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal);
7721
7722 if (mDNSIPv6AddressIsZero(retVal))
7723 return zerov6Addr;
7724
7725 if (!IPv6AddressIsOnInterface(retVal, ifname))
7726 {
7727 LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname);
7728 return zerov6Addr;
7729 }
7730
7731 return retVal;
7732 }
7733
7734 mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict)
7735 {
7736 CFTypeRef zones = NULL;
7737
7738 if (!BTMMDict)
7739 return NULL;
7740
7741 if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones))
7742 {
7743 LogInfo("CopyBTMMZones: Zones key does not exist");
7744 return NULL;
7745 }
7746
7747 return zones;
7748 }
7749
7750 mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info)
7751 {
7752 mDNSv6Addr addr = zerov6Addr;
7753 char buffer[MAX_ESCAPED_DOMAIN_NAME];
7754 CFStringRef domain = NULL;
7755 CFTypeRef theZone = NULL;
7756
7757 if (!zones)
7758 return addr;
7759
7760 ConvertDomainNameToCString(&info->domain, buffer);
7761 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
7762 if (!domain)
7763 return addr;
7764
7765 if (CFDictionaryGetValueIfPresent(zones, domain, &theZone))
7766 addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address"));
7767
7768 CFRelease(domain);
7769
7770 return addr;
7771 }
7772
7773 mDNSlocal void SetupBackToMyMacInnerAddresses(mDNS *const m, CFDictionaryRef BTMMDict)
7774 {
7775 DomainAuthInfo* info;
7776 CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
7777 mDNSv6Addr newAddr;
7778
7779 for (info = m->AuthInfoList; info; info = info->next)
7780 {
7781 if (!info->AutoTunnel)
7782 continue;
7783
7784 newAddr = ParseBackToMyMacZone(zones, info);
7785
7786 if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress))
7787 continue;
7788
7789 info->AutoTunnelInnerAddress = newAddr;
7790 DeregisterAutoTunnelHostRecord(m, info);
7791 UpdateAutoTunnelHostRecord(m, info);
7792 UpdateAutoTunnelDomainStatus(m, info);
7793 }
7794 }
7795
7796 // MUST be called holding the lock
7797 mDNSlocal void ProcessConndConfigChanges(mDNS *const m)
7798 {
7799 CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
7800 if (!dict)
7801 LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
7802 mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
7803
7804 LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
7805
7806 SetupBackToMyMacInnerAddresses(m, dict);
7807
7808 if (dict) CFRelease(dict);
7809
7810 if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr))
7811 {
7812 m->AutoTunnelRelayAddr = relayAddr;
7813
7814 DomainAuthInfo* info;
7815 for (info = m->AuthInfoList; info; info = info->next)
7816 if (info->AutoTunnel)
7817 {
7818 DeregisterAutoTunnel6Record(m, info);
7819 UpdateAutoTunnel6Record(m, info);
7820 UpdateAutoTunnelDomainStatus(m, info);
7821 }
7822
7823 // Determine whether we need racoon to accept incoming connections
7824 UpdateAnonymousRacoonConfig(m);
7825 }
7826
7827 // If awacsd crashes or exits for some reason, restart it
7828 UpdateBTMMRelayConnection(m);
7829 }
7830 #endif /* APPLE_OSX_mDNSResponder */
7831
7832 mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
7833 {
7834 DNSServer *s;
7835 // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
7836 for (s = m->DNSServers; s; s = s->next)
7837 {
7838 if (s->addr.ip.v4.b[0] == 17)
7839 {
7840 LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s->domain.c, &s->addr);
7841 return mDNStrue;
7842 }
7843 }
7844 return mDNSfalse;
7845 }
7846
7847 mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
7848 {
7849 LogInfo("*** Network Configuration Change *** (%d)%s",
7850 m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0,
7851 m->p->NetworkChanged ? "" : " (no scheduled configuration change)");
7852 m->p->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
7853 mDNSs32 utc = mDNSPlatformUTC();
7854 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
7855 m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
7856 MarkAllInterfacesInactive(m, utc);
7857 UpdateInterfaceList(m, utc);
7858 ClearInactiveInterfaces(m, utc);
7859 SetupActiveInterfaces(m, utc);
7860
7861 #if APPLE_OSX_mDNSResponder
7862
7863 mDNS_Lock(m);
7864 ProcessConndConfigChanges(m);
7865 mDNS_Unlock(m);
7866
7867 // Scan to find client tunnels whose questions have completed,
7868 // but whose local inner/outer addresses have changed since the tunnel was set up
7869 ClientTunnel *p;
7870 for (p = m->TunnelClients; p; p = p->next)
7871 if (p->q.ThisQInterval < 0)
7872 {
7873 DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname);
7874 if (!info)
7875 {
7876 LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c);
7877 AutoTunnelSetKeys(p, mDNSfalse);
7878 }
7879 else
7880 {
7881 mDNSv6Addr inner = info->AutoTunnelInnerAddress;
7882
7883 if (!mDNSIPPortIsZero(p->rmt_outer_port))
7884 {
7885 mDNSAddr tmpSrc = zeroAddr;
7886 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
7887 tmpDst.ip.v4 = p->rmt_outer;
7888 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
7889 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7890 !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
7891 {
7892 AutoTunnelSetKeys(p, mDNSfalse);
7893 p->loc_inner = inner;
7894 p->loc_outer = tmpSrc.ip.v4;
7895 AutoTunnelSetKeys(p, mDNStrue);
7896 }
7897 }
7898 else
7899 {
7900 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7901 !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
7902 {
7903 AutoTunnelSetKeys(p, mDNSfalse);
7904 p->loc_inner = inner;
7905 p->loc_outer6 = m->AutoTunnelRelayAddr;
7906 AutoTunnelSetKeys(p, mDNStrue);
7907 }
7908 }
7909 }
7910 }
7911
7912 SetSPS(m);
7913
7914 NetworkInterfaceInfoOSX *i;
7915 for (i = m->p->InterfaceList; i; i = i->next)
7916 {
7917 if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
7918 {
7919 if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) CloseBPF(i);
7920 }
7921 else // else, we're Sleep Proxy Server; open BPF fds
7922 {
7923 if (i->Exists && i->Registered == i && i->ifinfo.McastTxRx && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1)
7924 { LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); }
7925 }
7926 }
7927
7928 #endif // APPLE_OSX_mDNSResponder
7929
7930 uDNS_SetupDNSConfig(m);
7931 mDNS_ConfigChanged(m);
7932
7933 if (IsAppleNetwork(m) != mDNS_McastTracingEnabled)
7934 {
7935 mDNS_McastTracingEnabled = mDNS_McastTracingEnabled ? mDNSfalse : mDNStrue;
7936 LogMsg("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
7937 UpdateDebugState();
7938 }
7939
7940 }
7941
7942 // Called with KQueueLock & mDNS lock
7943 // SetNetworkChanged is allowed to extend (but not reduce) the pause while we wait for configuration changes to settle
7944 mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay)
7945 {
7946 if (!m->p->NetworkChanged || m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
7947 {
7948 m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
7949 LogInfo("SetNetworkChanged: Scheduling in %d msec", delay);
7950 }
7951 else
7952 LogInfo("SetNetworkChanged: *NOT* reducing delay from %d to %d", m->p->NetworkChanged - m->timenow, delay);
7953 }
7954
7955 // Called with KQueueLock & mDNS lock
7956 mDNSlocal void SetKeyChainTimer(mDNS *const m, mDNSs32 delay)
7957 {
7958 // If it's not set or it needs to happen sooner than when it's currently set
7959 if (!m->p->KeyChainTimer || m->p->KeyChainTimer - NonZeroTime(m->timenow + delay) > 0)
7960 {
7961 m->p->KeyChainTimer = NonZeroTime(m->timenow + delay);
7962 LogInfo("SetKeyChainTimer: %d", delay);
7963 }
7964 }
7965
7966 // Copy the fourth slash-delimited element from either:
7967 // State:/Network/Interface/<bsdname>/IPv4
7968 // or
7969 // Setup:/Network/Service/<servicename>/Interface
7970 mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
7971 {
7972 CFArrayRef a;
7973 CFStringRef name = NULL;
7974
7975 a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
7976 if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
7977 if (a != NULL) CFRelease(a);
7978
7979 return name;
7980 }
7981
7982 // Whether a key from a network change notification corresponds to
7983 // an IP service that is explicitly configured for IPv4 Link Local
7984 mDNSlocal int ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
7985 {
7986 SCDynamicStoreRef store = NULL;
7987 CFDictionaryRef dict = NULL;
7988 CFMutableArrayRef a;
7989 const void **keys = NULL, **vals = NULL;
7990 CFStringRef pattern = NULL;
7991 int i, ic, j, jc;
7992 int found = 0;
7993
7994 jc = CFArrayGetCount(inkeys);
7995 if (!jc) goto done;
7996
7997 store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:ChangedKeysHaveIPv4LL"), NULL, NULL);
7998 if (store == NULL) goto done;
7999
8000 a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8001 if (a == NULL) goto done;
8002
8003 // Setup:/Network/Service/[^/]+/Interface
8004 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
8005 if (pattern == NULL) goto done;
8006 CFArrayAppendValue(a, pattern);
8007 CFRelease(pattern);
8008
8009 // Setup:/Network/Service/[^/]+/IPv4
8010 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
8011 if (pattern == NULL) goto done;
8012 CFArrayAppendValue(a, pattern);
8013 CFRelease(pattern);
8014
8015 dict = SCDynamicStoreCopyMultiple(store, NULL, a);
8016 CFRelease(a);
8017
8018 if (!dict)
8019 {
8020 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
8021 goto done;
8022 }
8023
8024 ic = CFDictionaryGetCount(dict);
8025 vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
8026 keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
8027 CFDictionaryGetKeysAndValues(dict, keys, vals);
8028
8029 // For each key we were given...
8030 for (j = 0; j < jc; j++)
8031 {
8032 CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
8033 CFStringRef ifname = NULL;
8034
8035 char buf[256];
8036
8037 // It would be nice to use a regex here
8038 if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
8039
8040 if ((ifname = CopyNameFromKey(key)) == NULL) continue;
8041 if (mDNS_LoggingEnabled)
8042 {
8043 if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8044 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
8045 }
8046
8047 // Loop over the interfaces to find matching the ifname, and see if that one has kSCValNetIPv4ConfigMethodLinkLocal
8048 for (i = 0; i < ic; i++)
8049 {
8050 CFDictionaryRef ipv4dict;
8051 CFStringRef name;
8052 CFStringRef serviceid;
8053 CFStringRef configmethod;
8054
8055 if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
8056
8057 if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
8058
8059 if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
8060
8061 if (!CFEqual(ifname, name)) continue;
8062
8063 if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
8064 if (mDNS_LoggingEnabled)
8065 {
8066 if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8067 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
8068 }
8069
8070 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
8071 CFRelease(serviceid);
8072 if (pattern == NULL) continue;
8073
8074 ipv4dict = CFDictionaryGetValue(dict, pattern);
8075 CFRelease(pattern);
8076 if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
8077
8078 configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
8079 if (!configmethod) continue;
8080
8081 if (mDNS_LoggingEnabled)
8082 {
8083 if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8084 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
8085 }
8086
8087 if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found++; break; }
8088 }
8089
8090 CFRelease(ifname);
8091 }
8092
8093 done:
8094 if (vals != NULL) mDNSPlatformMemFree(vals);
8095 if (keys != NULL) mDNSPlatformMemFree(keys);
8096 if (dict != NULL) CFRelease(dict);
8097 if (store != NULL) CFRelease(store);
8098
8099 return found;
8100 }
8101
8102 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
8103 {
8104 (void)store; // Parameter not used
8105 mDNS *const m = (mDNS *const)context;
8106 KQueueLock(m);
8107 mDNS_Lock(m);
8108
8109 mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
8110
8111 int c = CFArrayGetCount(changedKeys); // Count changes
8112 CFRange range = { 0, c };
8113 int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
8114 int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
8115 int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0);
8116 int c4 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
8117 int c5 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac ) != 0);
8118 int c6 = ChangedKeysHaveIPv4LL(changedKeys);
8119 int c7 = 0;
8120
8121 // Do immediate network changed processing for "p2p*" interfaces and
8122 // for interfaces with the IFEF_DIRECTLINK flag set.
8123 {
8124 CFArrayRef labels;
8125 CFIndex n;
8126 for (int i = 0; i < c; i++)
8127 {
8128 CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i);
8129
8130 // Only look at keys with prefix "State:/Network/Interface/"
8131 if (!CFStringHasPrefix(key, NetworkChangedKey_StateInterfacePrefix))
8132 continue;
8133
8134 // And suffix "IPv6" or "IPv4".
8135 if (!CFStringHasSuffix(key, kSCEntNetIPv6) && !CFStringHasSuffix(key, kSCEntNetIPv4))
8136 continue;
8137
8138 labels = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
8139 if (labels == NULL)
8140 break;
8141 n = CFArrayGetCount(labels);
8142
8143 // Interface changes will have keys of the form:
8144 // State:/Network/Interface/<interfaceName>/IPv6
8145 // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
8146 if (n == 5)
8147 {
8148 char buf[256];
8149
8150 // The 4th label (index = 3) should be the interface name.
8151 if (CFStringGetCString(CFArrayGetValueAtIndex(labels, 3), buf, sizeof(buf), kCFStringEncodingUTF8)
8152 && (strstr(buf, "p2p") || (getExtendedFlags(buf) & IFEF_DIRECTLINK)))
8153 {
8154 LogInfo("NetworkChanged: interface %s qualifies for reduced change handling delay", buf);
8155 c7++;
8156 CFRelease(labels);
8157 break;
8158 }
8159 }
8160 CFRelease(labels);
8161 }
8162 }
8163
8164 if (c && c - c1 - c2 - c3 - c4 - c5 - c6 - c7 == 0)
8165 delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
8166
8167 // Immediately force a reconfig (esp. cache flush) if any of the following is true:
8168 // 1. DNS Settings changed.
8169 // 2 An interface changed that is explicitly IPv4 link local
8170 // 3. There are P2P/IFEF_DIRECTLINK/IsCarPlaySSID changes
8171 if (c3 || ChangedKeysHaveIPv4LL(changedKeys) || c7)
8172 {
8173 LogInfo("NetworkChanged: %s : Handling this change immediately",
8174 c3 ? "DNS Settings Changed" :
8175 c7 ? "P2P/IFEF_DIRECTLINK/IsCarPlaySSID Changed" :
8176 "An interface changed that is explicitly IPv4 link local");
8177 m->p->NetworkChanged = NonZeroTime(m->timenow);
8178 delay = 0; // for the logs below.
8179 }
8180
8181 if (mDNS_LoggingEnabled)
8182 {
8183 int i;
8184 for (i=0; i<c; i++)
8185 {
8186 char buf[256];
8187 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8188 LogInfo("*** NetworkChanged SC key: %s", buf);
8189 }
8190 LogInfo("*** NetworkChanged *** %d change%s %s%s%s%s%s%s%sdelay %d%s",
8191 c, c>1 ? "s" : "",
8192 c1 ? "(Local Hostname) " : "",
8193 c2 ? "(Computer Name) " : "",
8194 c3 ? "(DNS) " : "",
8195 c4 ? "(DynamicDNS) " : "",
8196 c5 ? "(BTMM) " : "",
8197 c6 ? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
8198 c7 ? "(P2P/IFEF_DIRECTLINK/IsCarPlaySSID) " : "",
8199 delay,
8200 (c4 || c5) ? " + SetKeyChainTimer" : "");
8201 }
8202
8203 SetNetworkChanged(m, delay);
8204
8205 // Other software might pick up these changes to register or browse in WAB or BTMM domains,
8206 // so in order for secure updates to be made to the server, make sure to read the keychain and
8207 // setup the DomainAuthInfo before handing the network change.
8208 // If we don't, then we will first try to register services in the clear, then later setup the
8209 // DomainAuthInfo, which is incorrect.
8210 if (c4 || c5)
8211 SetKeyChainTimer(m, delay);
8212
8213 mDNS_Unlock(m);
8214
8215 KQueueUnlock(m, "NetworkChanged");
8216 }
8217
8218 #if APPLE_OSX_mDNSResponder
8219 mDNSlocal void RefreshSPSStatus(const void *key, const void *value, void *context)
8220 {
8221 (void)context;
8222 char buf[IFNAMSIZ];
8223
8224 CFStringRef ifnameStr = (CFStringRef)key;
8225 CFArrayRef array = (CFArrayRef)value;
8226 if (!CFStringGetCString(ifnameStr, buf, sizeof(buf), kCFStringEncodingUTF8))
8227 buf[0] = 0;
8228
8229 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf, CFArrayGetCount(array));
8230 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, buf, value);
8231 }
8232 #endif
8233
8234 mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
8235 {
8236 mDNS *const m = (mDNS *const)info;
8237 (void)store;
8238
8239 LogInfo("DynamicStoreReconnected: Reconnected");
8240
8241 // State:/Network/MulticastDNS
8242 SetLocalDomains();
8243
8244 // State:/Network/DynamicDNS
8245 if (m->FQDN.c[0])
8246 mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
8247
8248 // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
8249 // as we receive network change notifications and thus not necessary. But we leave it here
8250 // so that if things are done differently in the future, this code still works.
8251
8252 // State:/Network/PrivateDNS
8253 if (privateDnsArray)
8254 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
8255
8256 #if APPLE_OSX_mDNSResponder
8257 mDNS_Lock(m);
8258 // State:/Network/BackToMyMac
8259 UpdateAutoTunnelDomainStatuses(m);
8260 mDNS_Unlock(m);
8261
8262 // State:/Network/Interface/en0/SleepProxyServers
8263 if (spsStatusDict)
8264 CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
8265 #endif
8266 }
8267
8268 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
8269 {
8270 mStatus err = -1;
8271 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
8272 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
8273 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8274 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
8275 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
8276 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8277
8278 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
8279 if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
8280
8281 CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
8282 CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
8283 CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
8284 CFArrayAppendValue(keys, NetworkChangedKey_Computername);
8285 CFArrayAppendValue(keys, NetworkChangedKey_DNS);
8286 CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
8287 CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
8288 CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings); // should remove as part of <rdar://problem/6751656>
8289 CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
8290 CFArrayAppendValue(patterns, pattern1);
8291 CFArrayAppendValue(patterns, pattern2);
8292 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
8293 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
8294 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
8295
8296 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8297 if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()))
8298 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8299 #else
8300 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
8301 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8302 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
8303 #endif
8304 SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected);
8305 m->p->Store = store;
8306 err = 0;
8307 goto exit;
8308
8309 error:
8310 if (store) CFRelease(store);
8311
8312 exit:
8313 if (patterns) CFRelease(patterns);
8314 if (pattern2) CFRelease(pattern2);
8315 if (pattern1) CFRelease(pattern1);
8316 if (keys) CFRelease(keys);
8317
8318 return(err);
8319 }
8320
8321 #if 0 // <rdar://problem/6751656>
8322 mDNSlocal void PMChanged(void *context)
8323 {
8324 mDNS *const m = (mDNS *const)context;
8325
8326 KQueueLock(m);
8327 mDNS_Lock(m);
8328
8329 LogSPS("PMChanged");
8330
8331 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
8332
8333 mDNS_Unlock(m);
8334 KQueueUnlock(m, "PMChanged");
8335 }
8336
8337 mDNSlocal mStatus WatchForPMChanges(mDNS *const m)
8338 {
8339 m->p->PMRLS = IOPMPrefsNotificationCreateRunLoopSource(PMChanged, m);
8340 if (!m->p->PMRLS) { LogMsg("IOPMPrefsNotificationCreateRunLoopSource failed!"); return mStatus_UnknownErr; }
8341
8342 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
8343
8344 return mStatus_NoError;
8345 }
8346 #endif
8347
8348 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8349
8350 mDNSlocal void mDNSSetPacketFilterRules(mDNS *const m, char * ifname, const ResourceRecord *const excludeRecord)
8351 {
8352 AuthRecord *rr;
8353 pfArray_t portArray;
8354 pfArray_t protocolArray;
8355 uint32_t count = 0;
8356
8357 for (rr = m->ResourceRecords; rr; rr=rr->next)
8358 {
8359 if ((rr->resrec.rrtype == kDNSServiceType_SRV)
8360 && ((rr->ARType == AuthRecordAnyIncludeP2P) || (rr->ARType == AuthRecordAnyIncludeAWDLandP2P)))
8361 {
8362 const mDNSu8 *p;
8363
8364 if (count >= PFPortArraySize)
8365 {
8366 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize, ARDisplayString(m, rr));
8367 continue;
8368 }
8369
8370 if (excludeRecord && IdenticalResourceRecord(&rr->resrec, excludeRecord))
8371 {
8372 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m, rr));
8373 continue;
8374 }
8375
8376 LogInfo("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr));
8377
8378 portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger;
8379
8380 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
8381 p = rr->resrec.name->c;
8382
8383 // Skip to App Protocol
8384 if (p[0]) p += 1 + p[0];
8385
8386 // Skip to Transport Protocol
8387 if (p[0]) p += 1 + p[0];
8388
8389 if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) protocolArray[count] = IPPROTO_TCP;
8390 else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) protocolArray[count] = IPPROTO_UDP;
8391 else
8392 {
8393 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
8394 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m, rr));
8395 return;
8396 }
8397 count++;
8398 }
8399 }
8400 mDNSPacketFilterControl(PF_SET_RULES, ifname, count, portArray, protocolArray);
8401 }
8402
8403 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
8404 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8405 {
8406 mDNS *const m = &mDNSStorage;
8407
8408 NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
8409 while (intf)
8410 {
8411 if (strncmp(intf->ifname, "p2p", 3) == 0)
8412 {
8413 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname);
8414 mDNSSetPacketFilterRules(m, intf->ifname, excludeRecord);
8415 break;
8416 }
8417 intf = GetFirstActiveInterface(intf->next);
8418 }
8419 }
8420
8421 #else // !TARGET_OS_EMBEDDED
8422
8423 // Currently no packet filter setup required on embedded platforms.
8424 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8425 {
8426 (void) excludeRecord; // unused
8427 }
8428
8429 #endif // !TARGET_OS_EMBEDDED
8430
8431 // Handle AWDL KEV_DL_MASTER_ELECTED event by restarting queries and advertisements
8432 // marked to include the AWDL interface.
8433 mDNSlocal void newMasterElected(mDNS *const m, struct net_event_data * ptr)
8434 {
8435 char ifname[IFNAMSIZ];
8436 mDNSu32 interfaceIndex;
8437 DNSQuestion *q;
8438 AuthRecord *rr;
8439 NetworkInterfaceInfoOSX *infoOSX;
8440 mDNSInterfaceID InterfaceID;
8441
8442 snprintf(ifname, IFNAMSIZ, "%s%d", ptr->if_name, ptr->if_unit);
8443 interfaceIndex = if_nametoindex(ifname);
8444
8445 if (!interfaceIndex)
8446 {
8447 LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname);
8448 return;
8449 }
8450
8451 LogInfo("newMasterElected: ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
8452 infoOSX = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)interfaceIndex);
8453
8454 // Can get an KEV_DL_MASTER_ELECTED event prior to the interface existing
8455 // when it is first brought up.
8456 if (!infoOSX)
8457 {
8458 LogInfo("newMasterElected: interface not yet active");
8459 return;
8460 }
8461 InterfaceID = infoOSX->ifinfo.InterfaceID;
8462
8463 for (q = m->Questions; q; q=q->next)
8464 {
8465 if ((!q->InterfaceID && (q->flags & kDNSServiceFlagsIncludeAWDL))
8466 || q->InterfaceID == InterfaceID)
8467 {
8468 LogInfo("newMasterElected: restarting %s query for %##s", DNSTypeName(q->qtype), q->qname.c);
8469 mDNSCoreRestartQuestion(m, q);
8470 }
8471 }
8472
8473 for (rr = m->ResourceRecords; rr; rr=rr->next)
8474 {
8475 if ((!rr->resrec.InterfaceID
8476 && ((rr->ARType == AuthRecordAnyIncludeAWDL) || ((rr->ARType == AuthRecordAnyIncludeAWDLandP2P))))
8477 || rr->resrec.InterfaceID == InterfaceID)
8478 {
8479 LogInfo("newMasterElected: restarting %s announcements for %##s", DNSTypeName(rr->resrec.rrtype), rr->namestorage.c);
8480 mDNSCoreRestartRegistration(m, rr, -1);
8481 }
8482 }
8483 }
8484
8485 // An ssth array of all zeroes indicates the peer has no services registered.
8486 mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op)
8487 {
8488 int i;
8489 int *intp = (int *) op->ssth;
8490
8491 // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
8492 // it's not, print an error message and return false so that
8493 // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
8494 // is received.
8495 if (MAX_SSTH_SIZE % sizeof(int))
8496 {
8497 LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE);
8498 return mDNSfalse;
8499 }
8500
8501 for (i = 0; i < (int)(MAX_SSTH_SIZE / sizeof(int)); i++, intp++)
8502 {
8503 if (*intp)
8504 return mDNSfalse;
8505 }
8506 return mDNStrue;
8507 }
8508
8509 // mDNS_Reconfirm_internal() adds 33% to this interval, so the records should
8510 // be removed in 4 seconds.
8511 #define kAWDLReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 3)
8512
8513 // Mark records from this peer for deletion from the cache.
8514 mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr *ap)
8515 {
8516 mDNSu32 slot;
8517 CacheGroup *cg;
8518 CacheRecord *cr;
8519 mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(m, ifindex);
8520
8521 if (!InterfaceID)
8522 {
8523 LogInfo("removeCachedPeerRecords: Invalid ifindex: %d", ifindex);
8524 return;
8525 }
8526
8527 FORALL_CACHERECORDS(slot, cg, cr)
8528 {
8529 if ((InterfaceID == cr->resrec.InterfaceID) && mDNSSameAddress(ap, & cr->sourceAddress))
8530 {
8531 LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
8532 DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c);
8533 mDNS_Reconfirm_internal(m, cr, kAWDLReconfirmTime);
8534 }
8535 }
8536 }
8537
8538 // Handle KEV_DL_NODE_PRESENCE event.
8539 mDNSlocal void nodePresence(mDNS *const m, struct kev_dl_node_presence * p)
8540 {
8541 char buf[INET6_ADDRSTRLEN];
8542 struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info;
8543
8544 if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
8545 LogInfo("nodePresence: IPv6 address: %s, SUI %d", buf, op->SUI);
8546 else
8547 LogInfo("nodePresence: inet_ntop() error");
8548
8549 // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
8550 // all zeroes when a node is present and has no services registered.
8551 if (allZeroSSTH(op))
8552 {
8553 mDNSAddr peerAddr;
8554
8555 peerAddr.type = mDNSAddrType_IPv6;
8556 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8557
8558 LogInfo("nodePresence: ssth is all zeroes, delete cached records from this peer");
8559 removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr);
8560 }
8561 }
8562
8563 // Handle KEV_DL_NODE_ABSENCE event.
8564 mDNSlocal void nodeAbsence(mDNS *const m, struct kev_dl_node_absence * p)
8565 {
8566 mDNSAddr peerAddr;
8567 char buf[INET6_ADDRSTRLEN];
8568
8569 if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
8570 LogInfo("nodeAbsence: IPv6 address: %s", buf);
8571 else
8572 LogInfo("nodeAbsence: inet_ntop() error");
8573
8574 peerAddr.type = mDNSAddrType_IPv6;
8575 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8576
8577 LogInfo("nodeAbsence: delete cached records from this peer");
8578 removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr);
8579 }
8580
8581 mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context)
8582 {
8583 mDNS *const m = (mDNS *const)context;
8584
8585 mDNS_Lock(m);
8586
8587 struct { struct kern_event_msg k; char extra[256]; } msg;
8588 int bytes = recv(s1, &msg, sizeof(msg), 0);
8589 if (bytes < 0)
8590 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
8591 else
8592 {
8593 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
8594 bytes, msg.k.total_size,
8595 msg.k.vendor_code, msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?",
8596 msg.k.kev_class, msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
8597 msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?",
8598 msg.k.id, msg.k.event_code,
8599 msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" :
8600 msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" :
8601 msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" :
8602 msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" :
8603 msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" :
8604 msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" :
8605 msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" :
8606 msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" :
8607 msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" :
8608 msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" :
8609 msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" :
8610 msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" :
8611 msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" :
8612 msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" :
8613 msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" :
8614 msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
8615 msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" :
8616 msg.k.event_code == KEV_DL_IF_IDLE_ROUTE_REFCNT ? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
8617 msg.k.event_code == KEV_DL_IFCAP_CHANGED ? "KEV_DL_IFCAP_CHANGED" :
8618 msg.k.event_code == KEV_DL_LINK_QUALITY_METRIC_CHANGED ? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" :
8619 msg.k.event_code == KEV_DL_NODE_PRESENCE ? "KEV_DL_NODE_PRESENCE" :
8620 msg.k.event_code == KEV_DL_NODE_ABSENCE ? "KEV_DL_NODE_ABSENCE" :
8621 msg.k.event_code == KEV_DL_MASTER_ELECTED ? "KEV_DL_MASTER_ELECTED" :
8622 "?");
8623
8624 if (msg.k.event_code == KEV_DL_NODE_PRESENCE)
8625 nodePresence(m, (struct kev_dl_node_presence *) &msg.k.event_data);
8626
8627 if (msg.k.event_code == KEV_DL_NODE_ABSENCE)
8628 nodeAbsence(m, (struct kev_dl_node_absence *) &msg.k.event_data);
8629
8630 if (msg.k.event_code == KEV_DL_MASTER_ELECTED)
8631 newMasterElected(m, (struct net_event_data *) &msg.k.event_data);
8632
8633 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
8634 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
8635 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
8636 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
8637 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
8638
8639 if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
8640 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
8641
8642 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8643
8644 // For p2p interfaces, need to open the advertised service port in the firewall.
8645 if (msg.k.event_code == KEV_DL_IF_ATTACHED)
8646 {
8647 struct net_event_data * p;
8648 p = (struct net_event_data *) &msg.k.event_data;
8649
8650 if (strncmp(p->if_name, "p2p", 3) == 0)
8651 {
8652 char ifname[IFNAMSIZ];
8653 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8654
8655 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8656
8657 mDNSSetPacketFilterRules(m, ifname, NULL);
8658 }
8659 }
8660
8661 // For p2p interfaces, need to clear the firewall rules on interface detach
8662 if (msg.k.event_code == KEV_DL_IF_DETACHED)
8663 {
8664 struct net_event_data * p;
8665 p = (struct net_event_data *) &msg.k.event_data;
8666
8667 if (strncmp(p->if_name, "p2p", 3) == 0)
8668 {
8669 pfArray_t portArray, protocolArray; // not initialized since count is 0 for PF_CLEAR_RULES
8670 char ifname[IFNAMSIZ];
8671 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8672
8673 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8674
8675 mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
8676 }
8677 }
8678 #endif // !TARGET_OS_EMBEDDED
8679
8680 }
8681
8682 mDNS_Unlock(m);
8683 }
8684
8685 mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
8686 {
8687 m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
8688 if (m->p->SysEventNotifier < 0)
8689 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); }
8690
8691 struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
8692 int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
8693 if (err < 0)
8694 {
8695 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno));
8696 close(m->p->SysEventNotifier);
8697 m->p->SysEventNotifier = -1;
8698 return(mStatus_UnknownErr);
8699 }
8700
8701 m->p->SysEventKQueue.KQcallback = SysEventCallBack;
8702 m->p->SysEventKQueue.KQcontext = m;
8703 m->p->SysEventKQueue.KQtask = "System Event Notifier";
8704 KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
8705
8706 return(mStatus_NoError);
8707 }
8708
8709 #ifndef NO_SECURITYFRAMEWORK
8710 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
8711 {
8712 LogInfo("*** Keychain Changed ***");
8713 mDNS *const m = (mDNS *const)context;
8714 SecKeychainRef skc;
8715 OSStatus err = SecKeychainCopyDefault(&skc);
8716 if (!err)
8717 {
8718 if (info->keychain == skc)
8719 {
8720 // 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
8721 mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
8722 if (!relevant)
8723 {
8724 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
8725 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
8726 SecKeychainAttributeList *a = NULL;
8727 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
8728 if (!err)
8729 {
8730 relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
8731 (a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))) ||
8732 (a->attr[1].length >= mDNSPlatformStrLen(btmmprefix) && (!strncasecmp(a->attr[1].data, btmmprefix, mDNSPlatformStrLen(btmmprefix)))));
8733 SecKeychainItemFreeAttributesAndData(a, NULL);
8734 }
8735 }
8736 if (relevant)
8737 {
8738 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
8739 keychainEvent,
8740 keychainEvent == kSecAddEvent ? "kSecAddEvent" :
8741 keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
8742 keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
8743 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
8744 KQueueLock(m);
8745 mDNS_Lock(m);
8746
8747 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
8748 // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
8749 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
8750 //
8751 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
8752 // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
8753 // a one second delay is ok, as we'll still converge to correctness, and there's no race
8754 // condition between the RegistrationDomain and the DomainAuthInfo.
8755 //
8756 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
8757 // the timer here, as it will not get set by NetworkChanged().
8758 SetKeyChainTimer(m, mDNSPlatformOneSecond);
8759
8760 mDNS_Unlock(m);
8761 KQueueUnlock(m, "KeychainChanged");
8762 }
8763 }
8764 CFRelease(skc);
8765 }
8766
8767 return 0;
8768 }
8769 #endif
8770
8771 mDNSlocal void PowerOn(mDNS *const m)
8772 {
8773 mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
8774 if (m->p->WakeAtUTC)
8775 {
8776 long utc = mDNSPlatformUTC();
8777 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
8778 if (m->p->WakeAtUTC - utc > 30)
8779 {
8780 LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
8781 }
8782 else if (utc - m->p->WakeAtUTC > 30)
8783 {
8784 LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
8785 }
8786 else if (IsAppleTV())
8787 {
8788 LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC);
8789 }
8790 else
8791 {
8792 LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m->p->WakeAtUTC - utc);
8793 m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond;
8794 }
8795 }
8796 }
8797
8798 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
8799 {
8800 mDNS *const m = (mDNS *const)refcon;
8801 KQueueLock(m);
8802 (void)service; // Parameter not used
8803 debugf("PowerChanged %X %lX", messageType, messageArgument);
8804
8805 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8806 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8807
8808 switch(messageType)
8809 {
8810 case kIOMessageCanSystemPowerOff: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
8811 case kIOMessageSystemWillPowerOff: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
8812 mDNSCoreMachineSleep(m, true);
8813 if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
8814 break;
8815 case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
8816 case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
8817 case kIOMessageSystemWillSleep: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
8818 mDNSCoreMachineSleep(m, true);
8819 break;
8820 case kIOMessageSystemWillNotSleep: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
8821 case kIOMessageSystemHasPoweredOn: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
8822 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
8823 if (m->SleepState)
8824 {
8825 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
8826 PowerOn(m);
8827 }
8828 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
8829 // the System Configuration Framework "network changed" event that we expect
8830 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
8831 mDNS_Lock(m);
8832 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
8833 mDNS_Unlock(m);
8834
8835 break;
8836 case kIOMessageSystemWillRestart: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
8837 case kIOMessageSystemWillPowerOn: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
8838
8839 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
8840 if (m->SleepState != SleepState_Sleeping)
8841 {
8842 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
8843 m->SleepState = SleepState_Sleeping;
8844 mDNSMacOSXNetworkChanged(m);
8845 }
8846 PowerOn(m);
8847 break;
8848 default: LogSPS("PowerChanged unknown message %X", messageType); break;
8849 }
8850
8851 if (messageType == kIOMessageSystemWillSleep) m->p->SleepCookie = (long)messageArgument;
8852 else IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
8853
8854 KQueueUnlock(m, "PowerChanged Sleep/Wake");
8855 }
8856
8857 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
8858 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
8859 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
8860 mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
8861 {
8862 mDNS *const m = (mDNS *const)refcon;
8863 KQueueLock(m);
8864 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
8865 connection, token, eventDescriptor,
8866 eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "",
8867 eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "",
8868 eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "",
8869 eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
8870 eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : "");
8871
8872 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8873 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8874
8875 if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
8876 {
8877 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
8878 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
8879 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
8880 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
8881 if (m->SleepLimit)
8882 {
8883 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8884 IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie);
8885 m->SleepLimit = 0;
8886 }
8887 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8888 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
8889 if (m->SleepState != SleepState_Awake)
8890 {
8891 PowerOn(m);
8892 // If the network notifications have already come before we got the wakeup, we ignored them and
8893 // in case we get no more, we need to trigger one.
8894 mDNS_Lock(m);
8895 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
8896 mDNS_Unlock(m);
8897 }
8898 IOPMConnectionAcknowledgeEvent(connection, token);
8899 }
8900 else
8901 {
8902 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
8903 // we should hear nothing more until we're told that the CPU has started executing again.
8904 if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
8905 //sleep(5);
8906 //mDNSMacOSXNetworkChanged(m);
8907 mDNSCoreMachineSleep(m, true);
8908 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
8909 m->p->SleepCookie = token;
8910 }
8911
8912 KQueueUnlock(m, "SnowLeopardPowerChanged Sleep/Wake");
8913 }
8914 #endif
8915
8916 #if COMPILER_LIKES_PRAGMA_MARK
8917 #pragma mark -
8918 #pragma mark - /etc/hosts support
8919 #endif
8920
8921 // Implementation Notes
8922 //
8923 // As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
8924 // 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
8925 // them into a hash table. The implementation need to be able to do the following things efficiently
8926 //
8927 // 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
8928 // 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
8929 // 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
8930 // need to be able set the RRSet of a resource record to the first one in the list and also update when
8931 // one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
8932 // not a duplicate
8933 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
8934 //
8935 // CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
8936 // "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
8937 // of the core layer which does all of the above very efficiently
8938
8939 #define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
8940
8941 mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
8942 {
8943 (void)m; // unused
8944 (void)rr;
8945 (void)result;
8946 if (result == mStatus_MemFree)
8947 {
8948 LogInfo("FreeEtcHosts: %s", ARDisplayString(m, rr));
8949 freeL("etchosts", rr);
8950 }
8951 }
8952
8953 // Returns true on success and false on failure
8954 mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(mDNS *const m, const domainname *domain, const struct sockaddr *sa, const domainname *cname, char *ifname, AuthHash *auth)
8955 {
8956 AuthRecord *rr;
8957 mDNSu32 slot;
8958 mDNSu32 namehash;
8959 AuthGroup *ag;
8960 mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly;
8961 mDNSu16 rrtype;
8962
8963 if (!domain)
8964 {
8965 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
8966 return mDNSfalse;
8967 }
8968 if (!sa && !cname)
8969 {
8970 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
8971 return mDNSfalse;
8972 }
8973
8974 if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
8975 {
8976 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa->sa_family);
8977 return mDNSfalse;
8978 }
8979
8980
8981 if (ifname)
8982 {
8983 mDNSu32 ifindex = if_nametoindex(ifname);
8984 if (!ifindex)
8985 {
8986 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain->c, ifname);
8987 return mDNSfalse;
8988 }
8989 InterfaceID = (mDNSInterfaceID)(uintptr_t)ifindex;
8990 }
8991
8992 if (sa)
8993 rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA);
8994 else
8995 rrtype = kDNSType_CNAME;
8996
8997 // Check for duplicates. See whether we parsed an entry before like this ?
8998 slot = AuthHashSlot(domain);
8999 namehash = DomainNameHashValue(domain);
9000 ag = AuthGroupForName(auth, slot, namehash, domain);
9001 if (ag)
9002 {
9003 rr = ag->members;
9004 while (rr)
9005 {
9006 if (rr->resrec.rrtype == rrtype)
9007 {
9008 if (rrtype == kDNSType_A)
9009 {
9010 mDNSv4Addr ip;
9011 ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
9012 if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip))
9013 {
9014 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c);
9015 return mDNSfalse;
9016 }
9017 }
9018 else if (rrtype == kDNSType_AAAA)
9019 {
9020 mDNSv6Addr ip6;
9021 ip6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
9022 ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
9023 ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
9024 ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
9025 if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6))
9026 {
9027 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c);
9028 return mDNSfalse;
9029 }
9030 }
9031 else if (rrtype == kDNSType_CNAME)
9032 {
9033 if (SameDomainName(&rr->resrec.rdata->u.name, cname))
9034 {
9035 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname->c, domain->c);
9036 return mDNSfalse;
9037 }
9038 }
9039 }
9040 rr = rr->next;
9041 }
9042 }
9043 rr= mallocL("etchosts", sizeof(*rr));
9044 if (rr == NULL) return mDNSfalse;
9045 mDNSPlatformMemZero(rr, sizeof(*rr));
9046 mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
9047 AssignDomainName(&rr->namestorage, domain);
9048
9049 if (sa)
9050 {
9051 rr->resrec.rdlength = sa->sa_family == AF_INET ? sizeof(mDNSv4Addr) : sizeof(mDNSv6Addr);
9052 if (sa->sa_family == AF_INET)
9053 rr->resrec.rdata->u.ipv4.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
9054 else
9055 {
9056 rr->resrec.rdata->u.ipv6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
9057 rr->resrec.rdata->u.ipv6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
9058 rr->resrec.rdata->u.ipv6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
9059 rr->resrec.rdata->u.ipv6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
9060 }
9061 }
9062 else
9063 {
9064 rr->resrec.rdlength = DomainNameLength(cname);
9065 rr->resrec.rdata->u.name.c[0] = 0;
9066 AssignDomainName(&rr->resrec.rdata->u.name, cname);
9067 }
9068 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
9069 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
9070 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(m, rr));
9071 InsertAuthRecord(m, auth, rr);
9072 return mDNStrue;
9073 }
9074
9075 mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **name)
9076 {
9077 int i;
9078
9079 *name = NULL;
9080 for (i = start; i < length; i++)
9081 {
9082 if (buffer[i] == '#')
9083 return -1;
9084 if (buffer[i] != ' ' && buffer[i] != ',' && buffer[i] != '\t')
9085 {
9086 *name = &buffer[i];
9087
9088 // Found the start of a name, find the end and null terminate
9089 for (i++; i < length; i++)
9090 {
9091 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
9092 {
9093 buffer[i] = 0;
9094 break;
9095 }
9096 }
9097 return i;
9098 }
9099 }
9100 return -1;
9101 }
9102
9103 mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t length, AuthHash *auth)
9104 {
9105 int i;
9106 int ifStart = 0;
9107 char *ifname = NULL;
9108 domainname name1d;
9109 domainname name2d;
9110 char *name1;
9111 char *name2;
9112 int aliasIndex;
9113
9114 //Ignore leading whitespaces and tabs
9115 while (*buffer == ' ' || *buffer == '\t')
9116 {
9117 buffer++;
9118 length--;
9119 }
9120
9121 // Find the end of the address string
9122 for (i = 0; i < length; i++)
9123 {
9124 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t' || buffer[i] == '%')
9125 {
9126 if (buffer[i] == '%')
9127 ifStart = i + 1;
9128 buffer[i] = 0;
9129 break;
9130 }
9131 }
9132
9133 // Convert the address string to an address
9134 struct addrinfo hints;
9135 bzero(&hints, sizeof(hints));
9136 hints.ai_flags = AI_NUMERICHOST;
9137 struct addrinfo *gairesults = NULL;
9138 if (getaddrinfo(buffer, NULL, &hints, &gairesults) != 0)
9139 {
9140 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
9141 return;
9142 }
9143
9144 if (ifStart)
9145 {
9146 // Parse the interface
9147 ifname = &buffer[ifStart];
9148 for (i = ifStart + 1; i < length; i++)
9149 {
9150 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
9151 {
9152 buffer[i] = 0;
9153 break;
9154 }
9155 }
9156 }
9157
9158 i = EtcHostsParseOneName(i + 1, length, buffer, &name1);
9159 if (i == length)
9160 {
9161 // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
9162 if (!MakeDomainNameFromDNSNameString(&name1d, name1))
9163 {
9164 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
9165 freeaddrinfo(gairesults);
9166 return;
9167 }
9168 mDNSMacOSXCreateEtcHostsEntry(m, &name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
9169 }
9170 else if (i != -1)
9171 {
9172 domainname first;
9173 // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
9174 // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
9175 // doing the right thing.
9176 if (!MakeDomainNameFromDNSNameString(&first, name1))
9177 {
9178 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
9179 freeaddrinfo(gairesults);
9180 return;
9181 }
9182 // If the /etc/hosts has an entry like this
9183 //
9184 // 1.2.3.4 sun star bright
9185 //
9186 // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
9187 // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
9188 //
9189 // To achieve this, we need to add the entry like this:
9190 //
9191 // star CNAME bright
9192 // bright CNAME sun
9193 // sun A 1.2.3.4
9194 //
9195 // We store the first name we parsed in "first". Then we parse additional names adding CNAME records
9196 // till we reach the end. When we reach the end, we wrap around and add one final CNAME with the last
9197 // entry and the first entry. Finally, we add the Address (A/AAAA) record.
9198 aliasIndex = 0;
9199 while (i <= length)
9200 {
9201 // Parse a name. If there are no names, we need to know whether we
9202 // parsed CNAMEs before or not. If we parsed CNAMEs before, then we
9203 // add a CNAME with the last name and the first name. Otherwise, this
9204 // is same as the common case above where the line has just one name
9205 // but with trailing white spaces.
9206 i = EtcHostsParseOneName(i + 1, length, buffer, &name2);
9207 if (name2)
9208 {
9209 if (!MakeDomainNameFromDNSNameString(&name2d, name2))
9210 {
9211 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2);
9212 freeaddrinfo(gairesults);
9213 return;
9214 }
9215 aliasIndex++;
9216 }
9217 else if (!aliasIndex)
9218 {
9219 // We have never parsed any aliases. This case happens if there
9220 // is just one name and some extra white spaces at the end.
9221 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c);
9222 break;
9223 }
9224 else
9225 {
9226 // We have parsed at least one alias before and we reached the end of the line.
9227 // Setup a CNAME for the last name with "first" name as its RDATA
9228 name2d.c[0] = 0;
9229 AssignDomainName(&name2d, &first);
9230 }
9231
9232 // Don't add a CNAME for the first alias we parse (see the example above).
9233 // As we parse more, we might discover that there are no more aliases, in
9234 // which case we would have set "name2d" to "first" above. We need to add
9235 // the CNAME in that case.
9236
9237 if (aliasIndex > 1 || SameDomainName(&name2d, &first))
9238 {
9239 // Ignore if it points to itself
9240 if (!SameDomainName(&name1d, &name2d))
9241 {
9242 if (!mDNSMacOSXCreateEtcHostsEntry(m, &name1d, mDNSNULL, &name2d, ifname, auth))
9243 {
9244 freeaddrinfo(gairesults);
9245 return;
9246 }
9247 }
9248 else
9249 LogMsg("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names name1 %##s, name2 %##s", name1d.c, name2d.c);
9250 }
9251
9252 // If we have already wrapped around, we just need to add the A/AAAA record alone
9253 // which is done below
9254 if (SameDomainName(&name2d, &first)) break;
9255
9256 // Remember the current name so that we can set the CNAME record if we parse one
9257 // more name
9258 name1d.c[0] = 0;
9259 AssignDomainName(&name1d, &name2d);
9260 }
9261 // Added all the CNAMEs if any, add the "A/AAAA" record
9262 mDNSMacOSXCreateEtcHostsEntry(m, &first, gairesults->ai_addr, mDNSNULL, ifname, auth);
9263 }
9264 freeaddrinfo(gairesults);
9265 }
9266
9267 mDNSlocal void mDNSMacOSXParseEtcHosts(mDNS *const m, int fd, AuthHash *auth)
9268 {
9269 mDNSBool good;
9270 char buf[ETCHOSTS_BUFSIZE];
9271 ssize_t len;
9272 FILE *fp;
9273
9274 if (fd == -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
9275
9276 fp = fopen("/etc/hosts", "r");
9277 if (!fp) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
9278
9279 while (1)
9280 {
9281 good = (fgets(buf, ETCHOSTS_BUFSIZE, fp) != NULL);
9282 if (!good) break;
9283
9284 // skip comment and empty lines
9285 if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n')
9286 continue;
9287
9288 len = strlen(buf);
9289 if (!len) break; // sanity check
9290 //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
9291 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
9292 {
9293 buf[len - 1] = '\0';
9294 len = len - 1;
9295 }
9296 // fgets always null terminates and hence even if we have no
9297 // newline at the end, it is null terminated. The callee
9298 // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
9299 // buf[length] is zero and hence we decrement len to reflect that.
9300 if (len)
9301 {
9302 //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
9303 //here we need to check for just \r but taking extra caution.
9304 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
9305 {
9306 buf[len - 1] = '\0';
9307 len = len - 1;
9308 }
9309 }
9310 if (!len) //Sanity Check: len should never be zero
9311 {
9312 LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
9313 continue;
9314 }
9315 mDNSMacOSXParseEtcHostsLine(m, buf, len, auth);
9316 }
9317 fclose(fp);
9318 }
9319
9320 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m);
9321
9322 mDNSlocal int mDNSMacOSXGetEtcHostsFD(mDNS *const m)
9323 {
9324 #ifdef __DISPATCH_GROUP__
9325 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9326 static dispatch_queue_t etcq = 0;
9327 static dispatch_source_t etcsrc = 0;
9328 static dispatch_source_t hostssrc = 0;
9329
9330 // First time through? just schedule ourselves on the main queue and we'll do the work later
9331 if (!etcq)
9332 {
9333 etcq = dispatch_get_main_queue();
9334 if (etcq)
9335 {
9336 // Do this work on the queue, not here - solves potential synchronization issues
9337 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9338 }
9339 return -1;
9340 }
9341
9342 if (hostssrc) return dispatch_source_get_handle(hostssrc);
9343 #endif
9344
9345 int fd = open("/etc/hosts", O_RDONLY);
9346
9347 #ifdef __DISPATCH_GROUP__
9348 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9349 if (fd == -1)
9350 {
9351 // If the open failed and we're already watching /etc, we're done
9352 if (etcsrc) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd; }
9353
9354 // we aren't watching /etc, we should be
9355 fd = open("/etc", O_RDONLY);
9356 if (fd == -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
9357 etcsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME, etcq);
9358 if (etcsrc == NULL)
9359 {
9360 close(fd);
9361 return -1;
9362 }
9363 dispatch_source_set_event_handler(etcsrc,
9364 ^{
9365 u_int32_t flags = dispatch_source_get_data(etcsrc);
9366 LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags);
9367 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9368 {
9369 dispatch_source_cancel(etcsrc);
9370 dispatch_release(etcsrc);
9371 etcsrc = NULL;
9372 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9373 return;
9374 }
9375 if ((flags & DISPATCH_VNODE_WRITE) != 0 && hostssrc == NULL)
9376 {
9377 mDNSMacOSXUpdateEtcHosts(m);
9378 }
9379 });
9380 dispatch_source_set_cancel_handler(etcsrc, ^{close(fd);});
9381 dispatch_resume(etcsrc);
9382
9383 // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
9384 fd = open("/etc/hosts", O_RDONLY | O_EVTONLY);
9385 if (fd == -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
9386 }
9387
9388 // create a dispatch source to watch for changes to hosts file
9389 hostssrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd,
9390 (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME |
9391 DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_LINK | DISPATCH_VNODE_REVOKE), etcq);
9392 if (hostssrc == NULL)
9393 {
9394 close(fd);
9395 return -1;
9396 }
9397 dispatch_source_set_event_handler(hostssrc,
9398 ^{
9399 u_int32_t flags = dispatch_source_get_data(hostssrc);
9400 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags);
9401 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9402 {
9403 dispatch_source_cancel(hostssrc);
9404 dispatch_release(hostssrc);
9405 hostssrc = NULL;
9406 // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
9407 // the block immediately, we try to open the file and the file may not exist and may
9408 // fail to get a notification in the future. When the file does not exist and
9409 // we start to monitor the directory, on "dispatch_resume" of that source, there
9410 // is no guarantee that the file creation will be notified always because when
9411 // the dispatch_resume returns, the kevent manager may not have registered the
9412 // kevent yet but the file may have been created
9413 usleep(1000000);
9414 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9415 return;
9416 }
9417 if ((flags & DISPATCH_VNODE_WRITE) != 0)
9418 {
9419 mDNSMacOSXUpdateEtcHosts(m);
9420 }
9421 });
9422 dispatch_source_set_cancel_handler(hostssrc, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd); close(fd);});
9423 dispatch_resume(hostssrc);
9424
9425 // Cleanup /etc source, no need to watch it if we already have /etc/hosts
9426 if (etcsrc)
9427 {
9428 dispatch_source_cancel(etcsrc);
9429 dispatch_release(etcsrc);
9430 etcsrc = NULL;
9431 }
9432
9433 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
9434 return hostssrc ? (int)dispatch_source_get_handle(hostssrc) : -1;
9435 #else
9436 (void)m;
9437 return fd;
9438 #endif
9439 }
9440
9441 // When /etc/hosts is modified, flush all the cache records as there may be local
9442 // authoritative answers now
9443 mDNSlocal void FlushAllCacheRecords(mDNS *const m)
9444 {
9445 CacheRecord *cr;
9446 mDNSu32 slot;
9447 CacheGroup *cg;
9448
9449 FORALL_CACHERECORDS(slot, cg, cr)
9450 {
9451 // Skip multicast.
9452 if (cr->resrec.InterfaceID) continue;
9453
9454 // If a resource record can answer A or AAAA, they need to be flushed so that we will
9455 // never used to deliver an ADD or RMV
9456 if (RRTypeAnswersQuestionType(&cr->resrec, kDNSType_A) ||
9457 RRTypeAnswersQuestionType(&cr->resrec, kDNSType_AAAA))
9458 {
9459 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr));
9460 mDNS_PurgeCacheResourceRecord(m, cr);
9461 }
9462 }
9463 }
9464
9465 // Add new entries to the core. If justCheck is set, this function does not add, just returns true
9466 mDNSlocal mDNSBool EtcHostsAddNewEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck)
9467 {
9468 AuthGroup *ag;
9469 mDNSu32 slot;
9470 AuthRecord *rr, *primary, *rrnext;
9471 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9472 for (ag = newhosts->rrauth_hash[slot]; ag; ag = ag->next)
9473 {
9474 primary = NULL;
9475 for (rr = ag->members; rr; rr = rrnext)
9476 {
9477 rrnext = rr->next;
9478 AuthGroup *ag1;
9479 AuthRecord *rr1;
9480 mDNSBool found = mDNSfalse;
9481 ag1 = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec);
9482 if (ag1 && ag1->members)
9483 {
9484 if (!primary) primary = ag1->members;
9485 rr1 = ag1->members;
9486 while (rr1)
9487 {
9488 // We are not using InterfaceID in checking for duplicates. This means,
9489 // if there are two addresses for a given name e.g., fe80::1%en0 and
9490 // fe80::1%en1, we only add the first one. It is not clear whether
9491 // this is a common case. To fix this, we also need to modify
9492 // mDNS_Register_internal in how it handles duplicates. If it becomes a
9493 // common case, we will fix it then.
9494 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9495 {
9496 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
9497 found = mDNStrue;
9498 break;
9499 }
9500 rr1 = rr1->next;
9501 }
9502 }
9503 if (!found)
9504 {
9505 if (justCheck)
9506 {
9507 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m, rr));
9508 return mDNStrue;
9509 }
9510 RemoveAuthRecord(m, newhosts, rr);
9511 // if there is no primary, point to self
9512 rr->RRSet = (primary ? primary : rr);
9513 rr->next = NULL;
9514 LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m, rr));
9515 if (mDNS_Register_internal(m, rr) != mStatus_NoError)
9516 LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr));
9517 }
9518 }
9519 }
9520 return mDNSfalse;
9521 }
9522
9523 // Delete entries from the core that are no longer needed. If justCheck is set, this function
9524 // does not delete, just returns true
9525 mDNSlocal mDNSBool EtcHostsDeleteOldEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck)
9526 {
9527 AuthGroup *ag;
9528 mDNSu32 slot;
9529 AuthRecord *rr, *primary, *rrnext;
9530 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9531 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
9532 for (rr = ag->members; rr; rr = rrnext)
9533 {
9534 mDNSBool found = mDNSfalse;
9535 AuthGroup *ag1;
9536 AuthRecord *rr1;
9537 rrnext = rr->next;
9538 if (rr->RecordCallback != FreeEtcHosts) continue;
9539 ag1 = AuthGroupForRecord(newhosts, slot, &rr->resrec);
9540 if (ag1)
9541 {
9542 primary = rr1 = ag1->members;
9543 while (rr1)
9544 {
9545 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9546 {
9547 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m, rr));
9548 found = mDNStrue;
9549 break;
9550 }
9551 rr1 = rr1->next;
9552 }
9553 }
9554 // there is no corresponding record in newhosts for the same name. This means
9555 // we should delete this from the core.
9556 if (!found)
9557 {
9558 if (justCheck)
9559 {
9560 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m, rr));
9561 return mDNStrue;
9562 }
9563 // if primary is going away, make sure that the rest of the records
9564 // point to the new primary
9565 if (rr == ag->members)
9566 {
9567 AuthRecord *new_primary = rr->next;
9568 AuthRecord *r = new_primary;
9569 while (r)
9570 {
9571 if (r->RRSet == rr)
9572 {
9573 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m, r));
9574 r->RRSet = new_primary;
9575 }
9576 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m, r), r->resrec.name);
9577 r = r->next;
9578 }
9579 }
9580 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m, rr));
9581 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
9582 }
9583 }
9584 return mDNSfalse;
9585 }
9586
9587 mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context)
9588 {
9589 AuthHash *newhosts = (AuthHash *)context;
9590
9591 mDNS_CheckLock(m);
9592
9593 //Delete old entries from the core if they are not present in the newhosts
9594 EtcHostsDeleteOldEntries(m, newhosts, mDNSfalse);
9595 // Add the new entries to the core if not already present in the core
9596 EtcHostsAddNewEntries(m, newhosts, mDNSfalse);
9597 }
9598
9599 mDNSlocal void FreeNewHosts(AuthHash *newhosts)
9600 {
9601 mDNSu32 slot;
9602 AuthGroup *ag, *agnext;
9603 AuthRecord *rr, *rrnext;
9604
9605 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9606 for (ag = newhosts->rrauth_hash[slot]; ag; ag = agnext)
9607 {
9608 agnext = ag->next;
9609 for (rr = ag->members; rr; rr = rrnext)
9610 {
9611 rrnext = rr->next;
9612 freeL("etchosts", rr);
9613 }
9614 freeL("AuthGroups", ag);
9615 }
9616 }
9617
9618 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
9619 {
9620 AuthHash newhosts;
9621
9622 // As we will be modifying the core, we can only have one thread running at
9623 // any point in time.
9624 KQueueLock(m);
9625
9626 mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
9627
9628 // Get the file desecriptor (will trigger us to start watching for changes)
9629 int fd = mDNSMacOSXGetEtcHostsFD(m);
9630 if (fd != -1)
9631 {
9632 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd);
9633 mDNSMacOSXParseEtcHosts(m, fd, &newhosts);
9634 }
9635 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
9636
9637 // Optimization: Detect whether /etc/hosts changed or not.
9638 //
9639 // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
9640 // newhosts is already registered with core. If we find at least one entry that is not
9641 // registered with core, then it means we have work to do.
9642 //
9643 // 2. Next, we check to see if any of the entries that are registered with core is not present
9644 // in newhosts. If we find at least one entry that is not present, it means we have work to
9645 // do.
9646 //
9647 // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
9648 // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
9649 // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
9650 // in the future and this code does not have to change.
9651 mDNS_Lock(m);
9652 // Add the new entries to the core if not already present in the core
9653 if (!EtcHostsAddNewEntries(m, &newhosts, mDNStrue))
9654 {
9655 // No new entries to add, check to see if we need to delete any old entries from the
9656 // core if they are not present in the newhosts
9657 if (!EtcHostsDeleteOldEntries(m, &newhosts, mDNStrue))
9658 {
9659 LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
9660 mDNS_Unlock(m);
9661 KQueueUnlock(m, "/etc/hosts changed");
9662 FreeNewHosts(&newhosts);
9663 return;
9664 }
9665 }
9666
9667 // This will flush the cache, stop and start the query so that the queries
9668 // can look at the /etc/hosts again
9669 //
9670 // Notes:
9671 //
9672 // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
9673 // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
9674 // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
9675 // delivers these events in the right order and then calls us back to delete them.
9676 //
9677 // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
9678 // is a common function that looks at all local auth records and delivers a RMV including
9679 // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
9680 // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
9681 // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
9682 // is called back where we do the Registration of the record. This results in RMV followed by ADD which
9683 // looks normal.
9684 mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts);
9685 mDNS_Unlock(m);
9686
9687 KQueueUnlock(m, "/etc/hosts changed");
9688 FreeNewHosts(&newhosts);
9689 }
9690
9691 #if COMPILER_LIKES_PRAGMA_MARK
9692 #pragma mark -
9693 #pragma mark - Initialization & Teardown
9694 #endif
9695
9696 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
9697 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
9698 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
9699 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
9700
9701 // Major version 13 is 10.9.x
9702 mDNSexport void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
9703 {
9704 int major = 0, minor = 0;
9705 char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
9706 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
9707 if (vers)
9708 {
9709 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
9710 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
9711 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
9712 if (cfprodname)
9713 CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
9714 if (cfprodvers)
9715 CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
9716 if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
9717 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
9718 CFRelease(vers);
9719 }
9720 if (!major)
9721 {
9722 major = 13;
9723 LogMsg("Note: No Major Build Version number found; assuming 13");
9724 }
9725 if (HINFO_SWstring)
9726 mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion));
9727 //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
9728
9729 // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
9730 if ((prodname[0] & 0xDF) == 'M')
9731 OSXVers = major;
9732 else
9733 iOSVers = major;
9734 }
9735
9736 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
9737 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
9738 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
9739 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
9740 {
9741 int err = -1;
9742 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
9743 if (s < 3)
9744 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
9745 else
9746 {
9747 struct sockaddr_in s5353;
9748 s5353.sin_family = AF_INET;
9749 s5353.sin_port = MulticastDNSPort.NotAnInteger;
9750 s5353.sin_addr.s_addr = 0;
9751 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
9752 close(s);
9753 }
9754
9755 if (err) LogMsg("No unicast UDP responses");
9756 else debugf("Unicast UDP responses okay");
9757 return(err == 0);
9758 }
9759
9760 mDNSlocal void CreatePTRRecord(mDNS *const m, const domainname *domain)
9761 {
9762 AuthRecord *rr;
9763 const domainname *pname = (domainname *)"\x9" "localhost";
9764
9765 rr= mallocL("localhosts", sizeof(*rr));
9766 if (rr == NULL) return;
9767 mDNSPlatformMemZero(rr, sizeof(*rr));
9768
9769 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
9770 AssignDomainName(&rr->namestorage, domain);
9771
9772 rr->resrec.rdlength = DomainNameLength(pname);
9773 rr->resrec.rdata->u.name.c[0] = 0;
9774 AssignDomainName(&rr->resrec.rdata->u.name, pname);
9775
9776 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
9777 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
9778 mDNS_Register(m, rr);
9779 }
9780
9781 // Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
9782 // on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
9783 // fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
9784 // a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
9785 //
9786 // Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
9787 // intentionally to avoid adding to the complexity of code handling /etc/hosts.
9788 mDNSlocal void SetupLocalHostRecords(mDNS *const m)
9789 {
9790 char buffer[MAX_REVERSE_MAPPING_NAME];
9791 domainname name;
9792 int i;
9793 struct in6_addr addr;
9794 mDNSu8 *ptr = addr.__u6_addr.__u6_addr8;
9795
9796 if (inet_pton(AF_INET, "127.0.0.1", &addr) == 1)
9797 {
9798 mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
9799 ptr[3], ptr[2], ptr[1], ptr[0]);
9800 MakeDomainNameFromDNSNameString(&name, buffer);
9801 CreatePTRRecord(m, &name);
9802 }
9803 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET failed");
9804
9805 if (inet_pton(AF_INET6, "::1", &addr) == 1)
9806 {
9807 for (i = 0; i < 16; i++)
9808 {
9809 static const char hexValues[] = "0123456789ABCDEF";
9810 buffer[i * 4 ] = hexValues[ptr[15 - i] & 0x0F];
9811 buffer[i * 4 + 1] = '.';
9812 buffer[i * 4 + 2] = hexValues[ptr[15 - i] >> 4];
9813 buffer[i * 4 + 3] = '.';
9814 }
9815 mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
9816 MakeDomainNameFromDNSNameString(&name, buffer);
9817 CreatePTRRecord(m, &name);
9818 }
9819 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET6 failed");
9820 }
9821
9822 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
9823 // 1) query for b._dns-sd._udp.local on LocalOnly interface
9824 // (.local manually generated via explicit callback)
9825 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
9826 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
9827 // 4) result above should generate a callback from question in (1). result added to global list
9828 // 5) global list delivered to client via GetSearchDomainList()
9829 // 6) client calls to enumerate domains now go over LocalOnly interface
9830 // (!!!KRS may add outgoing interface in addition)
9831
9832 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
9833 {
9834 mStatus err;
9835 m->p->CFRunLoop = CFRunLoopGetCurrent();
9836
9837 char HINFO_SWstring[256] = "";
9838 mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
9839
9840 err = mDNSHelperInit();
9841 if (err)
9842 return err;
9843
9844 DynamicStoreQueue = dispatch_queue_create("com.apple.mDNSResponder.DynamicStoreQueue", NULL);
9845 if (DynamicStoreQueue == NULL)
9846 {
9847 LogMsg("dispatch_queue_create: DynamicStoreQueue NULL!");
9848 return mStatus_NoMemoryErr;
9849 }
9850
9851 // Store mDNSResponder Platform
9852 if (OSXVers)
9853 {
9854 m->mDNS_plat = platform_OSX;
9855 }
9856 else if (iOSVers)
9857 {
9858 if (IsAppleTV())
9859 m->mDNS_plat = platform_Atv;
9860 else
9861 m->mDNS_plat = platform_iOS;
9862 }
9863 else
9864 {
9865 m->mDNS_plat = platform_NonApple;
9866 }
9867
9868 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
9869 // 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.
9870 int i;
9871 for (i=0; i<100; i++)
9872 {
9873 domainlabel testlabel;
9874 testlabel.c[0] = 0;
9875 GetUserSpecifiedLocalHostName(&testlabel);
9876 if (testlabel.c[0]) break;
9877 usleep(50000);
9878 }
9879
9880 m->hostlabel.c[0] = 0;
9881
9882 int get_model[2] = { CTL_HW, HW_MODEL };
9883 size_t len_model = sizeof(HINFO_HWstring_buffer);
9884
9885 // Normal Apple model names are of the form "iPhone2,1", and
9886 // internal code names are strings containing no commas, e.g. "N88AP".
9887 // We used to ignore internal code names, but Apple now uses these internal code names
9888 // even in released shipping products, so we no longer ignore strings containing no commas.
9889 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
9890 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
9891 HINFO_HWstring = HINFO_HWstring_buffer;
9892
9893 // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
9894 // For names of the form "N88AP" containg no comma, we use the entire string.
9895 HINFO_HWstring_prefixlen = strchr(HINFO_HWstring_buffer, ',') ? strcspn(HINFO_HWstring, "0123456789") : strlen(HINFO_HWstring);
9896
9897 if (mDNSPlatformInit_CanReceiveUnicast())
9898 m->CanReceiveUnicastOn5353 = mDNStrue;
9899
9900 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
9901 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
9902 if (hlen + slen < 254)
9903 {
9904 m->HIHardware.c[0] = hlen;
9905 m->HISoftware.c[0] = slen;
9906 mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
9907 mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
9908 }
9909
9910 m->p->permanentsockets.port = MulticastDNSPort;
9911 m->p->permanentsockets.m = m;
9912 m->p->permanentsockets.sktv4 = -1;
9913 m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack;
9914 m->p->permanentsockets.kqsv4.KQcontext = &m->p->permanentsockets;
9915 m->p->permanentsockets.kqsv4.KQtask = "UDP packet reception";
9916 m->p->permanentsockets.sktv6 = -1;
9917 m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
9918 m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
9919 m->p->permanentsockets.kqsv6.KQtask = "UDP packet reception";
9920
9921 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
9922 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
9923
9924 struct sockaddr_in s4;
9925 socklen_t n4 = sizeof(s4);
9926 if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0)
9927 LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
9928 else
9929 m->UnicastPort4.NotAnInteger = s4.sin_port;
9930
9931 if (m->p->permanentsockets.sktv6 >= 0)
9932 {
9933 struct sockaddr_in6 s6;
9934 socklen_t n6 = sizeof(s6);
9935 if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
9936 else m->UnicastPort6.NotAnInteger = s6.sin6_port;
9937 }
9938
9939 m->p->InterfaceList = mDNSNULL;
9940 m->p->userhostlabel.c[0] = 0;
9941 m->p->usernicelabel.c[0] = 0;
9942 m->p->prevoldnicelabel.c[0] = 0;
9943 m->p->prevnewnicelabel.c[0] = 0;
9944 m->p->prevoldhostlabel.c[0] = 0;
9945 m->p->prevnewhostlabel.c[0] = 0;
9946 m->p->NotifyUser = 0;
9947 m->p->KeyChainTimer = 0;
9948 m->p->WakeAtUTC = 0;
9949 m->p->RequestReSleep = 0;
9950 // Assume that everything is good to begin with. If something is not working,
9951 // we will detect that when we start sending questions.
9952 m->p->v4answers = 1;
9953 m->p->v6answers = 1;
9954 m->p->DNSTrigger = 0;
9955 m->p->LastConfigGeneration = 0;
9956
9957 #if APPLE_OSX_mDNSResponder
9958 uuid_generate(m->asl_uuid);
9959 #endif
9960
9961 m->AutoTunnelRelayAddr = zerov6Addr;
9962
9963 NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
9964 NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
9965 NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
9966 NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
9967 NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
9968 NetworkChangedKey_StateInterfacePrefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, CFSTR(""), NULL);
9969 if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS || !NetworkChangedKey_StateInterfacePrefix)
9970 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
9971
9972 err = WatchForNetworkChanges(m);
9973 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
9974
9975 #if 0 // <rdar://problem/6751656>
9976 err = WatchForPMChanges(m);
9977 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForPMChanges failed %d", err); return(err); }
9978 #endif
9979
9980 err = WatchForSysEvents(m);
9981 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
9982
9983 mDNSs32 utc = mDNSPlatformUTC();
9984 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
9985 UpdateInterfaceList(m, utc);
9986 SetupActiveInterfaces(m, utc);
9987
9988 // Explicitly ensure that our Keychain operations utilize the system domain.
9989 #ifndef NO_SECURITYFRAMEWORK
9990 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
9991 #endif
9992
9993 mDNS_Lock(m);
9994 SetDomainSecrets(m);
9995 SetLocalDomains();
9996 mDNS_Unlock(m);
9997
9998 #ifndef NO_SECURITYFRAMEWORK
9999 err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
10000 if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
10001 #endif
10002
10003 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
10004 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
10005 #else
10006 IOPMConnection c;
10007 IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
10008 if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
10009 else
10010 {
10011 iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
10012 if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
10013 else
10014 {
10015 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10016 IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue());
10017 LogInfo("IOPMConnectionSetDispatchQueue is now running");
10018 #else
10019 iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
10020 if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
10021 LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
10022 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
10023 }
10024 }
10025 m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
10026 if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
10027 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
10028 {
10029 m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
10030 if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
10031 else
10032 {
10033 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10034 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
10035 #else
10036 CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
10037 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
10038 }
10039 }
10040
10041 #if APPLE_OSX_mDNSResponder
10042 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
10043 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
10044 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
10045 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
10046 if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
10047 else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
10048 else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
10049 else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
10050 else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; }
10051 else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; }
10052 else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /* 4kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 13W */; }
10053 else if (!strncasecmp(HINFO_HWstring, "AirPort", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 12W */; }
10054 else if ( IsAppleTV() ) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 60 /* 1W */; SPMetricTotalPower = 63 /* 2W */; }
10055 else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
10056 else if (!strncasecmp(HINFO_HWstring, "PowerBook", 9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
10057 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
10058 HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
10059 #endif // APPLE_OSX_mDNSResponder
10060
10061 // Currently this is not defined. SSL code will eventually fix this. If it becomes
10062 // critical, we will define this to workaround the bug in SSL.
10063 #ifdef __SSL_NEEDS_SERIALIZATION__
10064 SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL);
10065 #else
10066 SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
10067 #endif
10068 if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
10069
10070 mDNSMacOSXUpdateEtcHosts(m);
10071 SetupLocalHostRecords(m);
10072 CUPInit(m);
10073
10074 return(mStatus_NoError);
10075 }
10076
10077 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
10078 {
10079 #if MDNS_NO_DNSINFO
10080 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
10081 #endif
10082
10083 // Adding interfaces will use this flag, so set it now.
10084 m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
10085
10086 #if APPLE_OSX_mDNSResponder
10087 m->SPSBrowseCallback = UpdateSPSStatus;
10088 #endif // APPLE_OSX_mDNSResponder
10089
10090 mStatus result = mDNSPlatformInit_setup(m);
10091
10092 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
10093 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
10094 if (result == mStatus_NoError)
10095 {
10096 mDNSCoreInitComplete(m, mStatus_NoError);
10097
10098 #if !NO_D2D
10099 // We only initialize if mDNSCore successfully initialized.
10100 if (D2DInitialize)
10101 {
10102 D2DStatus ds = D2DInitialize(m->p->CFRunLoop, xD2DServiceCallback, m) ;
10103 if (ds != kD2DSuccess)
10104 LogMsg("D2DInitialiize failed: %d", ds);
10105 else
10106 LogMsg("D2DInitialize succeeded");
10107 }
10108 #endif // ! NO_D2D
10109
10110 }
10111 result = DNSSECCryptoInit(m);
10112 return(result);
10113 }
10114
10115 mDNSexport void mDNSPlatformClose(mDNS *const m)
10116 {
10117 if (m->p->PowerConnection)
10118 {
10119 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10120 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);
10121 #else
10122 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
10123 #endif
10124 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
10125 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
10126 IODeregisterForSystemPower(&m->p->PowerNotifier);
10127 IOServiceClose ( m->p->PowerConnection);
10128 IONotificationPortDestroy ( m->p->PowerPortRef);
10129 m->p->PowerConnection = 0;
10130 }
10131
10132 if (m->p->Store)
10133 {
10134 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10135 if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
10136 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
10137 #else
10138 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
10139 CFRunLoopSourceInvalidate(m->p->StoreRLS);
10140 CFRelease(m->p->StoreRLS);
10141 m->p->StoreRLS = NULL;
10142 #endif
10143 CFRelease(m->p->Store);
10144 m->p->Store = NULL;
10145 }
10146
10147 if (m->p->PMRLS)
10148 {
10149 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
10150 CFRunLoopSourceInvalidate(m->p->PMRLS);
10151 CFRelease(m->p->PMRLS);
10152 m->p->PMRLS = NULL;
10153 }
10154
10155 if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
10156
10157 #if !NO_D2D
10158 if (D2DTerminate)
10159 {
10160 D2DStatus ds = D2DTerminate();
10161 if (ds != kD2DSuccess)
10162 LogMsg("D2DTerminate failed: %d", ds);
10163 else
10164 LogMsg("D2DTerminate succeeded");
10165 }
10166 #endif // ! NO_D2D
10167
10168 mDNSs32 utc = mDNSPlatformUTC();
10169 MarkAllInterfacesInactive(m, utc);
10170 ClearInactiveInterfaces(m, utc);
10171 CloseSocketSet(&m->p->permanentsockets);
10172
10173 #if APPLE_OSX_mDNSResponder
10174 // clean up tunnels
10175 while (m->TunnelClients)
10176 {
10177 ClientTunnel *cur = m->TunnelClients;
10178 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
10179 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
10180 AutoTunnelSetKeys(cur, mDNSfalse);
10181 m->TunnelClients = cur->next;
10182 freeL("ClientTunnel", cur);
10183 }
10184
10185 if (AnonymousRacoonConfig)
10186 {
10187 AnonymousRacoonConfig = mDNSNULL;
10188 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel");
10189 (void)mDNSConfigureServer(kmDNSDown, mDNSNULL, mDNSNULL);
10190 }
10191 #endif // APPLE_OSX_mDNSResponder
10192 }
10193
10194 #if COMPILER_LIKES_PRAGMA_MARK
10195 #pragma mark -
10196 #pragma mark - General Platform Support Layer functions
10197 #endif
10198
10199 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
10200 {
10201 return(arc4random());
10202 }
10203
10204 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
10205 mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
10206
10207 mDNSexport mStatus mDNSPlatformTimeInit(void)
10208 {
10209 // Notes: Typical values for mach_timebase_info:
10210 // tbi.numer = 1000 million
10211 // tbi.denom = 33 million
10212 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
10213 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
10214 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
10215 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
10216 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
10217 //
10218 // Arithmetic notes:
10219 // tbi.denom is at least 1, and not more than 2^32-1.
10220 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
10221 // tbi.denom is at least 1, and not more than 2^32-1.
10222 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
10223 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
10224 // which is unlikely on any current or future Macintosh.
10225 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
10226 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
10227 struct mach_timebase_info tbi;
10228 kern_return_t result = mach_timebase_info(&tbi);
10229 if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
10230 return(result);
10231 }
10232
10233 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
10234 {
10235 if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
10236
10237 static uint64_t last_mach_absolute_time = 0;
10238 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
10239 uint64_t this_mach_absolute_time = mach_absolute_time();
10240 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
10241 {
10242 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
10243 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
10244 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
10245 last_mach_absolute_time = this_mach_absolute_time;
10246 // Note: This bug happens all the time on 10.3
10247 NotifyOfElusiveBug("mach_absolute_time went backwards!",
10248 "This error occurs from time to time, often on newly released hardware, "
10249 "and usually the exact cause is different in each instance.\r\r"
10250 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
10251 "and assign it to Radar Component “Kernel” Version “X”.");
10252 }
10253 last_mach_absolute_time = this_mach_absolute_time;
10254
10255 return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
10256 }
10257
10258 mDNSexport mDNSs32 mDNSPlatformUTC(void)
10259 {
10260 return time(NULL);
10261 }
10262
10263 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
10264 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
10265 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
10266 mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); }
10267 mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); }
10268 mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
10269 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
10270 mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); }
10271 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); }
10272 mDNSexport void mDNSPlatformQsort ( void *base, int nel, int width, int (*compar)(const void *, const void *))
10273 {
10274 return (qsort(base, nel, width, compar));
10275 }
10276 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
10277 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
10278 #endif
10279 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
10280
10281 mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
10282 {
10283 if (allowSleep && m->p->IOPMAssertion)
10284 {
10285 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
10286 IOPMAssertionRelease(m->p->IOPMAssertion);
10287 m->p->IOPMAssertion = 0;
10288 }
10289 else if (!allowSleep)
10290 {
10291 #ifdef kIOPMAssertionTypeNoIdleSleep
10292 if (m->p->IOPMAssertion)
10293 {
10294 IOPMAssertionRelease(m->p->IOPMAssertion);
10295 m->p->IOPMAssertion = 0;
10296 }
10297
10298 CFStringRef assertionName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%d %s"), getprogname(), getpid(), reason ? reason : "");
10299 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, assertionName ? assertionName : CFSTR("mDNSResponder"), &m->p->IOPMAssertion);
10300 if (assertionName) CFRelease(assertionName);
10301 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__);
10302 #endif
10303 }
10304 }
10305
10306 mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
10307 {
10308 mDNSu32 ifindex;
10309
10310 // Sanity check
10311 ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
10312 if (ifindex <= 0)
10313 {
10314 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
10315 return;
10316 }
10317 mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration);
10318 }
10319
10320 mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
10321 {
10322 NetworkInterfaceInfoOSX *info;
10323
10324 if (InterfaceID == mDNSInterface_P2P)
10325 return mDNStrue;
10326
10327 if ( (InterfaceID == mDNSInterface_Any)
10328 || (InterfaceID == mDNSInterfaceMark)
10329 || (InterfaceID == mDNSInterface_LocalOnly)
10330 || (InterfaceID == mDNSInterface_Unicast))
10331 return mDNSfalse;
10332
10333 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
10334 if (info == NULL)
10335 {
10336 // this log message can print when operations are stopped on an interface that has gone away
10337 LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID);
10338 return mDNSfalse;
10339 }
10340
10341 return (mDNSBool) info->D2DInterface;
10342 }
10343
10344 // Filter records send over P2P (D2D) type interfaces
10345 // Note that the terms P2P and D2D are used synonymously in the current code and comments.
10346 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf)
10347 {
10348 // For an explicit match to a valid interface ID, return true.
10349 if (rr->resrec.InterfaceID == intf->InterfaceID)
10350 return mDNStrue;
10351
10352 // Only filtering records for D2D type interfaces, return true for all other interface types.
10353 if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
10354 return mDNStrue;
10355
10356 // If it's an AWDL interface the record must be explicitly marked to include AWDL.
10357 if (intf->InterfaceID == AWDLInterfaceID)
10358 {
10359 if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10360 return mDNStrue;
10361 else
10362 return mDNSfalse;
10363 }
10364
10365 // Send record if it is explicitly marked to include all other P2P type interfaces.
10366 if (rr->ARType == AuthRecordAnyIncludeP2P || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10367 return mDNStrue;
10368
10369 // Don't send the record over this interface.
10370 return mDNSfalse;
10371 }
10372
10373 // Filter questions send over P2P (D2D) type interfaces.
10374 mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
10375 {
10376 // For an explicit match to a valid interface ID, return true.
10377 if (q->InterfaceID == intf->InterfaceID)
10378 return mDNStrue;
10379
10380 // Only filtering questions for D2D type interfaces
10381 if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
10382 return mDNStrue;
10383
10384 // If it's an AWDL interface the question must be explicitly marked to include AWDL.
10385 if (intf->InterfaceID == AWDLInterfaceID)
10386 {
10387 if (q->flags & kDNSServiceFlagsIncludeAWDL)
10388 return mDNStrue;
10389 else
10390 return mDNSfalse;
10391 }
10392
10393 // Sent question if it is explicitly marked to include all other P2P type interfaces.
10394 if (q->flags & kDNSServiceFlagsIncludeP2P)
10395 return mDNStrue;
10396
10397 // Don't send the question over this interface.
10398 return mDNSfalse;
10399 }
10400
10401 // Returns true unless record was received over the AWDL interface and
10402 // the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
10403 // with the kDNSServiceFlagsIncludeAWDL flag set.
10404 mDNSexport mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
10405 {
10406 if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID))
10407 return mDNStrue;
10408
10409 if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL))
10410 {
10411 LogInfo("mDNSPlatformValidRecordForQuestion: Record recieved over AWDL not returned for %s %##s query",
10412 DNSTypeName(q->qtype), q->qname.c);
10413 return mDNSfalse;
10414 }
10415
10416 return mDNStrue;
10417 }
10418
10419 // formating time to RFC 4034 format
10420 mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
10421 {
10422 struct tm tmTime;
10423 time_t t = (time_t)te;
10424 // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
10425 // gmtime_r first and then use strftime
10426 gmtime_r(&t, &tmTime);
10427 strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
10428 }
10429
10430 mDNSexport mDNSs32 mDNSPlatformGetPID()
10431 {
10432 return getpid();
10433 }
10434
10435 // Schedule a function asynchronously on the main queue
10436 mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func)
10437 {
10438 // KQueueLock/Unlock is used for two purposes
10439 //
10440 // 1. We can't be running along with the KQueue thread and hence acquiring the lock
10441 // serializes the access to the "core"
10442 //
10443 // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
10444 // up and calls udsserver_idle which schedules the messages across the uds socket.
10445 // If "func" delivers something to the uds socket from the dispatch thread, it will
10446 // not be delivered immediately if not for the Unlock.
10447 dispatch_async(dispatch_get_main_queue(), ^{
10448 KQueueLock(m);
10449 func(m, context);
10450 KQueueUnlock(m, "mDNSPlatformDispatchAsync");
10451 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10452 // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
10453 // to handle any message that "func" might deliver.
10454 TriggerEventCompletion();
10455 #endif
10456 });
10457 }
10458
10459 // definitions for device-info record construction
10460 #define DEVINFO_MODEL "model="
10461 #define DEVINFO_MODEL_LEN strlen(DEVINFO_MODEL)
10462
10463 #define OSX_VER "osxvers="
10464 #define OSX_VER_LEN strlen(OSX_VER)
10465 #define VER_NUM_LEN 2 // 2 digits of version number added to base string
10466
10467 #define MODEL_COLOR "ecolor="
10468 #define MODEL_COLOR_LEN strlen(MODEL_COLOR)
10469 #define MODEL_RGB_VALUE_LEN strlen("255,255,255") // 'r,g,b'
10470
10471 // Bytes available in TXT record for model name after subtracting space for other
10472 // fixed size strings and their length bytes.
10473 #define MAX_MODEL_NAME_LEN (256 - (DEVINFO_MODEL_LEN + 1) - (OSX_VER_LEN + VER_NUM_LEN + 1) - (MODEL_COLOR_LEN + MODEL_RGB_VALUE_LEN + 1))
10474
10475 mDNSlocal mDNSBool getModelIconColors(char *color)
10476 {
10477 mDNSBool hasColor = mDNSfalse;
10478 mDNSPlatformMemZero(color, MODEL_RGB_VALUE_LEN + 1);
10479
10480 #if !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10481 mDNSu8 red = 0;
10482 mDNSu8 green = 0;
10483 mDNSu8 blue = 0;
10484
10485 IOReturn rGetDeviceColor = IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey,
10486 &red, &green, &blue);
10487 if (kIOReturnSuccess == rGetDeviceColor)
10488 {
10489 // IOKit was able to get enclosure color for the current device.
10490 hasColor = true;
10491 snprintf(color, MODEL_RGB_VALUE_LEN + 1, "%d,%d,%d", red, green, blue);
10492 }
10493 #endif // !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
10494
10495 return hasColor;
10496 }
10497
10498
10499 // Initialize device-info TXT record contents and return total length of record data.
10500 mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
10501 {
10502 mDNSu8 *bufferStart = ptr;
10503 mDNSu8 len = m->HIHardware.c[0] < MAX_MODEL_NAME_LEN ? m->HIHardware.c[0] : MAX_MODEL_NAME_LEN;
10504
10505 *ptr = DEVINFO_MODEL_LEN + len; // total length of DEVINFO_MODEL string plus the hardware name string
10506 ptr++;
10507 mDNSPlatformMemCopy(ptr, DEVINFO_MODEL, DEVINFO_MODEL_LEN);
10508 ptr += DEVINFO_MODEL_LEN;
10509 mDNSPlatformMemCopy(ptr, m->HIHardware.c + 1, len);
10510 ptr += len;
10511
10512 // only include this string for OSX
10513 if (OSXVers)
10514 {
10515 char ver_num[VER_NUM_LEN + 1]; // version digits + null written by snprintf
10516 *ptr = OSX_VER_LEN + VER_NUM_LEN; // length byte
10517 ptr++;
10518 mDNSPlatformMemCopy(ptr, OSX_VER, OSX_VER_LEN);
10519 ptr += OSX_VER_LEN;
10520 // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
10521 snprintf(ver_num, VER_NUM_LEN + 1, "%d", OSXVers);
10522 mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN);
10523 ptr += VER_NUM_LEN;
10524
10525 char rgb[MODEL_RGB_VALUE_LEN + 1]; // RGB value + null written by snprintf
10526 if (getModelIconColors(rgb))
10527 {
10528 len = strlen(rgb);
10529 *ptr = MODEL_COLOR_LEN + len; // length byte
10530 ptr++;
10531
10532 mDNSPlatformMemCopy(ptr, MODEL_COLOR, MODEL_COLOR_LEN);
10533 ptr += MODEL_COLOR_LEN;
10534
10535 mDNSPlatformMemCopy(ptr, rgb, len);
10536 ptr += len;
10537 }
10538 }
10539
10540 return (ptr - bufferStart);
10541 }
10542
10543
10544